Repository: sirocco-ventures/raggenie Branch: main Commit: 8a069ccc9cd9 Files: 351 Total size: 87.8 MB Directory structure: gitextract_rx9dudey/ ├── .dockerignore ├── .flake8 ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ └── workflows/ │ └── static.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── app/ │ ├── __init__.py │ ├── api/ │ │ └── v1/ │ │ ├── auth.py │ │ ├── commons.py │ │ ├── connector.py │ │ ├── llmchat.py │ │ ├── main_router.py │ │ └── provider.py │ ├── base/ │ │ ├── abstract_handlers.py │ │ ├── base_formatter.py │ │ ├── base_llm.py │ │ ├── base_plugin.py │ │ ├── base_vectordb.py │ │ ├── document_data_plugin.py │ │ ├── loader_metadata_mixin.py │ │ ├── messaging_plugin.py │ │ ├── model_loader.py │ │ ├── plugin_metadata_mixin.py │ │ ├── query_plugin.py │ │ └── remote_data_plugin.py │ ├── chain/ │ │ ├── chains/ │ │ │ ├── capability_chain.py │ │ │ ├── general_chain.py │ │ │ ├── intent_chain.py │ │ │ ├── metadata_chain.py │ │ │ └── query_chain.py │ │ ├── formatter/ │ │ │ └── general_response.py │ │ └── modules/ │ │ ├── cache_checker.py │ │ ├── cache_updater.py │ │ ├── context_retreiver.py │ │ ├── context_storage.py │ │ ├── document_retriever.py │ │ ├── executer.py │ │ ├── follow_up_handler.py │ │ ├── followup_interpreter.py │ │ ├── general_answer_generator.py │ │ ├── generator.py │ │ ├── input_formatter.py │ │ ├── intent_extracter.py │ │ ├── metadata_generator.py │ │ ├── metadata_ragfilter.py │ │ ├── ouput_formatter.py │ │ ├── post_processor.py │ │ ├── prompt_generator.py │ │ ├── router.py │ │ ├── schema_retriever.py │ │ └── validator.py │ ├── embeddings/ │ │ ├── cohere/ │ │ │ ├── __init__.py │ │ │ └── handler.py │ │ ├── default/ │ │ │ ├── chroma_default.py │ │ │ ├── default.py │ │ │ └── onnx.py │ │ ├── google/ │ │ │ ├── __init__.py │ │ │ └── handler.py │ │ ├── loader.py │ │ └── openai/ │ │ ├── __init__.py │ │ └── handler.py │ ├── loaders/ │ │ ├── ai71/ │ │ │ ├── __init__.py │ │ │ └── loader.py │ │ ├── base_loader.py │ │ ├── ollama/ │ │ │ ├── __init__.py │ │ │ └── loader.py │ │ ├── openai/ │ │ │ ├── __init__.py │ │ │ └── loader.py │ │ └── togethor/ │ │ ├── __init__.py │ │ └── loader.py │ ├── main.py │ ├── models/ │ │ ├── connector.py │ │ ├── db.py │ │ ├── environment.py │ │ ├── llmchat.py │ │ ├── prompt.py │ │ ├── provider.py │ │ ├── request.py │ │ └── user.py │ ├── plugins/ │ │ ├── airtable/ │ │ │ ├── __init__.py │ │ │ ├── formatter.py │ │ │ └── handler.py │ │ ├── bigquery/ │ │ │ ├── __init__.py │ │ │ ├── formatter.py │ │ │ └── handler.py │ │ ├── csv/ │ │ │ ├── __init__.py │ │ │ ├── formatter.py │ │ │ └── handler.py │ │ ├── document/ │ │ │ ├── __init__.py │ │ │ ├── formatter.py │ │ │ └── handler.py │ │ ├── loader.py │ │ ├── maria/ │ │ │ ├── __init__.py │ │ │ ├── formatter.py │ │ │ └── handler.py │ │ ├── mssql/ │ │ │ ├── __init__.py │ │ │ ├── formatter.py │ │ │ └── handler.py │ │ ├── mysql/ │ │ │ ├── __init__.py │ │ │ ├── formatter.py │ │ │ └── handler.py │ │ ├── postgresql/ │ │ │ ├── __init__.py │ │ │ ├── formatter.py │ │ │ └── handler.py │ │ ├── sqlite/ │ │ │ ├── __init__.py │ │ │ ├── formatter.py │ │ │ └── handler.py │ │ └── website/ │ │ ├── __init__.py │ │ ├── formatter.py │ │ └── handler.py │ ├── providers/ │ │ ├── cache_manager.py │ │ ├── clustering.py │ │ ├── config.py │ │ ├── container.py │ │ ├── context_storage.py │ │ ├── data_preperation.py │ │ ├── middleware.py │ │ ├── reranker.py │ │ └── zitadel.py │ ├── readers/ │ │ ├── base_reader.py │ │ ├── docs_reader.py │ │ ├── docx_reader.py │ │ ├── pdf_reader.py │ │ ├── text_reader.py │ │ ├── url_reader.py │ │ └── yaml_reader.py │ ├── repository/ │ │ ├── connector.py │ │ ├── environment.py │ │ ├── llmchat.py │ │ ├── provider.py │ │ └── user.py │ ├── schemas/ │ │ ├── common.py │ │ ├── connector.py │ │ ├── environment.py │ │ ├── llmchat.py │ │ ├── provider.py │ │ └── user.py │ ├── services/ │ │ ├── connector.py │ │ ├── connector_details.py │ │ ├── llmchat.py │ │ ├── provider.py │ │ └── user.py │ ├── utils/ │ │ ├── database.py │ │ ├── jwt.py │ │ ├── module_reader.py │ │ ├── parser.py │ │ └── read_config.py │ └── vectordb/ │ ├── loader.py │ └── mongodb/ │ ├── __init__.py │ └── handler.py ├── commands/ │ ├── cli.py │ └── llm.py ├── config.yaml ├── docker-compose.yml ├── documents/ │ ├── .gitignore │ ├── README.md │ ├── babel.config.js │ ├── docs/ │ │ ├── Configuring agents.md │ │ ├── Connectors/ │ │ │ ├── Airtable.md │ │ │ ├── Bigquery.md │ │ │ ├── Connectors.md │ │ │ ├── PDFs.md │ │ │ ├── Postgressql.md │ │ │ └── Websites.md │ │ ├── Examples.md │ │ ├── How to configure raggenie/ │ │ │ ├── Configuration.md │ │ │ ├── Deploy.md │ │ │ ├── Plugins.md │ │ │ ├── Preview.md │ │ │ ├── Samples.md │ │ │ └── _category_.json │ │ ├── How to run raggenie/ │ │ │ ├── To run raggenie backend Server.md │ │ │ ├── To run raggenie ui server.md │ │ │ ├── Using Docker.md │ │ │ └── _category_.json │ │ ├── LLM Inferences.md │ │ └── Prerequesites.md │ ├── docusaurus.config.js │ ├── package.json │ ├── sidebars.js │ ├── src/ │ │ ├── css/ │ │ │ └── custom.css │ │ └── pages/ │ │ ├── index.md │ │ └── index.module.css │ └── static/ │ └── .nojekyll ├── embeddings/ │ └── onnx/ │ ├── model.onnx │ └── tokenizer.json ├── main.py ├── nginx.conf ├── pyproject.toml ├── requirements.txt ├── setup.py ├── tests/ │ ├── README.md │ ├── __init__.py │ ├── conftest.py │ ├── functional/ │ │ ├── test_commons.py │ │ ├── test_connectors.py │ │ ├── test_llmchat.py │ │ └── test_provider.py │ ├── integration/ │ │ └── test_integration_connector.py │ └── unittest/ │ └── test_svc/ │ └── test_svc_provider.py ├── ui/ │ ├── .dockerignore │ ├── Dockerfile │ ├── README.md │ ├── eslint.config.js │ ├── index.html │ ├── jsconfig.json │ ├── nginx.conf │ ├── package.json │ ├── src/ │ │ ├── App.jsx │ │ ├── components/ │ │ │ ├── Breadcrumbs/ │ │ │ │ ├── Breadcrumbs.jsx │ │ │ │ └── Breadcrumbs.module.css │ │ │ ├── Button/ │ │ │ │ ├── Button.jsx │ │ │ │ ├── Button.module.css │ │ │ │ └── Button.test.jsx │ │ │ ├── Chart/ │ │ │ │ ├── AreaChart/ │ │ │ │ │ └── AreaChart.jsx │ │ │ │ ├── BarChart/ │ │ │ │ │ └── BarChart.jsx │ │ │ │ ├── LineChart/ │ │ │ │ │ └── LineChart.jsx │ │ │ │ ├── PieChart/ │ │ │ │ │ └── PieChart.jsx │ │ │ │ ├── Table/ │ │ │ │ │ └── Table.jsx │ │ │ │ └── style.module.css │ │ │ ├── ChatBox/ │ │ │ │ ├── ChatBox.jsx │ │ │ │ ├── ChatBox.module.css │ │ │ │ ├── ChatDropdownMenu/ │ │ │ │ │ ├── ChatDropdownMenu.jsx │ │ │ │ │ └── ChatDropdownMenu.module.css │ │ │ │ ├── ChatHistoryButton.jsx │ │ │ │ ├── ChatHistorySideBar.jsx │ │ │ │ ├── ErrorMessage.jsx │ │ │ │ ├── Feedback.jsx │ │ │ │ ├── Loader.jsx │ │ │ │ ├── Message.jsx │ │ │ │ ├── Summary.jsx │ │ │ │ └── Time.jsx │ │ │ ├── CodeBlock/ │ │ │ │ ├── CodeBlock.jsx │ │ │ │ └── CodeBlock.module.css │ │ │ ├── FileUpload/ │ │ │ │ ├── FileUpload.jsx │ │ │ │ └── FileUpload.module.css │ │ │ ├── Input/ │ │ │ │ ├── Input.jsx │ │ │ │ └── Input.module.css │ │ │ ├── Modal/ │ │ │ │ ├── Modal.jsx │ │ │ │ └── Modal.module.css │ │ │ ├── NotificationPanel/ │ │ │ │ ├── NotificationPanel.jsx │ │ │ │ └── NotificationPanel.module.css │ │ │ ├── RouteTab/ │ │ │ │ ├── RouteTab.jsx │ │ │ │ └── RouteTab.module.css │ │ │ ├── SearchInput/ │ │ │ │ ├── SearchInput.jsx │ │ │ │ └── SearchInput.module.css │ │ │ ├── Select/ │ │ │ │ ├── Select.jsx │ │ │ │ └── Select.module.css │ │ │ ├── Tab/ │ │ │ │ ├── Tab.jsx │ │ │ │ ├── Tab.module.css │ │ │ │ └── Tabs.jsx │ │ │ ├── Table/ │ │ │ │ ├── DatatableCustomTheme.css │ │ │ │ ├── Pagination.jsx │ │ │ │ ├── Table.jsx │ │ │ │ └── Table.module.css │ │ │ ├── Tag/ │ │ │ │ ├── Tag.jsx │ │ │ │ └── Tag.module.css │ │ │ ├── Textarea/ │ │ │ │ ├── Textarea.jsx │ │ │ │ └── Textarea.module.css │ │ │ └── TitleDescription/ │ │ │ ├── TitleDescription.jsx │ │ │ ├── TitleDescription.module.css │ │ │ └── TitleDescriptionContainer.jsx │ │ ├── config/ │ │ │ ├── const.js │ │ │ └── routes.jsx │ │ ├── embedbot/ │ │ │ ├── ChatBot.css │ │ │ ├── ChatBot.jsx │ │ │ ├── ChatBotAPI.js │ │ │ └── index.jsx │ │ ├── global.css │ │ ├── layouts/ │ │ │ ├── auth/ │ │ │ │ ├── AuthLogin.jsx │ │ │ │ ├── UserAuth.module.css │ │ │ │ ├── UserLogin.jsx │ │ │ │ └── UserSignUp.jsx │ │ │ ├── dashboard/ │ │ │ │ ├── DashboadBody.jsx │ │ │ │ ├── Dashboard.jsx │ │ │ │ ├── Dashboard.module.css │ │ │ │ ├── SideMenu.jsx │ │ │ │ └── SideMenuRoutes.js │ │ │ ├── errorPage/ │ │ │ │ ├── 404.jsx │ │ │ │ ├── 500.jsx │ │ │ │ └── error.module.css │ │ │ └── general/ │ │ │ ├── GeneralLayout.jsx │ │ │ └── GeneralLayout.module.css │ │ ├── main.jsx │ │ ├── pages/ │ │ │ ├── Chat/ │ │ │ │ ├── Chat.jsx │ │ │ │ └── Chat.module.css │ │ │ ├── ChatConfiguration/ │ │ │ │ ├── Capability/ │ │ │ │ │ ├── Capability.jsx │ │ │ │ │ └── Capability.module.css │ │ │ │ ├── ChatConfiguration.jsx │ │ │ │ ├── ChatConfiguration.module.css │ │ │ │ ├── ChatConfigurationForm.jsx │ │ │ │ ├── Configuration.module.css │ │ │ │ ├── ConfigurationList.jsx │ │ │ │ └── EmptyConfiguration.jsx │ │ │ ├── Configuration/ │ │ │ │ ├── Configuration.jsx │ │ │ │ ├── Configuration.module.css │ │ │ │ ├── ConfigurationList.jsx │ │ │ │ ├── EmptyConfiguration.jsx │ │ │ │ ├── ProviderForm/ │ │ │ │ │ ├── DatabaseTable.css │ │ │ │ │ ├── ProviderForm.jsx │ │ │ │ │ └── ProviderForm.module.css │ │ │ │ └── SchemaTable/ │ │ │ │ ├── SchemaTable.jsx │ │ │ │ └── SchemaTable.module.css │ │ │ ├── Deploy/ │ │ │ │ ├── Deploy.jsx │ │ │ │ ├── Deploy.module.css │ │ │ │ ├── DeployTabs/ │ │ │ │ │ ├── CopyEmbedCode.jsx │ │ │ │ │ ├── CopyURL.jsx │ │ │ │ │ ├── DeployTabs.module.css │ │ │ │ │ ├── MaximizedLayout.jsx │ │ │ │ │ └── MinimizedLayout.jsx │ │ │ │ └── deployTabRoutes.jsx │ │ │ ├── Preview/ │ │ │ │ ├── ChatBox.jsx │ │ │ │ ├── EmptyPreview.jsx │ │ │ │ ├── Preview.jsx │ │ │ │ └── Preview.module.css │ │ │ ├── Samples/ │ │ │ │ ├── EmptySample.jsx │ │ │ │ ├── SampleForm.jsx │ │ │ │ ├── SampleList.jsx │ │ │ │ ├── Samples.jsx │ │ │ │ └── Samples.module.css │ │ │ └── Sources/ │ │ │ ├── Connetor.jsx │ │ │ ├── Sources.jsx │ │ │ └── Sources.module.css │ │ ├── routes/ │ │ │ ├── DashboardRoute.jsx │ │ │ └── MainRoute.jsx │ │ ├── services/ │ │ │ ├── Auth.js │ │ │ ├── BotConfifuration.js │ │ │ ├── Capability.js │ │ │ ├── Connectors.js │ │ │ ├── Plugins.js │ │ │ └── Sample.js │ │ ├── store/ │ │ │ └── authStore.js │ │ ├── test/ │ │ │ └── setup.js │ │ └── utils/ │ │ ├── ConfirmDialog.jsx │ │ ├── form/ │ │ │ └── GenerateConfigs.jsx │ │ ├── http/ │ │ │ ├── DeleteService.js │ │ │ ├── GetService.js │ │ │ ├── PostService.js │ │ │ ├── Request.js │ │ │ └── UploadFile.js │ │ └── utils.js │ ├── vite.config.js │ └── vite.library.config.js └── zitadel-docker-compose.yaml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ ./github .gitignore poetry.lock README.md CODE_OF_CONDUCT.md pyproject.toml CONTRIBUTING.md .flake8 LICENSE setup.py Makefile .pre-commit-config.yaml .env.example ui/node_modules pgdata ================================================ FILE: .flake8 ================================================ [flake8] max-line-length = 88 enable-extensions = N, F, C, W, E # Enable naming checks select = E201, E202, E204, E999, N801, N802, N803, N806, F401, F405, F811, F821, F823, F841, C901, W503, W504, E741, T001 exclude = .git, __pycache__, build, dist, venv # Naming and Style Checks #N801: Class names should use CamelCase #N802: Function names should be snake_case #N803: Argument names should be snake_case #N806: Variable in function should be snake_case # Functionality Checks #F405: Name may be undefined, or defined from star imports: module #F401: Module imported but unused #F811: Redefinition of unused name from line n #F823: Local variable name ... referenced before assignment #F841: Local variable name is assigned to but never used #F821: Undefined name # Performance & Efficiency # E741: Do not use ambiguous variable names like 'l', 'O', or 'I' # Code Complexity #C901: Function is too complex (cyclomatic complexity) # Line Breaks #W503: Line break before binary operator #W504: Line break after binary operator #T001: Print statements found #E201: Whitespace after '(' #E202: Whitespace before ')' #E203: Whitespace before ':' #E211: Whitespace before '(' ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. iOS] - Browser [e.g. chrome, safari] - Version [e.g. 22] **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/workflows/static.yml ================================================ # Simple workflow for deploying static content to GitHub Pages name: Deploy static content to Pages on: # Runs on pushes targeting the default branch push: branches: ["main"] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false jobs: buid_and_deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: sparse-checkout: 'documents' sparse-checkout-cone-mode: false - name: Setup Pages uses: actions/configure-pages@v5 # Set up Node.js and install dependencies with npm - name: Set up Node.js uses: actions/setup-node@v3 with: node-version: 18.0.x - name: Install docusaurus run: npm install working-directory: documents - name: Build documents run: npm run build working-directory: documents - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: documents/build - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ================================================ FILE: .gitignore ================================================ # Byte-compiled / optimized / DLL files __pycache__/ __pycache__ # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ .DS_STORE # Default vector db path vector_db chromadb #assets files assets/datasource # Default log file .cache # Default databases context_store.db raggenie.db test_db.db csv_db.sqlite # node_modules folder ui/node_modules ui/dist-library #zitadel pgdata machinekey ================================================ FILE: .pre-commit-config.yaml ================================================ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 # Use the latest version hooks: - id: check-yaml - id: check-added-large-files - id: check-case-conflict - id: check-docstring-first - id: check-merge-conflict - id: trailing-whitespace ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders 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, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at slack : https://join.slack.com/t/theailounge/shared_invite/zt-2ogkrruyf-FPOHuPr5hdqXl34bDWjHjw. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing Guidelines for RAGGENIE ## 🪜 Steps to Contribute To contribute to this project, please follow these steps: 1. Fork and clone this repository 2. Make your changes on your fork. 3. If you modify the code (for a new feature or bug fix), please add corresponding tests. 4. Check for linting issues [see below](https://github.com/sirocco-ventures/raggenie/blob/main/CONTRIBUTING.md#-Linting) 5. Ensure all tests pass [see below](https://github.com/sirocco-ventures/raggenie/blob/main/CONTRIBUTING.md#-Testing) 6. Submit a pull request For more detailed information about pull requests, please refer to [GitHub's guides](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). ## 📦 Package manager At the moment we are using pip as our package manager. Please make sure to include all the required libraries in `requirements.txt` at the time of build. ## 📌 Pre-commit To ensure our standards, make sure to install pre-commit before starting to contribute. ```bash pre-commit install ``` ## 🧹 Linting We use `Flake8` for linting our code. You can use the linter by running the following code. ```bash make linting ``` ## 📝 Code formatting We use `Flake8` as our code formatter. You can format the code using the following code. ```bash make formatting ``` ## 🗒 Spellcheck We use `codespell` for spell checking our code. For running the spellchecker run the following code. ```bash make spellcheck ``` ## 🧪 Testing we use `pytest` for integration testing the RAGGENIE. and `unittest` for unit testing individual components. for unit testing run the following code ```bash make unit-test ``` for integration testing run the following code ```bash make integration-test ``` ================================================ FILE: Dockerfile ================================================ # Stage 1: UI Build FROM node:20-alpine AS ui-build ARG BACKEND_URL WORKDIR /app/ui # Copy package files first for better caching COPY ./ui/package.json ./ui/package-lock.json ./ # Install dependencies RUN npm install # Copy the rest of the UI source code COPY ./ui/ . # Set environment variable and build ENV VITE_BACKEND_URL=$BACKEND_URL RUN npm run build # Stage 2: Python Builder FROM python:3.11 AS python-builder # Improve performance and prevent generation of .pyc files ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 # Set the working directory in the container WORKDIR /app # Copy the requirements file into the container COPY requirements.txt . # Create and activate a virtual environment, then install the dependencies RUN pip install virtualenv && \ virtualenv /opt/venv && \ . /opt/venv/bin/activate && \ pip install -r requirements.txt # Stage 3: Final Deployer FROM python:3.11 AS deployer # Copy the virtual environment from the builder stage COPY --from=python-builder /opt/venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" # Install system dependencies RUN apt-get update && \ apt-get install -y unixodbc-dev libgl1 && \ rm -rf /var/lib/apt/lists/* # Set the working directory WORKDIR /app # Copy the rest of the application code COPY . . # Copy the built UI files from the UI build stage COPY --from=ui-build /app/ui/dist ./ui/dist COPY --from=ui-build /app/ui/dist-library ./ui/dist-library EXPOSE 8001 CMD ["python3", "main.py", "--config", "./config.yaml", "llm"] ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2024 sirocco ventures Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ # Define variables POETRY = poetry PYTHON = $(POETRY) run python POETRY_VENV = .venv PROJECT_DIR=./app # Specify the directories or files to spell check SPELLCHECK_FILES := **/*.py # Default target .PHONY: help help: @echo "Available commands:" @echo " make install Install dependencies" # Install dependencies .PHONY: install install: $(POETRY) install # Spellcheck target .PHONY: spellcheck spellcheck: - codespell $(shell find ./app -name "*.py") # lint check .PHONY: lint lint: @echo "Running flake8..." flake8 $(PROJECT_DIR) ================================================ FILE: README.md ================================================

RAGGENIE Logo

RAGGENIE

## What is RAGGENIE RAGGENIE is a low-code RAG builder designed to make it easy to build your own conversational AI applications. RAGGENIE out of the box pluggins where you can connect to multiple data sources and create a conversational AI on top of that, along with integrating it with pre-built agents for actions. The project is in its early stages, and we are working on adding more capabilities soon. • Open-source tool: Since there is some community interest in this project and we can't build all the plugins ourselves, we decided to release it under the MIT license, giving the community full freedom. • Current focus: We are currently focused on making it easy to build RAG Application. Going forward we will be focusing on maintaince and monitoring of the RAG system as well cosidering how to help these applications to take from pilots to production. ### RAGGENIE Demo 1. Demo with database - [![Demo with database](https://img.youtube.com/vi/7wBO6g4rj3U/0.jpg)](https://www.youtube.com/watch?v=7wBO6g4rj3U) 2. Demo with website data - [![Demo with website data](https://img.youtube.com/vi/8h4bqqs5S3U/0.jpg)](https://www.youtube.com/watch?v=8h4bqqs5S3U) ## 🌎 Communities Join our communities for product updates, support, and to stay connected with the latest from RAGGENIE! * Join our [Slack community](https://join.slack.com/t/theailounge/shared_invite/zt-2ogkrruyf-FPOHuPr5hdqXl34bDWjHjw) RAGGENIE Logo * Leave a star on our [GitHub](https://github.com/sirocco-ventures/raggenie) 🌟 * Report bugs with [GitHub Issues](https://github.com/sirocco-ventures/raggenie/issues) 🐞 ## 📐 Architecture ![picture of Architecture flow]() ### 🔮 Supported LLM Inferences Raggenie supports inference APIs to different LLM providers to run your model. The are the inference APIs currently supported by us: * [OpenAI](https://openai.com/index/openai-api/) * [Together.ai](https://www.together.ai/) * [Ollama] (https://ollama.com/) * [AI71] (https://ai71.ai/) ### 🗃️ Data Sources These connectors will help you connect your data to RAG. It can handle structured or unstructured data, enabling the RAG to answer questions from these sources. * Structured Datasources(airtable):
You can use raggenie to connect to your data sources to analyse it or to intergrate it to your application. Raggenie generates queries to execute on your data sources and provides the results. Current integrations are: * [MySQL](https://www.mysql.com/) * [PostgreSQL](https://www.postgresql.org/) * [Bigquery](https://cloud.google.com/bigquery) * [Airtable] (https://www.airtable.com/) * [MariaDB](https://mariadb.org/) * [MSSQL] (https://www.microsoft.com/en-in/sql-server) * [SQLite] (https://www.sqlite.org/) * Document based sources(default):
These sources allows you to load documents such as text documents or Word documents to create an AI chat application that can interact with this data. Current integrations are: * Document loader * CSV loader * Website loader ### 💡Capabilities you can have more functionalities from RAGGENIE than just as a chatbot by defining its capabilities. They can be used to do tasks such as booking a meeting, checking a calendar, or completing a form from the chat. Capabilities of the chatbot are defined by the user at the time of configuration. You can setup parameters required for each capability. * RAGGENIE can make sure that all the parameters are obtained for executing the capability. * RAGGENIE uses intent extraction to decide which of its defined capabilities should be used. * Capabilities can be used to trigger different actions. ### 🤖 Agents/Actions RAGGENIE can do actions to accomplish tasks with user queries. These can be setup along with capabilities to make RAGGENIE more than just a coversation bot. Currently supported actions are. * Fetch data from a database * Insert data into database ### 🖼️ UI Plugin This component will help you embed the chat widget into your UI with JavaScript. So that you can embeed this as a chat bot to your website or portal ## 🛠️ Getting Started You can use RAGGENIE to create your own conversational chat feature for your application either by integrating it as a chatbot or by embedding it into your application. You can also use it to create different chatbots for different internal teams by tuning each chatbot for different tasks and using different knowledge base for different usecases. ### How to run Video [![Setting up RAGGENIE](https://img.youtube.com/vi/LfCqiToOCvI/0.jpg)](https://www.youtube.com/watch?v=LfCqiToOCvI) ### 📄 Documentation Comprehensive documentation is available to help you get the most out of RAGGENIE. The full documentation for RAGGENIE can be found [here]() ### 📦 Installation and running #### Raggenie Backend * Installing dependencies * **Using `requirements.txt`** To install the required dependencies with `pip`, run: ```bash pip install -r requirements.txt ``` * **Using Poetry** First, install Poetry: ```bash curl -sSL https://install.python-poetry.org | python3 - ``` Then, to install the dependencies, run: ```bash poetry install ``` * Running Zitadel Container and Initial Setup * **Prerequisities** * **Docker** installed on your system. * **Docker Compose** installed on your system. 1. Start the Zitadel container using Docker Compose: ```bash docker-compose -f zitadel-docker-compose.yaml up -d ``` 2. Once the container is running, open your browser and go to: http://localhost:8080 3. Log in using the default credentials: - **Username:** `zitadel-admin@zitadel.localhost` - **Password:** `Password1!` 4. Creating a Service User and downloading key file 1. Navigate to the **Users** tab. 2. Select **Service Users** and create a new service user. 3. Provide a username and name of your choice. 4. Set the **Access Token Type** to **JWT**. 5. Go to the **Keys** section and create a new key: - Click **New**, then **Add**, and finally **Download** the key file. 5. Go to the Organization tab, click **Add a Manager** (top right), select the service user you just created, set **Org Owner** permission, and click **Add**. 6. Follow this [guide](https://zitadel.com/docs/guides/integrate/identity-providers/google) to add Google as an identity provider. Use http://localhost:8080/idps/callback as the redirect URI. * #### Configuring Environment Variables After downloading the key file, create an `.env` file and set the following variables: ```env CLIENT_PRIVATE_KEY_FILE_PATH="./path/to/downloaded/key.json" ZITADEL_TOKEN_URL="http://localhost:8080/oauth/v2/token" ZITADEL_DOMAIN="http://localhost:8080" ``` * Running RAGGENIE backend To run **RAGGENIE** in API mode, specify the config file to use by running the following command: ```bash python main.py --config ./config.yaml llm ``` Below is a sample configuration for the vector database setup in `config.yaml`: ```yaml vector_db: name: "chroma" params: path: "./vector_db" embeddings: provider: "chroma_default" ``` This configuration ensures that the RAGGENIE system connects to the `chroma` vector database and uses the default embeddings provided by Chroma. #### Raggenie Frontend * Move into the ui folder ``` cd ./ui ``` * Install dependencies ```bash npm install ``` * Running RAGGENIE Frontend * To run **RAGGENIE** frontend, create a .env file and add the URL to backend as env variables ```env VITE_BACKEND_URL=${BACKEND_URL} ``` * To start the server, run ```bash npm run dev ``` * Running RAGGENIE Frontend using fast api * Update .env file inside `./ui` folder ```env VITE_BACKEND_URL="" ``` * To serve UI using python server first build the UI ```bash npm run build ``` * Stop and start python server ```bash python main.py --config ./config.yaml llm ``` for more details visit [frontend readme](./ui/README.md) ## ⛔️ Troubleshooting If you encounter an error while running Python, please check the following - `Your system has an unsupported version of sqlite3. Chroma requires sqlite3 >= 3.35.0` This issue arises when the system is running a version of SQLite that is below 3.35. Chroma requires SQLite version 3.35 or higher. Please use the following links for suggested solutions - https://docs.trychroma.com/troubleshooting#sqlite - https://discuss.streamlit.io/t/issues-with-chroma-and-sqlite/47950/4 - https://gist.github.com/defulmere/8b9695e415a44271061cc8e272f3c300 ## 🚧 Feature Pipeline These are the planned features and improvements that are in the pipeline for future releases. * REST API Requests for actions * Web hooks for actions ## 📜 License RagGenie is licensed under the [MIT License](https://opensource.org/license/mit), which is a permissive open-source license that allows you to freely use, modify, and distribute the software with very few restrictions. ## 🤝 Contributing Contributions are welcome! Please check the outstanding issues and feel free to open a pull request. For more information, please check out the [contribution guidelines](https://github.com/sirocco-ventures/raggenie/blob/main/CONTRIBUTING.md). ================================================ FILE: app/__init__.py ================================================ ================================================ FILE: app/api/v1/auth.py ================================================ import json import requests from app.schemas.common import LoginData from fastapi import APIRouter, Depends, Response, Request, HTTPException, status from fastapi.responses import RedirectResponse, JSONResponse from app.providers.config import configs from app.providers.zitadel import Zitadel from app.schemas.common import CommonResponse from app.providers.middleware import verify_token import app.services.user as svc import app.schemas.user as schemas from app.utils.database import get_db from sqlalchemy.orm import Session import app.api.v1.commons as commons login = APIRouter() if configs.auth_enabled: zitadel = Zitadel() @login.post("/login") def login_user(response: Response, user: LoginData, db: Session = Depends(get_db)): login_response = zitadel.login_with_username_password(user.username, user.password) # Extract user_id from the respons e if login_response.status_code == 201: response_data = login_response.body.decode("utf-8") response_json = json.loads(response_data) user_id = response_json.get("user_id") username = response_json.get("username") user, error = svc.get_or_create_user(schemas.UserCreate(id=int(user_id), username=username), db) if error: return commons.is_error_response("DB Error", error, {"user": {}}) return login_response # will redirect to idp when called with ipdId # need to set successurl and failureUrl dynamically ***** @login.get("/login/idp/{idp_id}") def idp_login(response: Response, idp_id : int): return zitadel.redirect_to_idp(idp_id) # if idp login is success then is redirected to this endpoint with which we get the user # details from the idp (currently only tested with google) @login.get("/idp/success") def idp_success(request: Request,db: Session = Depends(get_db)): query_params = request.query_params idp_intent_id = query_params.get("id") idp_token = query_params.get("token") if not idp_intent_id or not idp_token: return commons.is_error_response("Missing required parameters", {}, {"user": {}}) user_id = query_params.get("user") try: response = zitadel.get_idp_intent_data(idp_intent_id, idp_token) user_data = response.json() username = user_data.get("idpInformation", {}).get("rawInformation", {}).get("User", {}).get("name", "") if(user_id): user, error = svc.get_or_create_user(schemas.UserCreate(id=int(user_id), username=username), db) session_response = zitadel.create_user_session(user_id, idp_intent_id, idp_token) else: session_response = zitadel.create_user(user_data, idp_intent_id, idp_token) if session_response.status_code != 201: return commons.is_error_response("Failed to create Zitadel user", session_response.body.decode("utf-8"), {"user": {}}) response_data = json.loads(session_response.body.decode("utf-8")) zitadel_user_id = response_data.get("user_id") new_user = schemas.UserCreate( id=int(zitadel_user_id), username=username, ) result, error = svc.get_or_create_user(new_user, db) if error: return commons.is_error_response("DB Error", error, {"user": {}}) if not result: return commons.is_none_reponse("User Not Created", {"user": {}}) if session_response.status_code == 201: redirect_response = RedirectResponse(url="/ui", status_code=303) # Copy cookies from session_response to redirect_response for cookie in session_response.headers.getlist("set-cookie"): redirect_response.headers.append("set-cookie", cookie) return redirect_response return session_response except (requests.exceptions.RequestException, json.JSONDecodeError, AttributeError) as e: return {"error": "Failed to create session", "details": str(e)}, 500 # endpoint to retreive all the available idp providers that is setup in Zitadel @login.get("/idp/list") def list_idp(response: Response): return zitadel.list_idp_providers() @login.get("/user_info", dependencies=[Depends(verify_token)]) def get_user_info(request: Request, db: Session = Depends(get_db), user_data: dict = Depends(verify_token)): if user_data.get("username") == 'Admin': new_user = schemas.UserCreate( id=int(user_data.get("user_id")), username=user_data.get("username"), ) result, error = svc.get_or_create_user(new_user, db) if error: return commons.is_error_response("DB Error", error, {"user": {}}) if not result: return commons.is_none_reponse("User Not Created", {"user": {}}) env_id, error = svc.get_users_active_env(user_data.get("user_id"), db) if error: return commons.is_error_response("DB Error", error, {"env": {}}) return CommonResponse( status=True, status_code=200, message="User info retrieved successfully", data={ "username": user_data['username'], "auth_enabled": configs.auth_enabled, "env_id": env_id }, error=None ) session_id = user_data["session_id"] user_info = zitadel.get_user_info(session_id) username = user_info.get("session").get("factors").get("user").get("displayName") user_id = user_info.get("session").get("factors").get("user").get("id") env_id, error = svc.get_users_active_env(user_id, db) if error: return commons.is_error_response("DB Error", error, {"env": {}}) return CommonResponse( status=True, status_code=200, message="User info retrieved successfully", data={ "username": username, "auth_enabled": configs.auth_enabled, "env_id": env_id }, error=None ) # change to get user info from raggenie.db @login.post("/logout",dependencies=[Depends(verify_token)]) def logout_user(response: Response, user_data: dict = Depends(verify_token)): session_id = user_data["session_id"] res = zitadel.logout_user(session_id) if res.status_code == 200: response.delete_cookie("session_data") return res ================================================ FILE: app/api/v1/commons.py ================================================ import app.schemas.common as resp_schemas def is_error_response(message:str, err:str, data:dict): return resp_schemas.CommonResponse( status= False, status_code=422, message=message, data=data, error=err ) def is_none_reponse(message:str, data:dict): return resp_schemas.CommonResponse( status= True, status_code=200, message=message, data=data, error="Not Found" ) ================================================ FILE: app/api/v1/connector.py ================================================ from typing import List, Optional from app.providers.cache_manager import cache_manager from fastapi import APIRouter, Depends from sqlalchemy.orm import Session import app.schemas.connector as schemas import app.schemas.common as resp_schemas from app.utils.database import get_db import app.services.connector as svc import app.services.provider as provider_svc from starlette.requests import Request from fastapi import APIRouter, UploadFile, File from app.chain.chains.capability_chain import CapabilityChain from app.chain.chains.metadata_chain import MetadataChain from app.chain.chains.query_chain import QueryChain from app.chain.chains.intent_chain import IntentChain from app.chain.chains.general_chain import GeneralChain import app.api.v1.commons as commons from loguru import logger from app.providers.config import configs from app.providers.middleware import verify_token import copy router = APIRouter() cap_router = APIRouter() inference_router = APIRouter() actions = APIRouter() @router.get("/list", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def list_connectors(db: Session = Depends(get_db), provider_category_ids: Optional[List[int]] = None, user_data: dict = Depends(verify_token)): """ Retrieves a list of all connectors from the database. If a provider category ID is provided, only connectors from that category are returned. Args: db (Session): Database session dependency. Returns: CommonResponse: A response containing either the list of connectors or an error message. """ user_id = user_data["user_id"] if provider_category_ids: result, error = svc.list_connectors_by_provider_category(provider_category_ids, db, user_id) else: result, error = svc.list_connectors(db, user_id) if error: return commons.is_error_response("DB Error", result, {"connectors": []}) if not result: return commons.is_none_reponse("Connector Not Found", {"connectors": []}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"connectors": result}, message="Connectors Found", error=None ) @router.get("/get/{connector_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_connector(connector_id: int, db: Session = Depends(get_db)): """ Retrieves a specific connector by its ID from the database. Args: connector_id (int): The ID of the connector. db (Session): Database session dependency. Returns: CommonResponse: A response containing either the connector details or an error message. """ result, error = svc.get_connector(connector_id, db) if error: return commons.is_error_response("DB Error", result, {"connector": {}}) if not result: return commons.is_none_reponse("Connector Not Found", {"connector": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"connector": result}, message="Connector Found", error=None ) @router.post("/upload/datasource", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) async def upload_document_datsource( file: UploadFile = File(...) ): """ Uploads an document data source file to the server. Args: file (UploadFile): The uploaded document file. Accepted formats are .pdf, .txt, .yaml, and .docx. Returns: CommonResponse: A response containing the file upload status, file details, or an error message. """ error, size = await svc.fileValidation(file) if error: return commons.is_error_response("Invalid File", error, {"file_path": None}) result, error = await svc.upload_pdf(file) if error: return commons.is_error_response("document not uploaded", error, {"file_path": None}) return resp_schemas.CommonResponse( status=True, status_code=201, data={"file": {"file_path": result["file_path"],"file_name": file.filename, "file_size":f"{round(size / (1024 * 1024), 2)}MB", "file_id": result["file_id"]}}, message="File Uploaded Success", error=None ) @router.post("/create", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def create_connector(connector: schemas.ConnectorBase, db: Session = Depends(get_db), user_data: dict = Depends(verify_token)): """ Creates a new connector in the database. Args: connector (ConnectorBase): The data for the new connector. db (Session): Database session dependency. Returns: CommonResponse: A response indicating success or failure of the connector creation process. """ user_id = user_data["user_id"] result, error = svc.create_connector(connector, db, user_id) if error: return commons.is_error_response("Connector Not Created", error, {"connector": {}}) return resp_schemas.CommonResponse( status=True, status_code=201, data={"connector": result}, message="Connector Created", error=None ) @router.post("/update/{connector_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def update_connector(connector_id: int, connector: schemas.ConnectorUpdate, db: Session = Depends(get_db)): """ Updates an existing connector based on its ID. Args: connector_id (int): The ID of the connector to update. connector (ConnectorUpdate): The updated data for the connector. db (Session): Database session dependency. Returns: CommonResponse: A response indicating success or failure of the update process. """ result, error = svc.update_connector(connector_id, connector, db) if error: return commons.is_error_response("DB Error", result, {"connector": {}}) if not result: return commons.is_none_reponse("Connector Not Found", {"connector": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"connector": result}, message="Connector Updated", error=None ) @router.post("/delete/{connector_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def delete_connector(connector_id: int, db: Session = Depends(get_db)): """ Deletes a connector from the database based on its ID. Args: connector_id (int): The ID of the connector to delete. db (Session): Database session dependency. Returns: CommonResponse: A response indicating success or failure of the deletion process. """ result, error = svc.delete_connector(connector_id, db) if error: return commons.is_error_response("DB Error", result, {"connector": {}}) if not result: return commons.is_none_reponse("Connector Not Found", {"connector": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"connector": result}, message="Connector Deleted", error=None ) @router.post("/schema/update/{connector_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def updateschemas(connector_id: int, connector: schemas.SchemaUpdate, db: Session = Depends(get_db)): """ Updates the schema details of a connector based on its ID. Args: connector_id (int): The ID of the connector whose schema is being updated. connector (SchemaUpdate): The schema update data for the connector. db (Session): Database session dependency. Returns: CommonResponse: A response indicating success or failure of the schema update. """ result, error = svc.updateschemas(connector_id, connector, db) if error: return commons.is_error_response("DB Error", result, {"schemas": {}}) if not result: return commons.is_none_reponse("Connector Not Found", {"schemas": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"schemas": result}, message="Schema Updated", error=None ) @router.get("/configuration/list", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def list_configurations(db: Session = Depends(get_db), user_data: dict = Depends(verify_token)): """ Lists all available configurations from the database. Args: db (Session): Database session dependency. Returns: CommonResponse: A response containing the list of configurations or an error message. """ user_id = user_data["user_id"] result, error = svc.list_configurations(db, user_id) if error: return commons.is_error_response("DB error", result, {"configurations": []}) if not result: return commons.is_none_reponse("Configurations Not Found", {"configurations": []}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Configurations retrieved successfully", error=None, data={"configurations": result} ) @router.get("/configuration/{config_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_configuration(config_id: int, db: Session = Depends(get_db)): """ Retrieves a configuration by its ID. Args: config_id (int): ID of the configuration to retrieve. db (Session): Database session dependency. Returns: CommonResponse: A response containing the configuration or an error message. """ result, error = svc.get_configuration(db, config_id) if error == "DB Error": return commons.is_error_response("DB error", result, {"configuration": None}) if error == "Configuration not found": return commons.is_none_reponse("Configuration Not Found", {"configuration": None}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Configuration retrieved successfully", error=None, data={"configuration": result} ) @router.delete("/configuration/{config_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_configuration(config_id: int, db: Session = Depends(get_db)): """ Retrieves a configuration by its ID. Args: config_id (int): ID of the configuration to retrieve. db (Session): Database session dependency. Returns: CommonResponse: A response containing the configuration or an error message. """ result, error = svc.delete_configuration(db, config_id) if error == "DB Error": return commons.is_error_response("DB error", result, {"configuration": None}) if error == "Configuration not found": return commons.is_none_reponse("Configuration Not Found", {"configuration": None}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Configuration deleted successfully", error=None, data={"configuration": result} ) @router.post("/configuration/create", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def create_configuration(configuration: schemas.ConfigurationCreation, db: Session = Depends(get_db), user_data: dict = Depends(verify_token)): """ Creates a new configuration and stores it in the database. Args: configuration (ConfigurationCreation): The new configuration details. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the configuration creation. """ user_id = user_data["user_id"] result, error = svc.create_configuration(configuration, db, user_id) if error: return commons.is_error_response("DB error", result, {"configuration": []}) if not result: return commons.is_none_reponse("Configuration Not Found", {"configuration": {}}) return resp_schemas.CommonResponse( status=True, status_code=201, message="Configuration created successfully", error=None, data={"configuration": result} ) @router.post("/configuration/update/{config_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def update_configuration(config_id: int, configuration: schemas.ConfigurationUpdate, db: Session = Depends(get_db)): """ Updates an existing configuration in the database. Args: config_id (int): The ID of the configuration to update. configuration (ConfigurationUpdate): The updated configuration details. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the configuration update. """ result, error = svc.update_configuration(config_id, configuration, db) if error: return commons.is_error_response("DB error", result, {"configuration": []}) if not result: return commons.is_none_reponse("Configuration Not Found", {"configuration": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Configuration updated successfully", error=None, data={"configuration": result} ) @cap_router.post("/create", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def create_capability(capability: schemas.CapabilitiesBase, db: Session = Depends(get_db)): """ Creates a new capability in the database. Args: capability (CapabilitiesBase): The new capability details. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the capability creation. """ result, error = svc.create_capabilities(capability, db) if error: return commons.is_error_response("DB error", result, {"capability": {}}) return resp_schemas.CommonResponse( status=True, status_code=201, message="Capabilities created successfully", error=None, data={"capability": result} ) @cap_router.get("/all", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_all_capabilities(db: Session = Depends(get_db)): """ Retrieves all capabilities from the database. Args: db (Session): Database session dependency. Returns: CommonResponse: A response containing the list of capabilities or an error message. """ result, error = svc.get_all_capabilities(db) if error: return commons.is_error_response("DB error", result, {"capabilities": []}) if not result: return commons.is_none_reponse("Capabilities Not Found", {"capabilities": []}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Capabilities retrieved successfully", error=None, data={"capabilities": result} ) @cap_router.post("/update/{cap_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def update_capability(cap_id: int, capability: schemas.CapabilitiesUpdateBase, db: Session = Depends(get_db)): """ Updates an existing capability in the database. Args: cap_id (int): The ID of the capability to update. capability (CapabilitiesUpdateBase): The updated capability details. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the capability update. """ result, error = svc.update_capability(cap_id, capability, db) if error: return commons.is_error_response("DB error", result, {"capability": {}}) if not result: return commons.is_none_reponse("Capability Not Found", {"capability": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Capability updated successfully", error=None, data={"capability": result} ) @cap_router.delete("/delete/{cap_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def delete_capability(cap_id: int, db: Session = Depends(get_db)): """ Deletes an existing capability from the database. Args: cap_id (int): The ID of the capability to delete. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the capability deletion. """ result, error = svc.delete_capability(cap_id, db) if error: return commons.is_error_response("DB error", result, {"capability": {}}) if not result: return commons.is_none_reponse("Capability Not Found", {"capability": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Capability deleted successfully", error=None, data={"capability": {}} ) @router.post("/createyaml/{config_id}", dependencies=[Depends(verify_token)]) def create_yaml(request: Request, config_id: int, db: Session = Depends(get_db), index: Optional[bool] = True): """ Creates a YAML configuration file and initializes processing chains for the specified configuration. Args: request (Request): The request object containing the data for YAML creation. config_id (int): The ID of the configuration to use. db (Session): The database session dependency. Returns: dict: A dictionary with success status and error message, if any. """ documentations, use_case, is_error = svc.create_yaml_file(request,config_id, db) if is_error: return { "success":False, "error":is_error } inference_config, is_error = svc.create_inference_yaml(config_id,db) if is_error and not inference_config: return { "success":False, "error":is_error } combined_yaml_content = { 'datasources': documentations if documentations != None else [], 'use_case': use_case } configs.inference_llm_model=inference_config[0]["unique_name"] config = copy.deepcopy(request.app.config) vector_store, is_error = provider_svc.create_vectorstore_instance(db, config_id) if vector_store: vector_store.connect() context_storage = request.app.context_storage data_sources = combined_yaml_content["datasources"] use_case = combined_yaml_content["use_case"] config["use_case"] = use_case config["datasources"] = data_sources config["models"] = inference_config confyaml = svc.get_inference_and_plugin_configurations(db, config_id) request.app.container.config.from_dict(confyaml) datasources = request.app.container.datasources() mappings = confyaml.get("mappings",{}) datasources, err = svc.update_datasource_documentations(db, vector_store, datasources, mappings, config_id, index) if err: logger.error("Error updating") query_chain = QueryChain(config, vector_store, datasources, context_storage) general_chain = GeneralChain(config, vector_store, datasources, context_storage) capability_chain = CapabilityChain(config, context_storage, query_chain) metedata_chain = MetadataChain(config, vector_store, datasources, context_storage) chain = IntentChain(config, vector_store, datasources, context_storage, query_chain, general_chain, capability_chain, metedata_chain) cache_manager.set(config_id, { "chain": chain, "config": config, "vector_store": vector_store, "datasources": datasources, "context_storage": context_storage }) return { "success": True, "error":None } @inference_router.post("/get/models", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_llm_provider_models(llm_provider: schemas.LLMProviderBase): """ Retrieves the models associated with the specified LLM provider. Args: llm_provider (schemas.LLMProviderBase): The details of the LLM provider. db (Session): The database session dependency. Returns: CommonResponse: A response containing the list of LLM provider models or an error message. """ data, is_error = svc.get_llm_provider_models(llm_provider) if is_error: return commons.is_error_response("LLM Provider Models Not Found", data, {"provider_models": []}) return resp_schemas.CommonResponse( status=True, status_code=200, message="LLM Provider Models Found", error=None, data={"provider_models": [data]} ) @inference_router.get("/get/{inference_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_inference(inference_id: int, db: Session = Depends(get_db)): """ Retrieves an inference record from the database using the given inference ID. Args: inference_id (int): The ID of the inference record to retrieve. db (Session): The database session dependency. Returns: dict: A dictionary with the inference details or error message, if any. """ result, error = svc.get_inference(inference_id, db) if error: return commons.is_error_response("DB error", result, {"inference": {}}) if not result: return commons.is_none_reponse("Inference Not Found", {"inference": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Inference Found", error=None, data={"inference": result} ) @inference_router.post("/create", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def create_inference(inference: schemas.InferenceBase, db: Session = Depends(get_db)): """ Creates a new inference record in the database. Args: inference (schemas.InferenceBase): The details of the inference to be created. db (Session): The database session dependency. Returns: dict: A dictionary indicating the success of the operation and the created inference details or error message. """ success, message = provider_svc.test_inference_credentials(inference) if not success: return commons.is_error_response("Test Credentials Failed", message, {"inference": {}}) result, error = svc.create_inference(inference, db) if error: return commons.is_error_response("DB error", result, {"inference": {}}) return resp_schemas.CommonResponse( status=True, status_code=201, message="Inference Created Successfully", error=None, data={"inference": result} ) @inference_router.post("/update/{inference_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def update_inference(inference_id: int, inference: schemas.InferenceBaseUpdate, db: Session = Depends(get_db)): """ Updates an existing inference record in the database. Args: inference_id (int): The ID of the inference record to update. inference (schemas.InferenceBaseUpdate): The updated details of the inference. db (Session): The database session dependency. Returns: dict: A dictionary with the status of the update operation and the updated inference details or error message, if any. """ success, message = provider_svc.test_inference_credentials(inference) if not success: return commons.is_error_response("Test Credentials Failed", message, {"inference": {}}) result, error = svc.update_inference(inference_id, inference, db) if error: return commons.is_error_response("DB error", result, {"inference": {}}) if not result: return commons.is_none_reponse("Inference Not Found", {"inference": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Inference Updated Successfully", error=None, data={"inference": result} ) @actions.get("/list", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def list_actions(db: Session = Depends(get_db)): """ Retrieves all actions from the database. Args: db (Session): Database session dependency. Returns: CommonResponse: A response containing the list of actions or an error message. """ result, error = svc.list_actions(db) if error: return commons.is_error_response("DB error", result, {"actions": []}) if not result: return commons.is_none_reponse("Actions Not Found", {"actions": []}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"actions": result}, message="Actions Found", error=None ) @actions.get("/get/{action_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_action(action_id:int, db: Session = Depends(get_db)): """ Retrieves a specific action by its ID. Args: action_id (int): The unique identifier of the action to retrieve. db (Session): Database session dependency. Returns: CommonResponse: A response containing the action details or an error message. """ result, error = svc.get_actions(action_id,db) if error: return commons.is_error_response("DB error", result, {"action": {}}) if not result: return commons.is_none_reponse("Action Not Found", {"action": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"action": result}, message="Action Found", error=None ) @actions.get("/{connector_id}/list", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_actions_by_connector(connector_id:int, db: Session = Depends(get_db)): """ Retrieves all actions related to a specific connector by its ID. Args: connector_id (int): The unique identifier of the connector. db (Session): Database session dependency. Returns: CommonResponse: A response containing the list of actions or an error message. """ result, error = svc.get_actions_by_connector(connector_id,db) if error: return commons.is_error_response("DB error", result, {"actions": []}) if not result: return commons.is_none_reponse("Actions Not Found", {"actions": []}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"actions": result}, message="Action Found", error=None ) @actions.post("/create", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def create_action(action: schemas.Actions, db: Session = Depends(get_db)): """ Creates a new action in the database. Args: action (Actions): The schema containing action details to create. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the action creation. """ result, error = svc.create_action(action, db) if error: return commons.is_error_response("Action Not Created", result, {"action": {}}) return resp_schemas.CommonResponse( status=True, status_code=201, data={"action": result}, message="Action Created", error=None ) @actions.post("/update/{action_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def update_action(action_id: int, action: schemas.ActionsUpdate, db: Session = Depends(get_db)): """ Updates an existing action in the database by its ID. Args: action_id (int): The unique identifier of the action to update. action (ActionsUpdate): The schema containing updated action details. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the action update. """ result, error = svc.update_action(action_id, action, db) if error: return commons.is_error_response("DB error", result, {"action": {}}) if not result: return commons.is_none_reponse("Action Not Found", {"action": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"action": result}, message="Action Updated", error=None ) @actions.post("/{action_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def delete_action(action_id: int, db: Session = Depends(get_db)): """ Deletes an action by its ID from the database. Args: action_id (int): The unique identifier of the action to delete. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the action deletion. """ result, error = svc.delete_action(action_id, db) if error: return commons.is_error_response("DB error", result, {"action": {}}) if not result: return commons.is_none_reponse("Action Not Found", {"action": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"action": result}, message="Action Deleted", error=None ) ================================================ FILE: app/api/v1/llmchat.py ================================================ # src/endpoints/chat.py from fastapi import APIRouter, Depends from sqlalchemy.orm import Session import app.schemas.common as resp_schemas from app.schemas import llmchat as schemas from app.utils.database import get_db from app.services import llmchat as svc import app.api.v1.commons as commons chat_router = APIRouter() # Create a new chat @chat_router.post("/create", response_model=resp_schemas.CommonResponse) def create_chat(chat: schemas.ChatHistoryCreate, db: Session = Depends(get_db)): """ Creates a new chat record in the database. Args: chat (ChatHistoryCreate): The data for the new chat entry. db (Session): Database session dependency. Returns: CommonResponse: A response indicating success or failure of the chat creation process. """ result, error = svc.create_chat(chat, db) if error: return commons.is_error_response("DB Error", result, {"chat": {}}) return resp_schemas.CommonResponse( status=True, status_code=201, data={"chat": result}, message="Chat created successfully", error=None ) # Create feedback for a chat @chat_router.post("/feedback/create", response_model=resp_schemas.CommonResponse) def create_feedback(feedback: schemas.FeedbackCreate, db: Session = Depends(get_db)): """ Creates feedback for an existing chat record. Args: feedback (FeedbackCreate): The feedback data to be added to the chat. db (Session): Database session dependency. Returns: CommonResponse: A response indicating success or failure of the feedback creation process. """ result, error = svc.create_feedback(feedback, db) if error: return commons.is_error_response("DB Error", result, {"chat": {}}) if not result: return commons.is_none_reponse("Chat Not Found", {"chat": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"chat": result}, message="Feedback updated successfully", error=None ) # List the primary chat based on context @chat_router.get("/list/context/all/{env_id}", response_model=resp_schemas.CommonResponse) def list_chat_by_context(env_id: int, db: Session = Depends(get_db)): """ Retrieves all the primary chats based on context from the database. Args: db (Session): Database session dependency. Returns: CommonResponse: A response containing either the list of primary chats or an error message. """ result, error = svc.list_chats_by_context(env_id, db) if error: return commons.is_error_response("DB Error", error, {"chats": []}) if not result: return commons.is_none_reponse("Context Not found", {"chats": []}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"chats": result}, message="Primary chats found", error=None ) # Get a specific chat by context ID @chat_router.get("/get/{context_id}", response_model=resp_schemas.CommonResponse) def get_chat_by_context(context_id: str, db: Session = Depends(get_db)): """ Retrieves a specific chat by context ID from the database. Args: context_id (str): The ID of the context to retrieve the chat for. db (Session): Database session dependency. Returns: CommonResponse: A response containing either the chat data or an error message. """ result, error = svc.list_all_chats_by_context_id(context_id, db) if error: return commons.is_error_response("DB Error", error, {"chats": []}) if not result: return commons.is_none_reponse("Chat not found", {"chats": []}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"chats": result}, message="Chat found", error=None ) ================================================ FILE: app/api/v1/main_router.py ================================================ from app.providers.cache_manager import cache_manager from fastapi import APIRouter, Depends, status, Query from fastapi.encoders import jsonable_encoder from app.models.request import Chat, FeedbackCorrectionRequest from starlette.requests import Request from loguru import logger from app.schemas import llmchat as schemas from app.api.v1 import llmchat from app.api.v1 import connector from sqlalchemy.orm import Session from app.utils.database import get_db MainRouter = APIRouter() @MainRouter.post("/query", status_code=status.HTTP_201_CREATED) async def qna( query: Chat, request: Request, context_id: str = Query(..., alias="contextId"), config_id: str = Query(..., alias="configId"), env_id: str = Query(..., alias="envId"), db: Session = Depends(get_db) ): """ Handles user queries and invokes the chain to get an answer from the LLM. Args: query (Chat): User query as a Chat model. request (Request): FastAPI request object containing context and app-level dependencies. background_tasks (BackgroundTasks): Background task for asynchronous logging. db (Session): Database session dependency. Returns: dict: Response containing the answer to the user's query and the original query text. """ logger.info(f"{context_id} - {config_id} - query: {query.content}") cached_data = cache_manager.get(int(config_id)) if not cached_data: logger.info("configuration was not found in the cache") response = connector.create_yaml(request, int(config_id), db, False) if response['success'] == True: cached_data = cache_manager.get(int(config_id)) else: return chain = cached_data["chain"] vector_store = cached_data['vector_store'] request.app.chain = chain request.app.vector_store = vector_store out = await chain.invoke({ "question": query.content, "context_id": context_id, }) resp = llmchat.create_chat( schemas.ChatHistoryCreate( chat_context_id=context_id, chat_query=query.content, chat_answer= jsonable_encoder(out), chat_summary=out.get("summary", query.content), configuration_id=config_id, environment_id=env_id ), db ) if resp.status: out["chat_id"] = resp.data["chat"].chat_id return { "response": out, "query": query.content, } #! This api is not in use right now, instead we are using a scheduler for the feedback_correction job @MainRouter.post("/feedback_correction", status_code=status.HTTP_201_CREATED) def feedback_correction(request: Request, body: FeedbackCorrectionRequest): """ Processes feedback from LLM responses and updates the vector store accordingly. Args: request (Request): FastAPI request object containing the app's vector store. body (FeedbackCorrectionRequest): Request body containing user feedback to be processed. Returns: str: Success message indicating the feedback processing outcome. """ store = request.app.vector_store if body.responses: for response in body.responses: similar_sample = store.find_similar_samples(response.description) if len(similar_sample) > 0 and similar_sample[0]['distances'] < 0.3: store.update_store(similar_sample[0]['id'],response.metadata,response.description) else: store.update_store(metadatas = response.metadata,documents = response.description) return "Success: Feedback received and processed." else: return "Success: No Feedback received and processed." ================================================ FILE: app/api/v1/provider.py ================================================ from fastapi import APIRouter, Depends from sqlalchemy.orm import Session import app.schemas.common as resp_schemas import app.schemas.provider as schemas from app.utils.database import get_db import app.services.provider as svc import app.api.v1.commons as commons import app.schemas.connector as conn_schemas from fastapi import Request from app.providers.middleware import verify_token router = APIRouter() sample = APIRouter() vectordb = APIRouter() @router.get("/list", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def list_providers(db: Session = Depends(get_db)): """ Retrieves a list of providers (plugins) from the database. Args: db (Session): Database session dependency. Returns: CommonResponse: A response containing either the list of providers or an error message. """ result, error = svc.list_providers(db) if error: return commons.is_error_response("DB error", result, {"providers": []}) if not result: return commons.is_none_reponse("Providers Not Found", {"providers": []}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"providers": result}, message="Providers Found", error=None ) @router.get("/get/{provider_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_provider(provider_id: int, db: Session = Depends(get_db)): """ Retrieves a specific provider (plugin) by its ID. Args: provider_id (int): The ID of the provider to retrieve. db (Session): Database session dependency. Returns: CommonResponse: A response containing either the provider details or an error message. """ result, error=svc.get_provider(provider_id, db) if error: return commons.is_error_response("DB error", result, {"provider": {}}) if not result: return commons.is_none_reponse("Providers Not Found", {"provider": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"provider": result}, message="Provider Found", error=None ) @router.post("/{provider_id}/test-credentials", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def test_connections(provider_id: int, config: schemas.TestCredentials, db: Session = Depends(get_db)): """ Tests the credentials for a specific provider (plugin) by its ID. Args: provider_id (int): The ID of the provider for which to test credentials. config (TestCredentials): The credentials to test. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the credential test. """ success, message = svc.test_credentials(provider_id, config, db) if not success: return resp_schemas.CommonResponse( status=False, status_code=422, message=message, error=message, ) return resp_schemas.CommonResponse( status=True, status_code=200, message=message, error=None, ) @vectordb.post("/test_credentials", response_model=resp_schemas.CommonResponse) def test_vectordb_credentials(config: schemas.TestVectorDBCredentials, db: Session = Depends(get_db)): """ Tests the credentials for a VectorDB provider. Args: config (TestVectorDBCredentials): The credentials to test. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the credential test. """ message, is_error = svc.test_vectordb_credentials(config, db) if is_error: return resp_schemas.CommonResponse( status=False, status_code=422, message="Test credentials Failed", error=message, ) return resp_schemas.CommonResponse( status=True, status_code=200, message=message, error=None, ) @vectordb.get("/list/all",response_model= resp_schemas.CommonResponse) def getvectordbs(db: Session = Depends(get_db)): """ Retrieves a list of available VectorDB providers. Args: request (Request): The HTTP request object. Returns: CommonResponse: A response containing either the list of VectorDB providers or an error message. """ result, is_error = svc.getvectordbs(db) if is_error: return commons.is_error_response("DB error", result, {"vectordbs": []}) if not result: return commons.is_none_reponse("Sample SQL Not Found", {"vectordbs": []}) return resp_schemas.CommonResponse( status=True, status_code=200, message="VectorDB providers found", data={"vectordbs":result}, error=None, ) @router.get("/llmproviders", response_model=resp_schemas.CommonResponse) def getllmproviders(request: Request): """ Retrieves a list of available LLM (Large Language Model) providers. Args: request (Request): The HTTP request object. Returns: CommonResponse: A response containing either the list of LLM providers or an error message. """ result, is_error = svc.getllmproviders(request) if is_error: return resp_schemas.CommonResponse( status=False, status_code=422, message="LLM providers not found", error=None, ) return resp_schemas.CommonResponse( status=True, status_code=200, message="LLM providers found", data=result, error=None, ) @router.post("/test-inference-credentials", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def test_inference_connections(inference: conn_schemas.InferenceBase): """ Tests the inference connections by validating the credentials for a specific LLM provider. Args: inference (conn_schemas.InferenceBase): Configuration object containing the provider details, including model name, API key, and endpoint, for testing the connections. Returns: resp_schemas.CommonResponse: - Response object containing: - status (bool): Indicates whether the credentials validation was successful. - status_code (int): HTTP status code (200 for success, 422 for failure). - message (str): A message providing the outcome of the credentials test. - error (Optional[str]): Error message if the credentials test failed, otherwise None. """ success, message = svc.test_inference_credentials(inference) if not success: return resp_schemas.CommonResponse( status=False, status_code=422, message="Test Credentials Failed", error=message, ) return resp_schemas.CommonResponse( status=True, status_code=200, message=message, error=None, ) @sample.get("/list", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def list_sql(db: Session = Depends(get_db), user_data: dict = Depends(verify_token)): """ Retrieves a list of sample SQL records from the database. Args: db (Session): Database session dependency. Returns: CommonResponse: A response containing either the list of sample SQL records or an error message. """ user_id = user_data["user_id"] result, error = svc.listsql(db, user_id) if error: return commons.is_error_response("DB error", result, {"sql": []}) if not result: return commons.is_none_reponse("Sample SQL Not Found", {"sql": []}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"sql": result}, message="Sample SQL Found", error=None ) @sample.get("/{id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_sql(id: int, db: Session = Depends(get_db)): """ Retrieves a specific sample SQL record by its ID. Args: id (int): The ID of the sample SQL record to retrieve. db (Session): Database session dependency. Returns: CommonResponse: A response containing either the SQL record or an error message. """ result, error = svc.getsql(id, db) if error: return commons.is_error_response("DB error", result, {"sql": {}}) if not result: return commons.is_none_reponse("Sample SQL Not Found", {"sql": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, data={"sql": result}, message="Sample SQL Found", error=None ) @sample.post("/create", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def create_sql(request:Request,sql: schemas.SampleSQLBase, db: Session = Depends(get_db), user_data: dict = Depends(verify_token)): """ Creates a new sample SQL record in the database. Args: request (Request): The HTTP request object. sql (SampleSQLBase): The data for the new SQL record. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the SQL creation process. """ user_id = user_data["user_id"] result, error = svc.create_sql(request, sql, db, user_id) if error: return commons.is_error_response("DB error", result, {"sql": {}}) return resp_schemas.CommonResponse( status=True, status_code=201, message="Sample SQL Created Successfully", error=None, data={"SQL": result} ) @sample.post("/update/{id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def update_sql(id: int, request: Request, sql: schemas.SampleSQLUpdate, db: Session = Depends(get_db)): """ Updates an existing sample SQL record by its ID. Args: id (int): The ID of the SQL record to update. request (Request): The HTTP request object. sql (SampleSQLUpdate): The updated SQL data. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the SQL update process. """ result, error = svc.update_sql(request, id, sql, db) if error: return commons.is_error_response("DB error", result, {"sql": {}}) if not result: return commons.is_none_reponse("Sample SQL Not Found", {"sql": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Sample SQL Updated Successfully", error=None, data={"sql": result} ) @sample.post("delete/{id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def delete_sql(id: int, db: Session = Depends(get_db)): """ Deletes a sample SQL record by its ID. Args: id (int): The ID of the SQL record to delete. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the SQL deletion process. """ result, error = svc.delete_sql(id, db) if error: return commons.is_error_response("DB error", result, {"sql": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Sample SQL Deleted Successfully", error=None, ) @vectordb.post("/create", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def create_vectordb_instance(vectordb: schemas.VectorDBBase, db: Session = Depends(get_db)): """ Creates a new VectorDB instance in the database. Args: request (Request): The HTTP request object. sql (VectorDBBase): The data for the new VectorDB instance. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the VectorDB instance creation process. """ result, error = svc.create_vectordb_and_embedding("create",0,vectordb, db) if error: return commons.is_error_response("DB error", result, {"vectordb": {}}) return resp_schemas.CommonResponse( status=True, status_code=201, message="VectorDB Instance Created Successfully", error=None, data={"VectorDB": result} ) @vectordb.post("/update/{id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def update_vectordb_instance(id:int,vectordb: schemas.VectorDBUpdateBase, db: Session = Depends(get_db)): """ Updates VectorDB instance in the database. Args: request (Request): The HTTP request object. sql (VectorDBBase): The data for the new VectorDB instance. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the VectorDB instance creation process. """ result, error = svc.create_vectordb_and_embedding(key="update",id=id,vectordb=vectordb, db=db) if error: return commons.is_error_response("DB error", result, {"vectordb": {}}) return resp_schemas.CommonResponse( status=True, status_code=201, message="VectorDB Instance Updated Successfully", error=None, data={"VectorDB": result} ) @vectordb.get("/get/{config_id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_vectordb_instance(id: int, db: Session = Depends(get_db)): """ Retrieves a VectorDB instance by its ID. Args: id (int): The ID of the VectorDB instance. db (Session): Database session dependency. Returns: CommonResponse: A response containing the VectorDB instance or an error message. """ result, error = svc.get_vectordb_instance(id, db) if error: return commons.is_error_response("DB error", result, {"vectordb": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, message="VectorDB Instance Retrieved Successfully", error=None, data={"VectorDB": result} ) @vectordb.delete("/delete/{id}", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def delete_vectordb_instance(id: int, db: Session = Depends(get_db)): """ Deletes a VectorDB instance by its ID, along with its associated config mapping. Args: id (int): The ID of the VectorDB instance to delete. db (Session): Database session dependency. Returns: CommonResponse: A response indicating the success or failure of the deletion process. """ result, error = svc.delete_vectordb_instance(id, db) if error: return commons.is_error_response("DB error or VectorDB not found", result, {"vectordb": {}}) return resp_schemas.CommonResponse( status=True, status_code=200, message="VectorDB Instance Deleted Successfully", error=None, data={"VectorDB": result} ) @vectordb.get("/embedding/all", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)]) def get_all_embeddings(): """ Retrieves all embeddings from module. Returns: CommonResponse: A response containing the embeddings or an error message. """ result, error = svc.get_all_embeddings() if error: return commons.is_error_response("Fetching Error", result, {"embeddings": []}) return resp_schemas.CommonResponse( status=True, status_code=200, message="Embeddings Retrieved Successfully", error=None, data={"embeddings": result} ) ================================================ FILE: app/base/abstract_handlers.py ================================================ from __future__ import annotations from abc import ABC, abstractmethod from typing import Any, Optional class Handler(ABC): """ The Handler interface declares a method for building the chain of handlers. It also declares a method for executing a request. """ @abstractmethod def set_next(self, handler: Handler) -> Handler: pass @abstractmethod async def handle(self, request) -> Optional[str]: pass class AbstractHandler(Handler): """ The default chaining behavior can be implemented inside a base handler class. """ _next_handler: Handler = None def set_next(self, handler: Handler) -> Handler: self._next_handler = handler # Returning a handler from here will let us link handlers in a # convenient way like this: # monkey.set_next(squirrel).set_next(dog) return handler @abstractmethod async def handle(self, request: Any) -> str: if self._next_handler: return await self._next_handler.handle(request) return None ================================================ FILE: app/base/base_formatter.py ================================================ from abc import ABC, abstractmethod class BaseFormatter(ABC): @abstractmethod def format(self)-> (dict): """ Abstract method to format data. This method should be implemented by subclasses to define specific formatting logic. Returns: dict: A dictionary containing the formatted data. """ pass ================================================ FILE: app/base/base_llm.py ================================================ # SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # 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 # # 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. from typing import List, Optional, Any import requests import json from langchain.callbacks.manager import ( AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun, ) from langchain.llms.base import LLM from loguru import logger class BaseLLM(LLM): temperature: Optional[float] = 0.5 url: Any = "" headers : Optional[Any] = {} body : Optional[Any] = {} def _call( self, prompt: Optional[str]="", stop: Optional[List[str]] = None, run_manager: Optional[CallbackManagerForLLMRun] = None, ) -> str: if prompt != "": self.body["prompt"] = prompt try: r = requests.post(self.url, json=self.body,headers=self.headers) model_out = json.loads(r.content) except Exception as e: logger.error(e) model_out = {} return model_out async def _acall( self, prompt: str, stop: Optional[List[str]] = None, run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, **kwargs: Any, ) -> str: return "hi" @property def _llm_type(self) -> str: return "rest llm" @property def _identifying_params(self) -> dict: return { "url": self.url, } ================================================ FILE: app/base/base_plugin.py ================================================ from abc import ABC, abstractmethod class BasePlugin(ABC): @abstractmethod def connect(self): pass @abstractmethod def healthcheck(self): pass ================================================ FILE: app/base/base_vectordb.py ================================================ from app.embeddings.loader import EmLoader class BaseVectorDB(): def load_embeddings_function(self): return EmLoader(self.embeddings).load_embclass().load_emb() ================================================ FILE: app/base/document_data_plugin.py ================================================ from abc import ABC, abstractmethod from typing import Dict, Any, Optional class DocumentDataPlugin(ABC): @abstractmethod def fetch_data(self, params: Optional[Dict[str, Any]] = None) -> list: """ Fetches data based on the provided parameters. :param params: Optional query parameters. :return: a list of strings """ pass ================================================ FILE: app/base/loader_metadata_mixin.py ================================================ import importlib from loguru import logger class LoaderMetadataMixin: # plugin default variables __unique_name__ = "" __display_name__ = "" __icon__ = "" def __init__(self, name): logger.info("Initializing mixin class") self._load_metadata(name.removesuffix('.loader')) @classmethod def _load_metadata(self, class_path): module = importlib.import_module(class_path) try: self.__unique_name__ = getattr(module, '__unique_name__') self.__display_name__ = getattr(module, '__display_name__') self.__icon__ = getattr(module, '__icon__') except Exception as e: raise Exception(e) ================================================ FILE: app/base/messaging_plugin.py ================================================ from abc import ABC, abstractmethod class MessagePlugin(ABC): @abstractmethod def send(self): pass ================================================ FILE: app/base/model_loader.py ================================================ class ModelLoader: def __init__(self, model_config): self.model_config = model_config def load_model(self): raise NotImplementedError("load_model method must be implemented in subclass") def get_response(self) -> dict: raise NotImplementedError("load_model method must be implemented in subclass") def get_usage(self, prompt, response, out) -> dict: raise NotImplementedError("load_model method must be implemented in subclass") def get_models(self): raise NotImplementedError("load_model method must be implemented in subclass") ================================================ FILE: app/base/plugin_metadata_mixin.py ================================================ import importlib from loguru import logger class PluginMetadataMixin: # plugin default variables __version__ = "" __plugin_name__ = "" __description__ = "" __icon__ = "" __connection_args__= "" __category__ = "" __prompt__ = "" def __init__(self, name): logger.info("Initializing mixin class") self._load_metadata(name.removesuffix('.handler')) @classmethod def _load_metadata(self, class_path): module = importlib.import_module(class_path) try: self.__version__ = getattr(module, '__version__') self.__plugin_name__ = getattr(module, '__plugin_name__') self.__description__ = getattr(module, '__description__') self.__icon__ = getattr(module, '__icon__') self.__connection_args__ = getattr(module, '__connection_args__') self.__category__ = getattr(module, '__category__') self.__prompt__ = getattr(module, '__prompt__') except Exception as e: raise Exception(e) ================================================ FILE: app/base/query_plugin.py ================================================ from abc import ABC, abstractmethod from typing import Dict, Any, Optional, Tuple class QueryPlugin(ABC): @abstractmethod def fetch_data(self, query: str, params: Optional[Dict[str, Any]] = None) -> Tuple[Any, Optional[str]]: """ Fetches data based on the provided query. :param query: The query. :param params: Optional query parameters. :return: A tuple containing the fetched data and an optional error message. """ pass @abstractmethod def fetch_schema_details(self) -> Tuple[list, list]: """ Fetches schema details from Airtable. :return: A tuple containing schema DDL as a list of strings and table metadata. """ pass @abstractmethod def create_ddl_from_metadata(self, table_metadata: list) -> list: """ Creates DDL from table metadata. :param table_metadata: List of table metadata dictionaries. :return: List of schema DDL strings. """ pass @abstractmethod def validate(self, formatted_sql: str) -> None: """ Validates the provided SQL. :param formatted_sql: SQL string to validate. """ pass ================================================ FILE: app/base/remote_data_plugin.py ================================================ from abc import ABC, abstractmethod from typing import Dict, Any, Optional class RemoteDataPlugin(ABC): @abstractmethod def fetch_data(self, params: Optional[Dict[str, Any]] = None) -> list: """ Fetches data based on the provided parameters. :param params: Optional query parameters. :return: a list of strings """ pass ================================================ FILE: app/chain/chains/capability_chain.py ================================================ from app.chain.modules.input_formatter import InputFormatter from app.chain.modules.post_processor import PostProcessor from app.chain.modules.follow_up_handler import FollowupHandler from app.chain.modules.context_retreiver import ContextRetreiver from app.chain.modules.followup_interpreter import FollowupInterpreter from loguru import logger class CapabilityChain: """ CapabilityChain class represents the processing chain for handling capability-related requests. This class orchestrates various modules to process user input, handle follow-ups, interpret follow-up requests, and manage context across interactions. Attributes: common_context (dict): A shared context dictionary used across modules. input_formatter (InputFormatter): Module for formatting user input. context_retriver (ContextRetreiver): Module for retrieving context. followup_handler (FollowupHandler): Module for handling follow-up requests. followup_interpreter (FollowupInterpreter): Module for interpreting follow-up requests. post_processor (PostProcessor): Module for post-processing responses. handler: The first module in the processing chain. The CapabilityChain class follows a modular design, where each module is responsible for a specific part of the processing pipeline. This allows for flexibility and easy extension of functionality. """ def __init__(self, model_configs, context_storage, general_chain): logger.info("loading modules into capability chain") self.common_context = {} self.input_formatter = InputFormatter() self.context_retriver = ContextRetreiver(self.common_context, context_storage) self.followup_handler = FollowupHandler(self.common_context, model_configs) self.followup_interpreter = FollowupInterpreter(self.common_context, general_chain) self.post_processor = PostProcessor() logger.info("initializing chain") self.input_formatter.set_next(self.context_retriver).set_next(self.followup_handler).set_next(self.followup_interpreter).set_next(self.post_processor) self.handler = self.input_formatter def invoke(self, user_request): logger.info("Processing user request") return self.handler.handle(user_request) ================================================ FILE: app/chain/chains/general_chain.py ================================================ from app.chain.modules.input_formatter import InputFormatter # from app.chain.modules.guard_rail import GuardRail from app.chain.modules.prompt_generator import PromptGenerator from app.chain.modules.general_answer_generator import GeneralAnswerGenerator from app.chain.modules.ouput_formatter import OutputFormatter from app.chain.modules.post_processor import PostProcessor from app.chain.modules.context_retreiver import ContextRetreiver from loguru import logger class GeneralChain: """ Chain class represents the main processing chain for handling user requests. This class orchestrates various modules to process user input, retrieve context, generate prompts, execute actions, and format output. Attributes: vector_store: A storage system for vector embeddings. data_sources: A list of data sources to be used in processing. context_store: A storage system for maintaining context across interactions. common_context (dict): A shared context dictionary used across modules. configs (dict): Configuration settings for the models. input_formatter (InputFormatter): Module for formatting user input. rag_module (RagModule): Module for Retrieval-Augmented Generation. prompt_generator (PromptGenerator): Module for generating prompts. generator (Generator): Module for generating responses. validator (Validator): Module for validating responses. context_retriver (ContextRetreiver): Module for retrieving context. context_storage (ContextStorage): Module for storing context. executer (Executer): Module for executing actions. cache_checker (Cachechecker): Module for checking and managing cache. output_formatter (OutputFormatter): Module for formatting output. The Chain class follows a modular design, where each module is responsible for a specific part of the processing pipeline. This allows for flexibility and easy extension of functionality. """ def __init__(self, model_configs, store, datasource, context_store): logger.info("loading modules into chain") self.vector_store = store self.data_sources = datasource if datasource is not None else [] self.context_store = context_store self.common_context = { "chain_retries" : 0, "rag": { "context": [], "schema" : [], }, } self.configs = model_configs self.input_formatter = InputFormatter() self.prompt_generator = PromptGenerator(self.common_context, model_configs, self.data_sources) self.generator = GeneralAnswerGenerator(self.common_context, model_configs) self.context_retriver = ContextRetreiver(self.common_context, context_store) self.output_formatter = OutputFormatter(self.common_context,self.data_sources) self.post_processor = PostProcessor() logger.info("initializing chain") self.input_formatter.set_next(self.context_retriver) \ .set_next(self.prompt_generator).set_next(self.generator).set_next(self.output_formatter).set_next(self.post_processor) self.handler = self.input_formatter def invoke(self, user_request): self.common_context["chain_retries"] = 0 self.common_context["intent"] = user_request["intent_extractor"]["intent"] self.common_context["context_id"] = user_request["context_id"] self.common_context["rag"].update({ "context": [], "schema" : [], }) return self.handler.handle(user_request) ================================================ FILE: app/chain/chains/intent_chain.py ================================================ from app.chain.modules.document_retriever import DocumentRetriever from app.chain.modules.input_formatter import InputFormatter from app.chain.modules.intent_extracter import IntentExtracter from app.chain.modules.router import Router from app.chain.modules.post_processor import PostProcessor from app.chain.formatter.general_response import Formatter from app.chain.modules.context_retreiver import ContextRetreiver from loguru import logger class IntentChain: """ IntentChain class represents the main processing chain for handling user intents. This class orchestrates various modules to process user input, extract intents, route requests, and manage context across interactions. Attributes: vector_store: A storage system for vector embeddings. data_source: A data source to be used in processing. context_store: A storage system for maintaining context across interactions. common_context (dict): A shared context dictionary used across modules. configs (dict): Configuration settings for the models. input_formatter (InputFormatter): Module for formatting user input. context_retriver (ContextRetreiver): Module for retrieving context. intent_extractor (IntentExtracter): Module for extracting intents from user input. post_processor (PostProcessor): Module for post-processing responses. router (Router): Module for routing requests to appropriate chains. handler: The first module in the processing chain. The IntentChain class follows a modular design, where each module is responsible for a specific part of the processing pipeline. This allows for flexibility and easy extension of functionality. """ def __init__(self, model_configs, store, datasource, context_store, intent_chain, general_chain, capability_chain, metadata_chain): logger.info("loading modules into chain") self.vector_store = store self.context_store = context_store self.data_sources = datasource if datasource is not None else {} self.common_context = { "chain_retries" : 0, } self.configs = model_configs self.input_formatter = InputFormatter() self.context_retriver = ContextRetreiver(self.common_context, context_store) self.intent_extractor = IntentExtracter(self.common_context, model_configs, self.data_sources) self.document_retriever = DocumentRetriever(self.vector_store, self.data_sources) self.post_processor = PostProcessor() self.router = Router(self.common_context, self.post_processor, intent_chain, general_chain, capability_chain, metadata_chain) self.input_formatter.set_next(self.context_retriver).set_next(self.document_retriever).set_next(self.intent_extractor).set_next(self.router).set_next(self.post_processor) self.handler = self.input_formatter def invoke(self, user_request): try: self.common_context["chain_retries"] = 0 self.common_context["context_id"] = user_request["context_id"] return self.handler.handle(user_request) except Exception as error: logger.error(f"An error occurred: {error}") return Formatter.format("Oops! Something went wrong. Try Again!",error) ================================================ FILE: app/chain/chains/metadata_chain.py ================================================ from app.chain.modules.input_formatter import InputFormatter from app.chain.modules.post_processor import PostProcessor from app.chain.modules.metadata_generator import MetadataGenerator from app.chain.modules.context_retreiver import ContextRetreiver from app.chain.modules.ouput_formatter import OutputFormatter from app.chain.modules.metadata_ragfilter import MetadataRagFilter from app.chain.modules.document_retriever import DocumentRetriever from loguru import logger class MetadataChain: """ MetadataChain class represents the processing chain for handling metadata-related requests. This class orchestrates various modules to process user input, retrieve context, generate metadata, and format output for metadata-related operations. Attributes: vector_store: A storage system for vector embeddings. data_sources: A list of data sources to be used in processing. context_store: A storage system for maintaining context across interactions. common_context (dict): A shared context dictionary used across modules. input_formatter (InputFormatter): Module for formatting user input. context_retriver (ContextRetreiver): Module for retrieving context. document_retriever (DocumentRetriever): Module for retrieving relevant documents. metadata_generator (MetadataGenerator): Module for generating metadata. post_processor (PostProcessor): Module for post-processing responses. metadata_ragfilter (MetadataRagFilter): Module for filtering metadata using RAG. output_formatter (OutputFormatter): Module for formatting output. handler: The first module in the processing chain. The MetadataChain class follows a modular design, where each module is responsible for a specific part of the processing pipeline. This allows for flexibility and easy extension of functionality in metadata processing and generation. """ def __init__(self, model_configs, store, datasource, context_store): logger.info("loading modules into metadata chain") self.vector_store = store self.data_sources = datasource if datasource is not None else [] self.context_store = context_store self.common_context = { "chain_retries" : 0, } self.input_formatter = InputFormatter() self.context_retriver = ContextRetreiver(self.common_context, context_store) self.document_retriever = DocumentRetriever(self.vector_store, self.data_sources) self.metadata_generator = MetadataGenerator(self.common_context, model_configs, self.data_sources) self.post_processor = PostProcessor() self.metadata_ragfilter = MetadataRagFilter() self.output_formatter = OutputFormatter(self.common_context,self.data_sources) self.input_formatter.set_next(self.context_retriver).set_next(self.metadata_ragfilter).set_next(self.document_retriever).set_next(self.metadata_generator).set_next(self.output_formatter).set_next(self.post_processor) self.handler = self.input_formatter def invoke(self, user_request): self.common_context["chain_retries"] = 0 return self.handler.handle(user_request) ================================================ FILE: app/chain/chains/query_chain.py ================================================ from app.chain.modules.document_retriever import DocumentRetriever from app.chain.modules.input_formatter import InputFormatter # from app.chain.modules.guard_rail import GuardRail from app.chain.modules.prompt_generator import PromptGenerator from app.chain.modules.generator import Generator from app.chain.modules.schema_retriever import SchemaRetriever from app.chain.modules.validator import Validator from app.chain.modules.executer import Executer from app.chain.modules.ouput_formatter import OutputFormatter from app.chain.modules.post_processor import PostProcessor from app.chain.formatter.general_response import Formatter from app.chain.modules.cache_checker import Cachechecker from app.chain.modules.context_retreiver import ContextRetreiver from app.chain.modules.context_storage import ContextStorage from loguru import logger class QueryChain: """ Chain class represents the main processing chain for handling user requests. This class orchestrates various modules to process user input, retrieve context, generate prompts, execute actions, and format output. Attributes: vector_store: A storage system for vector embeddings. data_sources: A list of data sources to be used in processing. context_store: A storage system for maintaining context across interactions. common_context (dict): A shared context dictionary used across modules. configs (dict): Configuration settings for the models. input_formatter (InputFormatter): Module for formatting user input. rag_module (RagModule): Module for Retrieval-Augmented Generation. prompt_generator (PromptGenerator): Module for generating prompts. generator (Generator): Module for generating responses. validator (Validator): Module for validating responses. context_retriver (ContextRetreiver): Module for retrieving context. context_storage (ContextStorage): Module for storing context. executer (Executer): Module for executing actions. cache_checker (Cachechecker): Module for checking and managing cache. output_formatter (OutputFormatter): Module for formatting output. The Chain class follows a modular design, where each module is responsible for a specific part of the processing pipeline. This allows for flexibility and easy extension of functionality. """ def __init__(self, model_configs, store, datasource, context_store): logger.info("loading modules into chain") self.vector_store = store self.data_sources = datasource if datasource is not None else [] self.context_store = context_store self.common_context = { "chain_retries" : 0, "llm": { "input_tokens" : 0, "output_tokens": 0, "total_cost": 0, "latency": 0, "response": { "input_tokens" : 0, "output_tokens": 0, "total_cost": 0, "latency": 0, "logprob_percentage": 0, "name": "default" }, }, "execution_logs": [], "general_response": Formatter, "prompt_mode" : "manual", "inference_raw" : "", "prompt": "", "rag": { "context": [], "schema" : [], }, } self.configs = model_configs self.input_formatter = InputFormatter() self.prompt_generator = PromptGenerator(self.common_context, model_configs, self.data_sources) self.generator = Generator(self.common_context, model_configs) self.validator = Validator(self.common_context,self.data_sources) self.context_retriver = ContextRetreiver(self.common_context, context_store) self.context_storage = ContextStorage(self.common_context, context_store) self.schema_retriever = SchemaRetriever(self.vector_store, self.data_sources) self.executer = Executer(self.common_context,self.data_sources, self.prompt_generator) self.cache_checker = Cachechecker(self.common_context, self.vector_store,self.executer) self.output_formatter = OutputFormatter(self.common_context,self.data_sources) self.post_processor = PostProcessor() logger.info("initializing chain") self.input_formatter.set_next(self.cache_checker) \ .set_next(self.context_retriver) \ .set_next(self.prompt_generator).set_next(self.generator).set_next(self.validator).set_next(self.executer) \ .set_next(self.output_formatter).set_next(self.post_processor) self.handler = self.input_formatter def invoke(self, user_request): self.common_context["chain_retries"] = 0 self.common_context["intent"] = user_request["intent_extractor"]["intent"] self.common_context["context_id"] = user_request["context_id"] self.common_context["llm"].update({ "input_tokens" : 0, "output_tokens": 0, "total_cost": 0, "latency": 0, "response": { "input_tokens" : 0, "output_tokens": 0, "total_cost": 0, "latency": 0, "logprob_percentage": 0, "name": "default" }, }) self.common_context["prompt_mode"] = "manual" self.common_context["rag"].update({ "context": [], "schema" : [], }) return self.handler.handle(user_request) ================================================ FILE: app/chain/formatter/general_response.py ================================================ class Formatter: def format(data: any, error: any) -> (dict): response = {} response["main_entity"] = "none" response["main_format"] = "general_chat" response["role"] = "assistant" response["content"] = data response["summary"] = data response["error"] = error return response ================================================ FILE: app/chain/modules/cache_checker.py ================================================ from typing import Any from loguru import logger from app.base.abstract_handlers import AbstractHandler class Cachechecker(AbstractHandler): """ A handler class for checking and managing cache operations. This class extends AbstractHandler and provides functionality to check if a query exists in the cache and handle the response accordingly. """ def __init__(self,common_context, cachestore, forward_handler, forward: bool = True) -> None: """ Initialize the Cachechecker. Args: common_context: The common context shared across handlers. Cachestore: The cache storage mechanism. forward_handler: The next handler in the chain. forward (bool): Whether to forward the request to the next handler. """ self.cache = cachestore self.forward_handler = forward_handler self.forward = forward self.common_context = common_context async def handle(self, request: Any) -> str: """ Handle the incoming request by checking the cache Args: request (Any): The incoming request to be processed. Returns: str: The response after processing the request. """ logger.info("passing through => cache_checker") response = request question = request.get("question", "") rag_filters = response["rag_filters"]["datasources"] output = await self.cache.find_similar_cache(rag_filters, question) if "rag" not in response: response["rag"] = { "suggestions": output } else: response["rag"]["suggestions"] = output if self.forward and len(output) > 0: if output[0]["distances"] < -10: result = output[0]["metadatas"] logger.info("query retrieved from cache") return await self.forward_handler.handle({"inference":result}) logger.info("query not retrieved from cache") return await super().handle(response) ================================================ FILE: app/chain/modules/cache_updater.py ================================================ from typing import Any from loguru import logger from app.base.abstract_handlers import AbstractHandler class Cacheupdater(AbstractHandler): """ A handler class for updating the cache with new query responses. This class extends AbstractHandler and provides functionality to update the cache with new question-inference pairs when appropriate. """ def __init__(self,cachestore) -> None: """ Initialize the Cacheupdater. Args: Cachestore (Any): The cache storage mechanism. """ self.cache = cachestore async def handle(self, response: Any) -> str: """ Handle the incoming response by updating the cache if necessary. Args: response (Dict[str, Any]): The response to be processed. Returns: str: The response after processing. """ logger.info("passing through => cache_updater") data = response["query_response"] # question would not be in response if retrieved from cache if ("question" in response) and not(data is None or len(data) == 0): logger.info("cache updated") inference = response["inference"] question = response["question"] self.cache.update_cache( document = question, metadata = inference, ) return await super().handle(response) ================================================ FILE: app/chain/modules/context_retreiver.py ================================================ from typing import Any from loguru import logger from app.base.abstract_handlers import AbstractHandler from app.models.llmchat import ChatHistory class ContextRetreiver(AbstractHandler): """ A handler class for retrieving context information for a chat. This class extends AbstractHandler and provides functionality to fetch relevant context based on the context_id provided in the request. """ def __init__(self,common_context, context_store) -> None: """ Initialize the ContextRetriever. Args: common_context (Any): The common context shared across handlers. context_store (Any): The storage mechanism for context data. """ self.context_store = context_store self.common_context = context_store async def handle(self, request: Any) -> str: """ Handle the incoming request by retrieving relevant context. Args: request (Dict[str, Any]): The incoming request to be processed. Returns: str: The response after processing the request. """ logger.info("retrieving context into chain") response = request context = [] if "context_id" in request: records = self.context_store.query_data(model = ChatHistory, filters= {"chat_context_id": request["context_id"]}) context.extend(records) response["context"] = context return await super().handle(response) ================================================ FILE: app/chain/modules/context_storage.py ================================================ from typing import Any from loguru import logger from app.base.abstract_handlers import AbstractHandler from app.models.db import Chat import datetime class ContextStorage(AbstractHandler): """ A handler class for storing chat interactions in the context. This class extends AbstractHandler and provides functionality to store chat interactions, including questions, answers, and summaries, in the context store. """ def __init__(self,common_context, context_store) -> None: """ Initialize the ContextStorage. Args: common_context (Any): The common context shared across handlers. context_store (Any): The storage mechanism for context data. """ self.context_store = context_store self.common_context = context_store async def handle(self, request: Any) -> str: """ Handle the incoming request by storing the interaction in the context. Args: request (Dict[str, Any]): The incoming request to be processed. Returns: str: The response after processing the request. """ logger.info("Storing interaction into context") response = request summary = '' if "summary" in request: summary = request['summary'] if "context_id" in request: self.context_store.insert_data(Chat(context_id = request["context_id"], question = request["question"], created_at = datetime.datetime.now(), answer = request["content"], summary = summary)) return await super().handle(response) ================================================ FILE: app/chain/modules/document_retriever.py ================================================ from app.base.abstract_handlers import AbstractHandler from loguru import logger from typing import Any from app.providers.container import Container import asyncio class DocumentRetriever(AbstractHandler): """ A handler class for retrieving relevant documents based on the input question. This class extends AbstractHandler and provides functionality to find and process similar documents from a vector store based on the input question. """ def __init__(self,store, datasources): """ Initialize the DocumentRetriever. Args: store (Any): The vector store for document retrieval. """ self.store =store self.context_relevance_threshold = 4 self.datasources = datasources async def handle(self, request: Any) -> str: """ Handle the incoming request by retrieving relevant documents. Args: request (Dict[str, Any]): The incoming request to be processed. Returns: str: The response after processing the request. """ logger.info("passing through => document_retriever") response = request tasks = [ self.store.find_similar_documentation(datasource, request['question'], 10) for datasource in self.datasources ] results = await asyncio.gather(*tasks) logger.info("sorting retrieved documents") for index, out in enumerate(results): opt_doc = [] if out and len(out) > 0 and out[0]['distances'] < self.context_relevance_threshold: distances = [doc['distances'] for doc in out] if len(out) > 5: clusters = Container.clustering().kmeans(distances, 2) shortest_cluster = clusters[0] for doc in out: if doc['distances'] in shortest_cluster: opt_doc.append(doc) else: opt_doc = out if "rag" not in response: response["rag"]= {"context" : {}} response["rag"]["context"][list(self.datasources.keys())[index]] = opt_doc return await super().handle(response) ================================================ FILE: app/chain/modules/executer.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger from app.providers.config import configs class Executer(AbstractHandler): """ A handler class for executing queries based on the inference. This class extends AbstractHandler and provides functionality to execute queries using the appropriate datasource and handle any errors that occur. """ def __init__(self, common_context, datasource, fallback_handler) -> None: """ Initialize the Executer. Args: common_context (Dict[str, Any]): The common context shared across handlers. datasource (Dict[str, Any]): A dictionary of datasources keyed by intent. fallback_handler (AbstractHandler): The handler to call in case of errors. """ self.fall_back_handler = fallback_handler self.common_context = common_context self.datasource = datasource async def handle(self, request: Any) -> str: """ Handle the incoming request by executing the query. Args: request (Dict[str, Any]): The incoming request to be processed. Returns: str: The response after processing the request. """ logger.info("passing through => executor") inference = request.get("inference", {}) formated_sql = inference.get("query", "") logger.debug(f"executing query:{formated_sql}") out, err = self.datasource[self.common_context["intent"]].fetch_data(formated_sql) if err is not None: logger.error(f"error in executing query:{err}") if self.common_context["chain_retries"] < configs.retry_limit : logger.info("going back for resolving error") self.common_context["chain_retries"] =self.common_context["chain_retries"] + 1 self.common_context["execution_logs"].append({"query": formated_sql, "error": str(err)}) return await self.fall_back_handler.handle(request) response = {**dict(request), **{ "query_response": out, "query_error": err, }} return await super().handle(response) ================================================ FILE: app/chain/modules/follow_up_handler.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger from app.providers.config import configs from app.loaders.base_loader import BaseLoader from string import Template from app.utils.parser import parse_llm_response from app.chain.formatter.general_response import Formatter class FollowupHandler(AbstractHandler): """ A handler class for processing follow-up queries and extracting required parameters. This class extends AbstractHandler and provides functionality to process follow-up queries, extract intent-specific parameters, and generate appropriate responses. """ def __init__(self, common_context , model_configs) -> None: """ Initialize the FollowupHandler. Args: common_context (Dict[str, Any]): The common context shared across handlers. model_configs (Dict[str, Any]): Configuration for the models used in processing. """ self.model_configs = model_configs self.common_context = common_context async def handle(self, request: Any) -> str: """ Handle the incoming request by processing follow-up queries and extracting parameters. Args: request (Dict[str, Any]): The incoming request to be processed. Returns: str: The response after processing the request. """ response = request logger.info("passing through => Intent extractor") use_case = self.model_configs.get("use_case", {}) capabilities = use_case.get("capabilities", []) intent_extracted = request.get("intent_extractor") intent = intent_extracted.get("intent", "") filtered_capabilities = [capability for capability in capabilities if capability["name"]== intent] capability = filtered_capabilities[0] long_description = use_case["long_description"] capability_description = capability["description"] parameter_description = "" parameters = capability["requirements"] for parameter in parameters: parameter_description= parameter_description + parameter["parameter_name"]+ " : "+ parameter["parameter_description"]+"\n" prompt = """ You are part of a Form automations system where your duty is to: $capability_description You will be given inputs that need to be captured. Your task is to ask and capture this information from the user and get it confirmed. -- Form system context --- $long_description -- Form system context --- Required parameters -- Parameter section --- $parameter_description --- Parameter section --- Instructions: Carefully review all previous messages to establish context. Only extract values that are explicitly provided in previous messages. Do not assume or fill in any values that are not present in previous messages. Do not hallucinate or claim that required values are present when they are not. Generate a JSON response in the following format for the query '$question': { "explanation": "Describe which required values were found in previous messages and how they were extracted. If no values were found, state this clearly.", "params": {},dont extract values for the params which is not mentioned in previous messages "completed": "true|false, if all the required values are captured", "message": "Ask for specific required parameters that have not been provided yet. If all parameters are captured, provide a success message for the booking.", "summary" : "summarise question and answer in one sentence" } """ contexts = request.get("context", []) contexts = contexts[-5:] if len(contexts) >= 5 else contexts prompt = Template(prompt).safe_substitute( question = request["question"], long_description= long_description, capability_description= capability_description, parameter_description=parameter_description ) loader = BaseLoader(model_configs=self.model_configs["models"]) infernce_model = loader.load_model(configs.inference_llm_model) output, response_metadata = infernce_model.do_inference( prompt, contexts ) if output["error"] is not None: return await Formatter.format("Oops! Something went wrong. Try Again!",output['error']) response["inference"] = parse_llm_response(output['content']) response["capability"] = capability return await super().handle(response) ================================================ FILE: app/chain/modules/followup_interpreter.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger from app.chain.formatter.general_response import Formatter class FollowupInterpreter(AbstractHandler): """ A handler class for interpreting follow-up responses and formatting them. This class extends AbstractHandler and provides functionality to interpret the inference results from follow-up queries and format the response accordingly. """ def __init__(self, common_context, general_chain) -> None: """ Initialize the FollowupInterpreter. Args: common_context (Dict[str, Any]): The common context shared across handlers. general_chain (Any): The general processing chain for fallback scenarios. """ self.common_context = common_context self.general_chain = general_chain async def handle(self, request: Any) -> str: """ Handle the incoming request by interpreting the inference results and formatting the response. Args: request (Dict[str, Any]): The incoming request to be processed. Returns: str: The formatted response after processing the request. """ logger.info("passing through => interpreter") response = request if "inference" in request: inference = request["inference"] if inference["completed"] == True or inference["completed"] == "true": logger.info("Intent completed, trigger the action") response = Formatter.format(inference["message"],"") response["summary"] = request["inference"]["summary"] response["question"] = request["question"] response["context_id"] = request["context_id"] else: logger.info("No intents detected") response = Formatter.format("Sorry, I didn't get that","") return await super().handle(response) ================================================ FILE: app/chain/modules/general_answer_generator.py ================================================ from app.base.abstract_handlers import AbstractHandler from app.providers.config import configs from app.loaders.base_loader import BaseLoader from app.utils.parser import markdown_parse_llm_response from app.chain.formatter.general_response import Formatter from loguru import logger class GeneralAnswerGenerator(AbstractHandler): """ A handler class for generating inferences based on prompts and contexts. This class extends AbstractHandler and provides functionality to generate inferences using a specified language model based on given prompts and contexts. """ def __init__(self, common_context, model_configs) -> None: """ Initialize the Generator. Args: common_context (Dict[str, Any]): The common context shared across handlers. model_configs (Dict[str, Any]): Configuration for the models used in processing. """ self.model_configs = model_configs self.common_context = common_context async def handle(self, request: dict) -> str: """ Handle the incoming request by generating an inference based on the prompt and context. This method extracts the prompt and context from the request, uses an inference model to generate a response, and adds the parsed inference to the response. Args: request (Dict[str, Any]): The incoming request to be processed. Returns: str: The response after processing the request, including the generated inference. """ logger.info("passing through => generator") response = request prompt = response["prompt"] contexts = request.get("context",[]) contexts = contexts[-5:] if len(contexts) >= 5 else contexts loader = BaseLoader(model_configs=self.model_configs["models"]) infernce_model = loader.load_model(configs.inference_llm_model) output, response_metadata = infernce_model.do_inference( prompt, contexts ) if output["error"] is not None: return Formatter.format("Oops! Something went wrong. Try Again!",output['error']) response["inference"] = markdown_parse_llm_response(output['content']) if not response["inference"]: return Formatter.format("Oops! Something went wrong. Try Again!","") return await super().handle(response) ================================================ FILE: app/chain/modules/generator.py ================================================ from app.base.abstract_handlers import AbstractHandler from app.providers.config import configs from app.loaders.base_loader import BaseLoader from app.utils.parser import parse_llm_response from app.chain.formatter.general_response import Formatter from loguru import logger class Generator(AbstractHandler): """ A handler class for generating inferences based on prompts and contexts. This class extends AbstractHandler and provides functionality to generate inferences using a specified language model based on given prompts and contexts. """ def __init__(self, common_context, model_configs) -> None: """ Initialize the Generator. Args: common_context (Dict[str, Any]): The common context shared across handlers. model_configs (Dict[str, Any]): Configuration for the models used in processing. """ self.model_configs = model_configs self.common_context = common_context async def handle(self, request: dict) -> str: """ Handle the incoming request by generating an inference based on the prompt and context. This method extracts the prompt and context from the request, uses an inference model to generate a response, and adds the parsed inference to the response. Args: request (Dict[str, Any]): The incoming request to be processed. Returns: str: The response after processing the request, including the generated inference. """ logger.info("passing through => generator") response = request prompt = response["prompt"] loader = BaseLoader(model_configs=self.model_configs["models"]) infernce_model = loader.load_model(configs.inference_llm_model) output, response_metadata = infernce_model.do_inference( prompt, [] ) if output["error"] is not None: return Formatter.format("Oops! Something went wrong. Try Again!",output['error']) response["inference"] = parse_llm_response(output['content']) if not response["inference"]: return Formatter.format("Oops! Something went wrong. Try Again!","") return await super().handle(response) ================================================ FILE: app/chain/modules/input_formatter.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger class InputFormatter(AbstractHandler): async def handle(self, request: Any) -> str: logger.info("passing through => input_formatter") response = request return await super().handle(response) ================================================ FILE: app/chain/modules/intent_extracter.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger from app.providers.config import configs from app.loaders.base_loader import BaseLoader from string import Template from app.chain.formatter.general_response import Formatter from app.utils.parser import parse_llm_response class IntentExtracter(AbstractHandler): """ A handler for extracting user intents from chat queries based on a provided use case configuration. This class processes chat requests to determine the intent behind user queries using a language model. It generates a prompt with the chat context, available intents, and instructions to guide the model in intent extraction. Attributes: common_context (Any): Shared context information used across handlers. model_configs (dict): Configuration settings for the model, including use case details and model paths. """ def __init__(self, common_context , model_configs, datasources) -> None: """ Initializes the IntentExtractor with common context and model configurations. Args: common_context (Any): Shared context information used across handlers. model_configs (dict): Configuration settings for the model. """ self.model_configs = model_configs self.common_context = common_context self.datasources = datasources async def handle(self, request: Any) -> str: """ Processes the request to extract the intent from the user's query. Args: request (Any): The incoming request containing the user query and context. Returns: str: The result of the superclass's handle method with updated response information. """ response = request logger.info("passing through => Intent extractor") use_case = self.model_configs.get("use_case", {}) long_description = use_case.get("long_description", "") short_description = use_case.get("short_description", "") capabilities = use_case.get("capabilities", []) rag = request.get("rag", {}) context = rag.get("context", {}) capability_description = "" capability_names = ["out_of_context"] for capability in capabilities: name = capability["name"] description = capability["description"] capability_names.append(name) capability_description += f"{name} : {description}\n" datasources = self.model_configs.get("datasources", []) datasource_names = [] for datasource in datasources: if datasource["name"] in self.datasources: if self.datasources[datasource["name"]].__category__ in [2,5] and "metadata_inquiry" not in capability_names: capability_names.append("metadata_inquiry") name = datasource["name"] description = datasource["description"] capability_names.append(name) datasource_names.append(name) capability_description += f"\n{name} : {description}\n" datasource_context = context[name] for index,cont in enumerate(datasource_context[:2]): if index == 0: capability_description += f"{cont.get('document','')}\n" else: capability_description += f"{cont.get('document','')}\n" response["available_datasources"] = datasource_names if "metadata_inquiry" in capability_names: capability_description += "\n\nmetadata_inquiry : queries about overview of available data, the structure of a database (including tables and columns), the meaning behind specific columns, and the purpose within a database context, eg: what kind of data you have? or list questions which can be asked?\n" chat_contexts = request.get("context", []) previous_intent = chat_contexts[-1].chat_answer.get("intent","") if len(chat_contexts) > 0 else "None" prompt = """ You are part of a chatbot system where you have to extract intent from users chats and match it with given intents. -- chatbot context --- $long_description Also provide data structure information and overview of available data. -- chatbot context --- Available intents are: -- Intent section --- $capabilities out_of_context: If chat is irrelevant to chatbot context and its capabilities --- Intent section --- Previous last message Intent : $previous_intent Instructions: 1.Only one intent must be identified.Multiple intents are prohibited. 2.Pay special attention to whether the previous intent has been completed. 3.Strictly only if the current user query doesn't clearly match an intent, consider the previous messages to identify the most appropriate intent. 4.When asked to list possible questions, provide general examples without mentioning "specific" word Generate a response for the user query '$question' in the following JSON format: { "explanation": "Explain how you finalized the intent based on user context and instructions. Include your reasoning for determining whether the previous intent was completed or if the current query relates to a new intent.", "intent": "Detected intent, strictly one from the $capability_list" } """ capability_list = "|".join(capability_names) prompt = Template(prompt).safe_substitute( question = request["question"], long_description = long_description, short_description =short_description, capability_list = capability_list, capabilities= capability_description, previous_intent = previous_intent ) logger.debug(f"intent prompt:{prompt}") loader = BaseLoader(model_configs=self.model_configs["models"]) infernce_model = loader.load_model(configs.inference_llm_model) output, response_metadata = infernce_model.do_inference( prompt, chat_contexts ) if output["error"] is not None: return Formatter.format("Oops! Something went wrong. Try Again!",output['error']) response["available_intents"] = capability_names response["intent_extractor"] = parse_llm_response(output['content']) response["rag_filters"] = { "datasources" : response.get('intent_extractor', {}).get('intent', ''), "document_count" : 5, "schema_count" : 5 } return await super().handle(response) ================================================ FILE: app/chain/modules/metadata_generator.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger from app.providers.config import configs from app.loaders.base_loader import BaseLoader from string import Template from app.utils.parser import markdown_parse_llm_response from app.chain.formatter.general_response import Formatter class MetadataGenerator(AbstractHandler): def __init__(self, common_context , model_configs, datasources) -> None: self.model_configs = model_configs self.common_context = common_context self.datasources = datasources async def handle(self, request: Any) -> str: response = request logger.info("passing through => Metadata description generator") rag = request["rag"] contexts = "" for datasource_name, handler in self.datasources.items(): if handler.__category__ in [2,5]: rag_contexts = rag.get("context", {}).get(datasource_name,"") for index,cont in enumerate(rag_contexts): if index==0: contexts += "\n\n" + "Plugin/Database Name: "+ datasource_name + "\n" + cont["document"] else: contexts += "\n" + cont["document"] prompt = """ You are part of a chatbot system where you need to answer user questions based on the given database schema and context. Please review the following information carefully: A brief description about the schema is given below: -- start db schema context section-- $context -- end db schema context section-- Make sure to follow these: 1. Use the provided schema and context to inform your answer. 2. while listing tables and its columns strictly mention under which plugin name it is. 3. Provide accurate information based on the available data. 4. Keep the answer concise and with minimal explanation 5. If the question cannot be fully answered with the given information, explain what can be answered and what additional information might be needed. 6. Present the answer in a human-readable Markdown format 7. Give only what user wants, don't hallucinate to give long answers Your task is to go through the chat history carefully to understand the user's context and instructions. Then, generate a response to the user query '$question' using the provided schema and metadata information. Format your response in the following JSON structure: { "general_message": "Provide a concise human-readable answer in Markdown format to the user's question using the available information", } """ prompt = Template(prompt).safe_substitute(question = request["question"], context =contexts) response["prompt"] = prompt logger.info(f"prompt:{prompt}") chat_history = [] if "context" in request and len(request["context"]) > 0: chat_history = request["context"] chat_history = chat_history[-7:] if len(chat_history) >= 7 else chat_history loader = BaseLoader(model_configs=self.model_configs["models"]) infernce_model = loader.load_model(configs.inference_llm_model) output, response_metadata = infernce_model.do_inference( prompt, chat_history ) if output["error"] is not None: return Formatter.format("Oops! Something went wrong. Try Again!",output['error']) response["inference"] = markdown_parse_llm_response(output['content']) response["summary"] = "" return await super().handle(response) ================================================ FILE: app/chain/modules/metadata_ragfilter.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger class MetadataRagFilter(AbstractHandler): """ A handler for applying RAG (retrieval-augmented generation) filters based on metadata. This class modifies the request's response to include RAG filters, setting the number of documents and schemas to be considered in retrieval operations. It also includes tracing for monitoring and debugging purposes. Inherits from: AbstractHandler: A base class for handling requests in the application. Methods: handle(request: Any) -> str: Processes the request to apply RAG filters and forwards it to the next handler. """ async def handle(self, request: Any) -> str: """ Applies RAG filters to the request's response and forwards it to the next handler. Args: request (Any): The incoming request containing the necessary information for filtering. Returns: str: The result of the superclass's handle method with updated response information. """ logger.info("passing through => metadata_ragfilter") response = request response["rag_filters"] = { "datasources": response.get("available_datasources", []), "document_count": 50, "schema_count": 10 } return await super().handle(response) ================================================ FILE: app/chain/modules/ouput_formatter.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger class OutputFormatter(AbstractHandler): """ A handler for formatting the output based on the provided inference and query responses. This class processes the response from a query, formats it based on the available data and inference results, and prepares it for further handling. It manages content, context, and additional metadata. Attributes: common_context (dict): Shared context information used across handlers. datasource (dict): A dictionary for data formatting based on the intent. """ def __init__(self,common_context, datasource): """ Initializes the OutputFormatter with common context and datasource. Args: common_context (dict): Shared context information used across handlers. datasource (dict): A dictionary for data formatting based on the intent. """ self.datasource = datasource self.common_context = common_context async def handle(self, request: Any) -> str: """ Formats the response based on the inference and query response. Args: request (Any): The incoming request containing inference results and query response. Returns: str: The result of the superclass's handle method with updated response information. """ logger.info("passing through => output_formatter") input_data = request.get("inference", {}) response = {} if "main_entity" in input_data and "operation_kind" in input_data : intent_key = self.common_context.get("intent") if intent_key in self.datasource: response = self.datasource[intent_key].format(request.get("query_response"), input_data) elif "general_message" in input_data: response["content"] = str(input_data.get('general_message')) if "data" in response and isinstance(response["data"], list) and len(response["data"]) == 0: if "empty_message" in input_data: response["content"] = input_data["empty_message"] else: response["content"] = "I didn't find any data matching the query" response["main_format"] = "general_chat" elif "kind" in response and response["kind"] == "none": response["content"] = input_data.get("empty_message", "I didn't find any relevant data regarding this, please reframe your query") response["main_format"] = "general_chat" response["next_questions"] = input_data.get("next_questions", []) if "context_id" in request: response["context_id"] = request["context_id"] response["question"] = request["question"] response["query"] = input_data.get("query", '') response["intent"] = request.get("intent_extractor", {}).get("intent","") response["summary"] = request.get("summary", '') logger.debug(f"content: {response.get('content')}") return await super().handle(response) ================================================ FILE: app/chain/modules/post_processor.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger class PostProcessor(AbstractHandler): async def handle(self, request: Any) -> str: logger.info("passing through => post_processor") response = request return response ================================================ FILE: app/chain/modules/prompt_generator.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger from string import Template class PromptGenerator(AbstractHandler): """ A handler for generating prompts based on the provided context, model configurations, and data sources. This class creates a formatted prompt for the model by combining various elements such as system prompts, user prompts, and context information. It supports both manual and automatic prompt injection modes. Attributes: common_context (dict): Shared context information used across handlers. model_configs (dict): Configuration settings for the model, including prompt injection settings. datasources (dict): Data sources for generating prompt contexts based on intent. """ def __init__(self, common_context , model_configs, datasources) -> None: """ Initializes the PromptGenerator with common context, model configurations, and data sources. Args: common_context (dict): Shared context information used across handlers. model_configs (dict): Configuration settings for the model. datasources (dict): Data sources for generating prompt contexts based on intent. """ self.model_configs = model_configs self.common_context = common_context self.datasources = datasources async def handle(self, request: Any) -> str: """ Generates a prompt based on the incoming request and provided configurations. Args: request (Any): The incoming request containing data for prompt generation. Returns: str: The result of the superclass's handle method with the generated prompt included in the response. """ logger.info("passing through => prompt_generator") response = request intent = response["intent_extractor"]['intent'] contexts = request.get("context",[]) previous_messages = contexts[-5:] if len(contexts) >= 5 else contexts recal_history = "" for message in previous_messages: recal_history += f"USER: {message.chat_query}\n" answer = message.chat_answer recal_history += f"ASSITANT: {answer.get('query','')}\n\n" # Few shot prompting samples_retrieved = "" rag = request.get("rag", {}) suggestions = rag.get("suggestions", []) for doc in suggestions: samples_retrieved += f"question: {doc.get('document', '')}\n" samples_retrieved += f"query: {doc.get('metadatas', {}).get('query', '')}\n\n" prompt_injection = self.model_configs.get("prompt_injection", {"mode": "auto"}) data_source = self.datasources.get(self.common_context.get("intent", "default")) context = data_source.__prompt__ prompt = context.base_prompt system_prompt = "" if prompt_injection["mode"] == "manual" : system_prompt_context = context.system_prompt system_prompt = system_prompt_context.template.format( **{**system_prompt_context["prompt_variables"]} ) else: auto_context = "\n\n".join(cont["document"] for cont in rag.get("context", {}).get(intent,[])) auto_schema = "\n\n".join(schema["document"] for schema in rag.get("schema", [])) system_prompt_context = context.system_prompt system_prompt = system_prompt_context.template.format( schema=auto_schema, context=auto_context, question=request.get("question", ""), suggestions="", recal_history=recal_history ) user_prompt = "" if self.common_context["chain_retries"] == 0: user_prompt = context.user_prompt.template else: logger.info("regenerating prompt using available context") regeneration_promt_context = context.regeneration_prompt user_prompt = Template(regeneration_promt_context.template).safe_substitute( exception_log =self.common_context["execution_logs"][0]["error"] if len(self.common_context["execution_logs"])>0 else "", query_generated =self.common_context["execution_logs"][0]["query"] if len(self.common_context["execution_logs"])>0 else "" ) final_prompt = prompt.format(user_prompt=user_prompt, system_prompt=system_prompt) final_prompt = Template(final_prompt).safe_substitute( question=request.get("question", ""), suggestions=samples_retrieved, **self.model_configs.get("use_case", {}) ) response["prompt"] = final_prompt logger.debug(f"final_prompt:{final_prompt}") return await super().handle(response) ================================================ FILE: app/chain/modules/router.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger from app.chain.formatter.general_response import Formatter class Router(AbstractHandler): """ A handler that routes requests to appropriate handlers based on the detected intent. The Router class determines the correct handler to process the request based on the intent extracted from the request. It forwards the request to the appropriate handler or returns a fallback response if no suitable handler is found. Attributes: fallback_handler (AbstractHandler): Handler to process requests that do not match any specific intent. general_handler (AbstractHandler): Handler for general intent processing. capability_handler (AbstractHandler): Handler for capability-related intents. metadata_handler (AbstractHandler): Handler for metadata-related intents. """ def __init__(self, common_context, fallback_handler, intent_handler, general_handler, capability_handler, metadata_handler) -> None: """ Initializes the Router with the provided handlers. Args: common_context (dict): Shared context information used across handlers. fallback_handler (AbstractHandler): Handler for fallback responses. general_handler (AbstractHandler): Handler for general intent processing. capability_handler (AbstractHandler): Handler for capability-related intents. metadata_handler (AbstractHandler): Handler for metadata-related intents. """ self.fallback_handler = fallback_handler self.forwared_handler = intent_handler self.general_handler = general_handler self.capability_handler = capability_handler self.metadata_handler = metadata_handler async def handle(self, request: Any) -> str: """ Routes the request to the appropriate handler based on the detected intent. Args: request (Any): The incoming request containing intent information. Returns: str: The result of the handled request. """ logger.info("passing through => Router") response = request intent_extractor = request.get("intent_extractor", {}) intent = intent_extractor.get("intent", "") if intent: if intent in self.forwared_handler.data_sources: datasource = self.forwared_handler.data_sources[intent] if datasource.__category__ == 2 or datasource.__category__ == 5: logger.info("entered database workflow") return await self.forwared_handler.invoke(request) else: logger.info("entered default workflow") return await self.general_handler.invoke(request) elif intent == "metadata_inquiry": return await self.metadata_handler.invoke(request) elif intent in request.get("available_intents", []) and intent != "out_of_context": return await self.capability_handler.invoke(request) else: response = Formatter.format("Sorry, I can't help you with that. Is there anything i can help you with ?","") return await self.fallback_handler.handle(response) else: logger.info("No intents detected") response = Formatter.format("Sorry, I can't help you with that. Is there anything i can help you with ?","") return await self.fallback_handler.handle(response) ================================================ FILE: app/chain/modules/schema_retriever.py ================================================ from app.base.abstract_handlers import AbstractHandler from loguru import logger from typing import Any from app.providers.container import Container class SchemaRetriever(AbstractHandler): """ A handler for retrieving similar schemas based on a given question and context. This class queries the store for schemas similar to the input question and context. It processes the retrieved schemas to potentially cluster them and select the most relevant schemas based on certain criteria. Attributes: store (object): The data store used to find similar schemas. """ def __init__(self,store,datasources): """ Initializes the SchemaRetriever with the provided store. Args: store (object): The data store used for schema retrieval. """ self.store = store self.datasources = datasources async def handle(self, request: Any) -> str: """ Retrieves similar schemas from the store and updates the response with the results. Args: request (Any): The incoming request containing the question, context, and filtering criteria. Returns: Dict[str, Any]: The updated response dictionary with retrieved schemas. """ logger.info("passing through => schema_retriever") response = request schema_count = request.get('rag_filters', {}).get("schema_count", 0) auto_context = "\n\n".join(cont.get("document", "") for cont in request.get("rag", {}).get("context", [])) intent = request.get("intent_extracter",{}).get("intent","") datasource = self.datasources[intent] out = await self.store.find_similar_schema(datasource, request["question"] + "\n" + auto_context, schema_count) if out and len(out) > 0: distances = [doc['distances'] for doc in out] if len(out) > 2: clusters = Container.clustering().kmeans(distances, 2) shortest_cluster = clusters[0] opt_doc = [doc for doc in out if doc.get('distances') in shortest_cluster] else: opt_doc = out response["rag"].update({ "schema": opt_doc, }) else: response["rag"].update({ "schema": [], }) return await super().handle(response) ================================================ FILE: app/chain/modules/validator.py ================================================ from app.base.abstract_handlers import AbstractHandler from typing import Any from loguru import logger from app.chain.formatter.general_response import Formatter class Validator(AbstractHandler): """ A handler for validating queries generated by the system. This class validates the generated SQL queries against the data source and returns an appropriate response if there are validation issues. Attributes: common_context (dict): Shared context information used for formatting responses and accessing intent-specific data. datasource (dict): Data source used to validate the generated SQL queries. """ def __init__(self,common_context,datasource) -> None: """ Initializes the Validator with the provided context and datasource. Args: common_context (dict): Shared context information used for validation and response formatting. datasource (dict): Data source used for query validation. """ super().__init__() self.common_context = common_context self.datasource = datasource async def handle(self, request: Any) -> str: """ Validates the generated SQL query and updates the response if there are validation issues. Args: request (Any): The incoming request containing the generated query and other relevant information. Returns: str: The result of the handled request or an error message if validation fails. """ logger.info("passing through => query_validator") response = request inference = request.get("inference", {}) formated_sql = inference.get("query", "") if formated_sql: intent = self.common_context.get("intent", "") validator = self.datasource.get(intent, None) if validator: result = validator.validate(formated_sql) if result: logger.critical(f"Generated Query Validation Issue: {result}") return Formatter.format(result,"") return await super().handle(response) ================================================ FILE: app/embeddings/cohere/__init__.py ================================================ from collections import OrderedDict from app.models.request import ConnectionArgument __provider_name__ = "cohere" __vectordb_name__ = ["chroma"] __icon__ = '/assets/embeddings/logos/cohere.svg' __connection_args__ = [ { "config": ["api_key"], "models": [ "large" ] } ] __all__ = [ __vectordb_name__, __connection_args__, __provider_name__, __icon__ ] ================================================ FILE: app/embeddings/cohere/handler.py ================================================ import chromadb.utils.embedding_functions as embedding_functions from loguru import logger class CohereEm: def __init__(self,model_name:str = "",api_key:str = ""): logger.info("Initialising embedding providers") self.ef = embedding_functions.CohereEmbeddingFunction(api_key=api_key, model_name= model_name) def load_emb(self): return self.ef def health_check(self) -> None: pass ================================================ FILE: app/embeddings/default/chroma_default.py ================================================ import chromadb.utils.embedding_functions as embedding_functions from loguru import logger class ChromaDefaultEmbedding: def __init__(self): logger.info("Initialising embedding providers") self.ef = embedding_functions.DefaultEmbeddingFunction() def load_emb(self): return self.ef ================================================ FILE: app/embeddings/default/default.py ================================================ from .onnx import DefaultEmbeddingModel from .chroma_default import ChromaDefaultEmbedding from loguru import logger class DefaultEmbedding: def __init__(self, vectordb_key: str = "chroma"): logger.info("Initializing embedding providers") self.vectordb = vectordb_key def load_emb(self): match self.vectordb: case "chroma": return ChromaDefaultEmbedding().load_emb() case "mongodb": return DefaultEmbeddingModel() case _: logger.error(f"Unsupported vectordb_key: {self.key}") return None def health_check(self) -> None: pass ================================================ FILE: app/embeddings/default/onnx.py ================================================ import os import requests import numpy as np from tokenizers import Tokenizer import onnxruntime as ort from typing import List from loguru import logger MODEL_ID = "sentence-transformers/all-MiniLM-L6-v2" TOKENIZER_URL = "https://raw.githubusercontent.com/chroma-core/onnx-embedding/main/onnx/tokenizer.json" MODEL_URL = "https://github.com/chroma-core/onnx-embedding/raw/main/onnx/model.onnx?download=" # Function to download files from a URL and save them locally def download_file(url: str, local_path: str): response = requests.get(url) response.raise_for_status() # Check if the download is successful with open(local_path, 'wb') as f: f.write(response.content) # Ensure that the directory exists def ensure_dir(path): if not os.path.exists(path): os.makedirs(path) # Use PyTorch's default epsilon for division by zero def normalize(v): norm = np.linalg.norm(v, axis=1) norm[norm == 0] = 1e-12 return v / norm[:, np.newaxis] # Sample implementation of the default sentence-transformers model using ONNX class DefaultEmbeddingModel(): def __init__(self): # Define paths to save the tokenizer and model embedding_dir = os.path.join(os.getcwd(), "embeddings", "onnx") ensure_dir(embedding_dir) tokenizer_path = os.path.join(embedding_dir, "tokenizer.json") model_path = os.path.join(embedding_dir, "model.onnx") # Download the tokenizer and model from GitHub if they don't exist locally if not os.path.isfile(tokenizer_path): logger.info("Downloading tokenizer...") download_file(TOKENIZER_URL, tokenizer_path) if not os.path.isfile(model_path): logger.info("Downloading ONNX model...") download_file(MODEL_URL, model_path) # Load the tokenizer self.tokenizer = Tokenizer.from_file(tokenizer_path) self.tokenizer.enable_truncation(max_length=256) self.tokenizer.enable_padding(pad_id=0, pad_token="[PAD]", length=256) # Load the ONNX model self.model = ort.InferenceSession(model_path) def __call__(self, documents: List[str], batch_size: int = 32): all_embeddings = [] for i in range(0, len(documents), batch_size): batch = documents[i:i + batch_size] encoded = [self.tokenizer.encode(d) for d in batch] input_ids = np.array([e.ids for e in encoded]) attention_mask = np.array([e.attention_mask for e in encoded]) onnx_input = { "input_ids": np.array(input_ids, dtype=np.int64), "attention_mask": np.array(attention_mask, dtype=np.int64), "token_type_ids": np.array([np.zeros(len(e), dtype=np.int64) for e in input_ids], dtype=np.int64), } model_output = self.model.run(None, onnx_input) last_hidden_state = model_output[0] # Perform mean pooling with attention weighting input_mask_expanded = np.broadcast_to(np.expand_dims(attention_mask, -1), last_hidden_state.shape) embeddings = np.sum(last_hidden_state * input_mask_expanded, 1) / np.clip(input_mask_expanded.sum(1), a_min=1e-9, a_max=None) embeddings = normalize(embeddings).astype(np.float32) all_embeddings.append(embeddings) return np.concatenate(all_embeddings) ================================================ FILE: app/embeddings/google/__init__.py ================================================ from collections import OrderedDict from app.models.request import ConnectionArgument __provider_name__ = "google" __vectordb_name__ = ["chroma"] __icon__ = '/assets/embeddings/logos/google.svg' __connection_args__ = [ { "config": ["api_key"], "models": [] } ] __all__ = [ __vectordb_name__, __connection_args__, __provider_name__, __icon__ ] ================================================ FILE: app/embeddings/google/handler.py ================================================ import chromadb.utils.embedding_functions as embedding_functions from loguru import logger class GoogleEm: def __init__(self,api_key:str = ""): logger.info("Initialising embedding providers") self.ef = embedding_functions.GoogleGenerativeAiEmbeddingFunction(api_key=api_key) def load_emb(self): return self.ef def health_check(self) -> None: pass ================================================ FILE: app/embeddings/loader.py ================================================ from app.embeddings.google. handler import GoogleEm from app.embeddings.default.default import DefaultEmbedding from app.embeddings.openai.handler import OpenAIEm from app.embeddings.cohere.handler import CohereEm from loguru import logger class EmLoader: def __init__(self, configs): self.config = configs def load_embclass(self): emb_classes = { "google": GoogleEm, "openai": OpenAIEm, "cohere": CohereEm, # "default": DefaultEmbedding, } emb_provider = self.config.get("provider") connection_params = self.config.get("params") emb_class = emb_classes.get(emb_provider) logger.info(f"embedding class: {emb_provider}") if emb_class: return emb_class(**connection_params if connection_params else {}) else: logger.info("No specified embedding providers") return DefaultEmbedding(self.config.get("vectordb")) ================================================ FILE: app/embeddings/openai/__init__.py ================================================ from collections import OrderedDict from app.models.request import ConnectionArgument __provider_name__ = "openai" __vectordb_name__ = ["chroma"] __icon__ = '/assets/embeddings/logos/openai.svg' __connection_args__ = [ { "config": ["api_key"], "models": [ "text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large" ] } ] __all__ = [ __vectordb_name__, __connection_args__, __provider_name__, __icon__ ] ================================================ FILE: app/embeddings/openai/handler.py ================================================ import chromadb.utils.embedding_functions as embedding_functions from loguru import logger class OpenAIEm: def __init__(self,model_name:str = "",api_key:str = ""): logger.info("Initialising embedding providers") self.ef = embedding_functions.OpenAIEmbeddingFunction(api_key=api_key, model_name= model_name) def load_emb(self): return self.ef def health_check(self) -> None: pass ================================================ FILE: app/loaders/ai71/__init__.py ================================================ __unique_name__ = "ai71" __display_name__ = "AI71" __icon__ = "/assets/providers/logos/ai71.png" __all__ = ['__unique_name__', '__display_name__', '__icon__'] ================================================ FILE: app/loaders/ai71/loader.py ================================================ from app.base.model_loader import ModelLoader from app.base.loader_metadata_mixin import LoaderMetadataMixin from app.base.base_llm import BaseLLM from typing import Any import json import requests class Ai71ModelLoader(ModelLoader, LoaderMetadataMixin): model: Any = None model_config : Any = {} def do_inference(self, prompt, previous_messages) -> dict: messages = self.messages_format(prompt, previous_messages) self.model = BaseLLM( url = self.model_config["endpoint"], headers = { "Authorization": "Bearer "+self.model_config["api_key"], }, body = { "temperature" : 0.5, "model": self.model_config["name"], "messages": messages } ) out = self.model._call("") response = self.get_response(out) usage = self.get_response_metadata(prompt, response, out) return response, usage def get_response(self, message) -> dict: if "choices" in message and len(message["choices"]) > 0: choice = message["choices"][0] if "message" in choice: return {"content" : choice["message"]["content"], "error" : None} elif "error" in message: error = message["error"] if "message" in error: return {"content" : "", "error" : error["message"]} elif "detail" in message: return {"content" : "", "error" : message["detail"]} return {"content" : "", "error" : "Empty Response from LLM Provider"} def get_response_metadata(self, prompt, response, out) -> dict: return{ "input_tokens" : 0, "output_tokens" : 0, "logprobs" : [], } def messages_format(self, prompt, previous_messages) -> list: chat_history = [] for prev_message in previous_messages: chat_history.append({"role": "user", "content": prev_message.chat_query}) if prev_message.chat_answer is not None: temp = prev_message.chat_answer temp.pop("data", None) chat_history.append({"role": "assistant", "content": json.dumps(temp)}) messages = [] if len(chat_history) > 0: messages.extend(chat_history) messages.append({"role": "user", "content": prompt}) return messages def get_models(self): """ Retrieve models from the AI71 API and reformat the response. Args: llm_provider: The LLM provider object with API key. Returns: List of reformatted model information or an error message. """ url = "https://api.ai71.ai/v1/models" try: response = requests.get(url) if response.status_code == 200: data = response.json() models = [{"display_name": model["name"], "id": model["id"]} for model in data.get("data", [])] return models, False else: return f"Failed to retrieve AI71 models: {response.status_code} {response.text}", True except requests.RequestException as e: return f"Error occurred: {str(e)}", True ================================================ FILE: app/loaders/base_loader.py ================================================ from app.loaders.ollama.loader import OllamaModelLoader from app.loaders.togethor.loader import TogethorModelLoader from app.loaders.openai.loader import OpenAiModelLoader from app.loaders.ai71.loader import Ai71ModelLoader class BaseLoader: def __init__(self, model_configs): self.model_configs = model_configs def load_model(self, unique_name): for model in self.model_configs: if model['unique_name'] == unique_name: match model['kind']: case "togethor": loader = TogethorModelLoader(model_config=model) case "openai": loader = OpenAiModelLoader(model_config = model) case "ai71": loader = Ai71ModelLoader(model_config = model) case "ollama": loader = OllamaModelLoader(model_config = model) case _ : raise ValueError(f"Model with the inference provider '{model['kind']}' with the unique name '{unique_name}' was not found") return loader raise ValueError(f"Model with unique name '{unique_name}' not found") def load_model_config(self, unique_name): for model in self.model_configs: if model['unique_name'] == unique_name: return model ================================================ FILE: app/loaders/ollama/__init__.py ================================================ __unique_name__ = "ollama" __display_name__ = "Ollama" __icon__ = "/assets/providers/logos/ollama.png" __all__ = ['__unique_name__', '__display_name__', '__icon__'] ================================================ FILE: app/loaders/ollama/loader.py ================================================ from app.base.model_loader import ModelLoader from app.base.base_llm import BaseLLM from typing import Any from loguru import logger from app.base.loader_metadata_mixin import LoaderMetadataMixin import json import requests class OllamaModelLoader(ModelLoader, LoaderMetadataMixin): model: Any = None model_config : Any = {} def do_inference(self, prompt, previous_messages) -> dict: messages = self.messages_format(prompt, previous_messages) self.model = BaseLLM( url = self.model_config["endpoint"], body = { "model": self.model_config["name"], "messages": messages, "stream" : False } ) out = self.model._call("") logger.info(f"response:{out}") response = self.get_response(out) usage = self.get_response_metadata(prompt, response, out) return response, usage def get_response(self, message) -> dict: if "message" in message: message = message["message"] if "content" in message: return {"content" : message["content"], "error" : None} elif "error" in message: error = message["error"] return {"content" : "", "error" : error} return {"content" : "", "error" : "Empty Response from LLM Provider"} def get_response_metadata(self, prompt, response, out) -> dict: response_metadata = {} if "usage" in out: usage = out["usage"] response_metadata.update({ "input_tokens" : usage["prompt_tokens"], "output_tokens" : usage["completion_tokens"], }) else: response_metadata.update({ "input_tokens" : len(prompt), "output_tokens" : len(out), }) if "choices" in out and len(out["choices"]) > 0: choice = out["choices"][0] if "logprobs" in choice and choice["message"]["content"] != '' and choice['logprobs'] is not None: response_metadata.update({ "logprobs" : [logprob['logprob'] for logprob in choice['logprobs']['content']] }) return response_metadata response_metadata.update({ "logprobs" : [] }) return response_metadata def messages_format(self, prompt, previous_messages) -> list: chat_history = [] for prev_message in previous_messages: chat_history.append({"role": "user", "content": prev_message.chat_query}) if prev_message.chat_answer is not None: temp = prev_message.chat_answer temp.pop("data", None) chat_history.append({"role": "assistant", "content": json.dumps(temp)}) messages = [] if len(chat_history) > 0: messages.extend(chat_history) messages.append({"role": "user", "content": prompt}) logger.info(f"messages:{messages}") return messages def get_models(self): """ Retrieve models from the Ollama API. Returns: List of Ollama model names or an error message. """ url = "curl http://localhost:11434/api/tags" try: response = requests.get(url) if response.status_code == 200: data = response.json() models = [{"display_name": model["id"], "id": model["id"]} for model in data.get("data", [])] return models, False else: return f"Failed to retrieve Ollama models: {response.status_code} {response.text}", True except requests.RequestException as e: return f"Error occurred: {str(e)}", True ================================================ FILE: app/loaders/openai/__init__.py ================================================ __unique_name__ = "openai" __display_name__ = "Open AI" __icon__ = "/assets/providers/logos/openai.png" __all__ = ['__unique_name__', '__display_name__', '__icon__'] ================================================ FILE: app/loaders/openai/loader.py ================================================ from app.base.model_loader import ModelLoader from app.base.base_llm import BaseLLM from typing import Any from loguru import logger from app.base.loader_metadata_mixin import LoaderMetadataMixin import json import requests class OpenAiModelLoader(ModelLoader, LoaderMetadataMixin): model: Any = None model_config : Any = {} def do_inference(self, prompt, previous_messages) -> dict: messages = self.messages_format(prompt, previous_messages) self.model = BaseLLM( url = self.model_config["endpoint"], headers = { "Authorization": "Bearer "+self.model_config["api_key"], }, body = { "temperature" : 0.5, "model": self.model_config["name"], "messages": messages, "logprobs": False, } ) out = self.model._call("") response = self.get_response(out) logger.info(f"response: {response}") usage = self.get_response_metadata(prompt, response, out) return response, usage def get_response(self, message) -> dict: if "choices" in message and len(message["choices"]) > 0: choice = message["choices"][0] if "message" in choice: return {"content" : choice["message"]["content"], "error" : None} elif "error" in message: error = message["error"] if "message" in error: return {"content" : "", "error" : error["message"]} return {"content" : "", "error" : "Empty Response from LLM Provider"} def get_response_metadata(self, prompt, response, out) -> dict: response_metadata = {} if "usage" in out: usage = out["usage"] response_metadata.update({ "input_tokens" : usage["prompt_tokens"], "output_tokens" : usage["completion_tokens"], }) else: response_metadata.update({ "input_tokens" : len(prompt), "output_tokens" : len(out), }) if "choices" in out and len(out["choices"]) > 0: choice = out["choices"][0] if "logprobs" in choice and choice["message"]["content"] != '' and choice['logprobs'] is not None: response_metadata.update({ "logprobs" : [logprob['logprob'] for logprob in choice['logprobs']['content']] }) return response_metadata response_metadata.update({ "logprobs" : [] }) return response_metadata def messages_format(self, prompt, previous_messages) -> list: chat_history = [] for prev_message in previous_messages: chat_history.append({"role": "user", "content": prev_message.chat_query}) if prev_message.chat_answer is not None: temp = prev_message.chat_answer temp.pop("data", None) chat_history.append({"role": "assistant", "content": json.dumps(temp)}) messages = [] if len(chat_history) > 0: messages.extend(chat_history) messages.append({"role": "user", "content": prompt}) return messages def get_models(self): """ Retrieve models from the OpenAI API. Returns: List of OpenAI model names or an error message. """ url = "https://api.openai.com/v1/models" headers = { "Authorization": f"Bearer {self.model_config.get('api_key', '')}", } try: response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() models = [{"display_name": model["id"], "id": model["id"]} for model in data.get("data", [])] return models, False else: return f"Failed to retrieve OpenAI models: {response.status_code} {response.text}", True except requests.RequestException as e: return f"Error occurred: {str(e)}", True ================================================ FILE: app/loaders/togethor/__init__.py ================================================ __unique_name__ = "togethor" __display_name__ = "Togethor AI" __icon__ = "/assets/providers/logos/togetherai.png" __all__ = ['__unique_name__', '__display_name__', '__icon__'] ================================================ FILE: app/loaders/togethor/loader.py ================================================ from app.base.model_loader import ModelLoader from app.base.base_llm import BaseLLM from typing import Any from loguru import logger from app.base.loader_metadata_mixin import LoaderMetadataMixin import json import requests class TogethorModelLoader(ModelLoader, LoaderMetadataMixin): model: Any = None model_config : Any = {} def do_inference(self, prompt, previous_messages) -> dict: messages = self.messages_format(prompt, previous_messages) self.model = BaseLLM( url = self.model_config["endpoint"], headers = { "Authorization": "Bearer "+self.model_config["api_key"], }, body = { "temperature" : 0.5, "model": self.model_config["name"], "messages": messages, "logprobs": 1, } ) out = self.model._call("") logger.debug(out) response = self.get_response(out) respone_metadata = self.get_response_metadata(prompt, response, out) return response, respone_metadata def get_response(self, message) -> dict: if "choices" in message and len(message["choices"]) > 0: choice = message["choices"][0] if "message" in choice: return {"content" : choice["message"]["content"], "error" : None} elif "error" in message: error = message["error"] if "message" in error: return {"content" : "", "error" : error["message"]} return {"content" : "", "error" : "Empty Response from LLM Provider"} def get_response_metadata(self, prompt, response, out) -> dict: response_metadata = {} if "usage" in out: usage = out["usage"] response_metadata.update({ "input_tokens" : usage["prompt_tokens"], "output_tokens" : usage["completion_tokens"], }) else: response_metadata.update({ "input_tokens" : len(prompt), "output_tokens" : len(out), }) if "choices" in out and len(out["choices"]) > 0: choice = out["choices"][0] if "message" in choice: if "logprobs" in choice and choice["message"]["content"] != '': response_metadata.update({ "logprobs" : choice['logprobs']['token_logprobs'] }) return response_metadata response_metadata.update({ "logprobs" : [] }) return response_metadata def messages_format(self, prompt, previous_messages) -> list: chat_history = [] for prev_message in previous_messages: chat_history.append({"role": "user", "content": prev_message.chat_query}) if prev_message.chat_answer is not None: temp = prev_message.chat_answer temp.pop("data", None) chat_history.append({"role": "assistant", "content": json.dumps(temp)}) messages = [] if len(chat_history) > 0: messages.extend(chat_history) messages.append({"role": "user", "content": prompt}) logger.info(f"messages:{messages}") return messages def get_models(self): """ Retrieve models from the TogetherAI API. Returns: List of TogetherAI model names or an error message. """ url = "https://api.together.xyz/v1/models" headers = { "Authorization": f"Bearer {self.model_config.get('api_key', '')}", } try: response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() models = [{"display_name": model["display_name"], "id": model["id"]} for model in data] return models, False else: return f"Failed to retrieve TogetherAI models: {response.status_code} {response.text}", True except requests.RequestException as e: return f"Error occurred: {str(e)}", True ================================================ FILE: app/main.py ================================================ from fastapi import FastAPI from app.providers.container import Container from app.api.v1.main_router import MainRouter from app.api.v1.connector import router as ConnectorRouter from app.api.v1.llmchat import chat_router from app.api.v1.provider import router as ProviderRouter from app.api.v1.provider import vectordb as vectordb from app.api.v1.connector import cap_router as capabilityrouter from app.api.v1.connector import inference_router as inference_router from app.api.v1.connector import actions as actions from app.api.v1.provider import sample as sample_sql from app.api.v1.auth import login as login import app.repository.connector as repo from fastapi.responses import HTMLResponse # from app.providers.middleware import AuthMiddleware from fastapi.staticfiles import StaticFiles from app.chain.chains.intent_chain import IntentChain from app.chain.chains.capability_chain import CapabilityChain from app.chain.chains.metadata_chain import MetadataChain from app.chain.chains.query_chain import QueryChain from app.chain.chains.general_chain import GeneralChain from app.providers.config import Configs, configs from app.providers.context_storage import ContextStorage from fastapi.middleware.cors import CORSMiddleware from loguru import logger import app.services.connector as svc import app.services.provider as provider_svc from app.utils.database import SessionLocal, Base, engine from fastapi.templating import Jinja2Templates from fastapi import Request from typing import Optional session = SessionLocal() def create_app(config): logger.info("creating application") logger.info("creating container object") container = Container() logger.info("loading necessary configurations") json_config =Configs().model_dump(mode='json') container.config.from_dict(json_config) container.config.from_dict(config) config["models"] = [] logger.level("ONEPANE", no=27, color="") if container.config.logging_enabled(): logger.add("trace.log", level="ONEPANE", colorize=False, backtrace=True, diagnose=True) logger.info("creating database tables") Base.metadata.create_all(bind=engine) logger.info("initializing plugin providers") err = provider_svc.initialize_plugin_providers(session) if err is not None: logger.critical(err) logger.info("initializing vector store") err = provider_svc.initialize_vectordb_provider(session) if err is not None: logger.critical(err) logger.info("initializing Vector Embeddings") err = provider_svc.initialize_embeddings(session) if err is not None: logger.critical(err) logger.info("setting all configuration status to 1") repo.default_configuration_status(session) logger.info("creating local context storage") context_storage = ContextStorage(session) logger.info("creating llm fast_api server") app = FastAPI() app.mount("/assets",StaticFiles(directory="./assets"), name="assets") app.mount("/ui/assets",StaticFiles(directory="./ui/dist/assets", html=True), name="ui", ) app.mount("/ui/dist-library", StaticFiles(directory="./ui/dist-library", html=True), name="embedbot") templates = Jinja2Templates(directory="./ui/dist") @app.get("/ui", response_class=HTMLResponse) @app.get("/ui/{full_path:path}", response_class=HTMLResponse) def serve_home(request: Request, full_path: Optional[str]=""): if request: return templates.TemplateResponse("index.html", context= {"request": request}) else: return templates.TemplateResponse("index.html") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["OPTIONS", "GET", "POST", "DELETE"], allow_headers=["*"], ) logger.info("setting chain, vector store into app context") app.config = config app.container = container app.context_storage = context_storage app.include_router(MainRouter,prefix="/api/v1/query") app.include_router(ConnectorRouter, prefix="/api/v1/connector") app.include_router(chat_router, prefix="/api/v1/chat") app.include_router(ProviderRouter, prefix="/api/v1/provider") app.include_router(capabilityrouter, prefix="/api/v1/capability") app.include_router(inference_router, prefix="/api/v1/inference") app.include_router(actions, prefix="/api/v1/actions") app.include_router(sample_sql, prefix="/api/v1/sql") app.include_router(login, prefix="/api/v1/auth") app.include_router(vectordb, prefix="/api/v1/vectordb") curr_schema = app.openapi() curr_schema["info"]["title"] = "Rag genie Chat API" curr_schema["info"]["description"] = "API for raggenie cloud chatbot" return app ================================================ FILE: app/models/connector.py ================================================ from sqlalchemy import Column, String, Integer, ForeignKey, DateTime, Boolean, JSON, Text from sqlalchemy.sql import func from sqlalchemy.orm import relationship from app.utils.database import Base class Connector(Base): __tablename__ = 'connectors' id = Column(Integer, primary_key=True, index=True) connector_type = Column(Integer, ForeignKey('providers.id'), nullable=False) connector_name = Column(String, nullable=False, index=True) connector_description = Column(String, nullable=True, index=True) connector_config = Column(JSON, nullable=False) schema_config = Column(JSON, nullable=True) connector_docs = Column(Text, nullable=True) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) environment_id = Column(Integer, ForeignKey("environments.id"), nullable=False) environment = relationship("Environment", back_populates="connectors") provider = relationship('Provider', back_populates='connectors') actions = relationship('Actions', back_populates='connectors', cascade="all, delete-orphan") sample_sql = relationship('SampleSQL', back_populates='connectors', cascade="all, delete-orphan") configurations = relationship('ConfigurationConnectorMapping', back_populates='connector', cascade="all, delete") class Configuration(Base): __tablename__ = 'configurations' id = Column(Integer, primary_key=True, index=True) name= Column(String, nullable=False) short_description = Column(String, nullable=False, index=True) long_description = Column(String, nullable=True, index=True) enable = Column(Boolean, default=True) status = Column(Integer, default=0, index=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) environment_id = Column(Integer, ForeignKey("environments.id"), nullable=False) environment = relationship("Environment", back_populates="configurations") capabilities = relationship('Capabilities', back_populates='configuration', cascade="all,delete") inference_mapping = relationship('Inferenceconfigmapping', back_populates='configuration', cascade="all,delete") vectordb_config_mapping = relationship('VectorDBConfigMapping', back_populates='configuration', cascade="all,delete") chat_histories = relationship("ChatHistory", back_populates="configuration", cascade="all,delete") connectors = relationship('ConfigurationConnectorMapping', back_populates='configuration', cascade="all, delete",lazy="joined") class ConfigurationConnectorMapping(Base): __tablename__ = 'configuration_connector_mapping' id = Column(Integer, primary_key=True, index=True) configuration_id = Column(Integer, ForeignKey('configurations.id'),nullable=False) connector_id = Column(Integer, ForeignKey('connectors.id'),nullable=False) configuration = relationship('Configuration', back_populates='connectors') connector = relationship('Connector', back_populates='configurations') class Capabilities(Base): __tablename__ = 'capabilities' id = Column(Integer, primary_key=True, index=True) name = Column(String, nullable=False) description=Column(String, nullable=False) requirements=Column(JSON, nullable=False) config_id = Column(Integer, ForeignKey('configurations.id')) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) configuration = relationship('Configuration', back_populates='capabilities') cap_actions_mapping = relationship('CapActionsMapping', back_populates='capabilities') class Inference(Base): __tablename__ = 'inference' id = Column(Integer, primary_key=True, index=True) name = Column(String, nullable=False) llm_provider = Column(String, nullable=False) model = Column(String, nullable=False) endpoint= Column(String, nullable=False) apikey=Column(String, nullable=False) enable= Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) inference_mapping = relationship('Inferenceconfigmapping', back_populates='inference') class Inferenceconfigmapping(Base): __tablename__ ='inferenceconfigmapping' id = Column(Integer, primary_key=True, index=True) inference_id = Column(Integer, ForeignKey('inference.id')) config_id = Column(Integer, ForeignKey('configurations.id')) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) inference = relationship('Inference', back_populates='inference_mapping') configuration = relationship('Configuration', back_populates='inference_mapping') class Actions(Base): __tablename__ = 'actions' id = Column(Integer, primary_key=True, index=True) name = Column(String, nullable=False) description = Column(String, nullable=True) types = Column(String, nullable=False) body = Column(JSON, nullable=False) table = Column(String, nullable=True) enable = Column(Boolean, default=True) condition = Column(JSON, default=None) connector_id = Column(Integer, ForeignKey("connectors.id")) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) connectors = relationship('Connector', back_populates='actions') cap_actions_mapping = relationship('CapActionsMapping', back_populates='actions') class CapActionsMapping(Base): __tablename__ = 'cap_actions_mapping' id = Column(Integer, primary_key=True, index=True) capability_id = Column(Integer, ForeignKey('capabilities.id')) action_id = Column(Integer, ForeignKey('actions.id')) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) capabilities = relationship('Capabilities', back_populates='cap_actions_mapping') actions = relationship('Actions', back_populates= 'cap_actions_mapping') ================================================ FILE: app/models/db.py ================================================ from sqlalchemy import Column, Integer, String, DATETIME from sqlalchemy.orm import declarative_base Base = declarative_base() class Chat(Base): __tablename__ = 'chat' id = Column(Integer, primary_key=True, autoincrement=True) context_id = Column(String, nullable=False) question = Column(String, nullable=False) answer = Column(String, nullable=True) summary = Column(String, nullable=True) created_at = Column(DATETIME, nullable=False) ================================================ FILE: app/models/environment.py ================================================ from sqlalchemy import Column, Integer, String, ForeignKey, Boolean from app.utils.database import Base from sqlalchemy.orm import relationship class Environment(Base): __tablename__ = "environments" id = Column(Integer, primary_key=True) name = Column(String, nullable=False) configurations = relationship("Configuration", back_populates="environment") connectors = relationship("Connector", back_populates="environment") sample_sql = relationship("SampleSQL", back_populates="environment") chat_histories = relationship("ChatHistory", back_populates="environment") class UserEnvironmentMapping(Base): __tablename__ = "user_environment_mapping" id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey('users.id'), nullable=False) environment_id = Column(Integer, ForeignKey('environments.id'), nullable=False) is_active = Column(Boolean, default=False, nullable=False) ================================================ FILE: app/models/llmchat.py ================================================ from sqlalchemy import Column, String, Integer, DateTime, Boolean, JSON, ForeignKey from sqlalchemy.sql import func from sqlalchemy.orm import relationship from app.utils.database import Base class ChatHistory(Base): __tablename__ = 'chat_histories' chat_id = Column(Integer, primary_key=True, index=True, autoincrement=True) chat_context_id = Column(String, index=True, nullable=False) chat_query = Column(String, nullable=False) chat_answer = Column(JSON, nullable=False) chat_summary = Column(String, nullable=False) chat_status = Column(Integer, nullable=True) feedback_status = Column(Integer, nullable=True) feedback_json = Column(JSON, nullable=True) user_id = Column(Integer, nullable=True) primary_chat = Column(Boolean) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) configuration_id = Column(Integer, ForeignKey("configurations.id"), nullable=False) environment_id = Column(Integer, ForeignKey("environments.id"), nullable=False) configuration = relationship("Configuration", back_populates="chat_histories") environment = relationship("Environment", back_populates="chat_histories") ================================================ FILE: app/models/prompt.py ================================================ from pydantic import BaseModel, Field class SystemPrompt(BaseModel): template: str = Field( ..., description="The template used for system-level prompt generation." ) class UserPrompt(BaseModel): template: str = Field( ..., description="The template used for user-level prompt generation." ) class RegenerationPrompt(BaseModel): template: str = Field( ..., description="The template used for regenerating the response prompt." ) class Prompt(BaseModel): base_prompt: str = Field( ..., description="The base prompt structure combining system and user prompts." ) system_prompt: SystemPrompt = Field( ..., description="The system prompt details." ) user_prompt: UserPrompt = Field( ..., description="The user prompt details." ) regeneration_prompt: RegenerationPrompt = Field( ..., description="The regeneration prompt details." ) ================================================ FILE: app/models/provider.py ================================================ from sqlalchemy import Column, String, Integer, DateTime, Boolean, ForeignKey, JSON from sqlalchemy.sql import func from sqlalchemy.orm import relationship from app.utils.database import Base class Category(Base): __tablename__ = 'categories' id = Column(Integer, primary_key=True, index=True) name = Column(String, unique=True, nullable=False, index=True) description = Column(String, nullable=False) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) providers = relationship('Provider', back_populates='category') class Provider(Base): __tablename__ = 'providers' id = Column(Integer, primary_key=True, index=True) name = Column(String, unique=True, nullable=False, index=True) description = Column(String, nullable=False) key = Column(String, unique=True, nullable=False, index=True) icon = Column(String, nullable=False) category_id = Column(Integer, ForeignKey('categories.id'), nullable=False) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) connectors = relationship('Connector', back_populates='provider') category = relationship('Category', back_populates='providers') providerconfig = relationship('ProviderConfig', back_populates='provider') class ProviderConfig(Base): __tablename__ = "providerconfig" id = Column(Integer, primary_key=True, index=True) name = Column(String, unique=True, nullable=False, index=True) description = Column(String, nullable=False) field = Column(String, nullable=False) slug = Column(String, nullable=False) value = Column(JSON, nullable=True) enable = Column(Boolean, default=True) config_type= Column(Integer, nullable=False) order = Column(Integer, nullable=False) required=Column(Boolean, nullable=True, default=True) provider_id = Column(Integer, ForeignKey('providers.id'), nullable=False) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) provider = relationship('Provider', back_populates='providerconfig') class VectorDBConfig(Base): __tablename__ = "vectordbconfig" id = Column(Integer, primary_key=True, index=True) name = Column(String, unique=True, nullable=False, index=True) description = Column(String, nullable=False) key = Column(String, unique=True, nullable=False, index=True) icon = Column(String, nullable=False) config = Column(JSON) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) class SampleSQL(Base): __tablename__ = "sample_sql" id = Column(Integer, primary_key=True, index=True) description = Column(String, nullable=False) sql_metadata = Column(JSON, nullable=True) connector_id = Column(Integer, ForeignKey('connectors.id'), nullable=False) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) environment_id = Column(Integer, ForeignKey("environments.id"), nullable=False) environment = relationship("Environment", back_populates="sample_sql") connectors = relationship('Connector', back_populates='sample_sql') class VectorDB(Base): __tablename__ = "vectordb" id = Column(Integer, primary_key=True, index=True) vectordb = Column(String, nullable=False) vectordb_config = Column(JSON, nullable=False) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) vectordb_config_mapping = relationship('VectorDBConfigMapping', back_populates='vector_db',cascade="all,delete") vector_embedding_mapping = relationship('VectorEmbeddingMapping', back_populates='vector_db', cascade="all,delete") class VectorDBConfigMapping(Base): __tablename__ = "vectordb_config_mapping" id = Column(Integer, primary_key=True, index=True) vector_db_id = Column(Integer, ForeignKey('vectordb.id'), nullable=False) config_id = Column(Integer, ForeignKey('configurations.id'), nullable=False) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) vector_db = relationship('VectorDB', back_populates='vectordb_config_mapping') configuration = relationship('Configuration', back_populates='vectordb_config_mapping') class Embeddings(Base): __tablename__ = "embeddings_configs" id = Column(Integer, primary_key=True, index=True) provider = Column(String, nullable=False) config = Column(JSON, nullable=False) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) vector_embedding_mapping = relationship("VectorEmbeddingMapping", back_populates= "embeddings_config") class VectorEmbeddingMapping(Base): __tablename__ = "vector_embedding_mapping" id = Column(Integer, primary_key=True, index=True) vector_db_id = Column(Integer, ForeignKey('vectordb.id'), nullable=False) embedding_id = Column(Integer, ForeignKey('embeddings_configs.id'), nullable=False) enable = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) deleted_at = Column(DateTime(timezone=True), nullable=True) vector_db = relationship('VectorDB', back_populates='vector_embedding_mapping', cascade="all,delete") embeddings_config = relationship('Embeddings', back_populates='vector_embedding_mapping', cascade="all,delete") ================================================ FILE: app/models/request.py ================================================ from pydantic import BaseModel from typing import Dict,List, Literal from typing import Any class Chat(BaseModel): content: str role: str class FlowItem(BaseModel): question: str answer: dict class PostBody(BaseModel): question: str flow: list[FlowItem] class ResponseItem(BaseModel): description: str metadata: Dict[str,str] class FeedbackCorrectionRequest(BaseModel): responses: List[ResponseItem] class ConnectionArgument(BaseModel): type: Literal[1,2,3,4,6,7, 8] generic_name: str description: str order: int required: bool value: Any slug: str ================================================ FILE: app/models/user.py ================================================ from sqlalchemy import Column, Integer, String, Boolean from app.utils.database import Base class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True) username = Column(String, nullable=False) ================================================ FILE: app/plugins/airtable/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'airtable' __display_name__ = 'Airtable' __description__ = 'Airtable integration for handling Airtable database operations.' __icon__ = '/assets/plugins/logos/airtable.svg' __category__ = 2 # Connection arguments __connection_args__ = OrderedDict( token= ConnectionArgument( type = 2, generic_name= 'Airtable token', description = 'Token for airtable workspace', order = 2, required = True, value = None, slug = "api_key" ), workspace_id=ConnectionArgument( type= 1, generic_name= 'Airtable workspace id', description= 'Airtable workspace ID', order = 1, required = True, value = None, slug = "space_name" ) ) # Prompt __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are an Airtable expert.Your job is to answer questions about the Airtable tables specified in schema. You must output the Airtable query that answers the question using the schema provided. Use the schema details and db constraints enclosed in `[schema][/schema]` to generate query [schema] {schema} [/schema] {context} sample queries generated previously question: list all hospitals query: https://api.airtable.com/v0/appXXXXXXX/hospitals question: list all hospitals in x query: executing query:https://api.airtable.com/v0/appXXXXXXX/hospitals?filterByFormula=AND(SEARCH(LOWER('x'),LOWER({{location}}))=1) question: list all hospital supports xyz ab plan query: https://api.airtable.com/v0/appXXXXXXX/hospitals?filterByFormula=AND(SEARCH(LOWER("xyz ab"),LOWER({{insurance_plan}}))=1) Adhere to these rules while generating query: - Deliberately go through the question and database schema word by word to appropriately answer the question - Dont change the field names - Use Lower for comparing or equality """ }, "user_prompt":{ "template": """ User question is "$question" generate a json in the following format without any formatting. { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "complete airtable rest api query without authentication", "operation_kind" : "aggregation|list", "general_message": "general message like 'here is the list of x'", "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "main_entity": "document" } """ }, "regeneration_prompt": { "template": """ User query is "$question" generate a json in the following format without any formatting. extra explanation is strictly prohibited. { "output": "Your answer for the question", "main_entity": "document", "operation_kind": "text" } """ } }) __all__ = [ __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/airtable/formatter.py ================================================ from typing import Any, Dict from loguru import logger class Formatter: """ Formatter class to format the response based on the inference and data. """ def format(self, data: Dict[str, Any], inference: Dict[str, Any]) -> dict: """ Format the response using the given data and inference information. :param data: The data containing records to process. :param inference: Inference details including main entity and operation kind. :return: Formatted response dictionary. """ logger.info("Processing output using inference details") response = {} self.main_entity = inference.get("main_entity", "") self.kind = inference.get("operation_kind", "") self.general_message = inference.get("general_message", "Unable to process question, try again") self.next_questions = inference.get("next_questions", []) # Extract results from data records results = [record["fields"] for record in data.get("records", [])] response["content"] = self.general_message if len(results) == 0: response["content"]= "Sorry, I couldn't find any details regarding this" response["main_entity"] = self.main_entity response["main_format"] = self.kind response["role"] = "assistant" response["data"]= results return response ================================================ FILE: app/plugins/airtable/handler.py ================================================ from .formatter import Formatter from loguru import logger import requests import uuid from urllib.parse import urlsplit, urlunsplit, parse_qs, urlencode from app.base.base_plugin import BasePlugin from app.base.query_plugin import QueryPlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin from typing import Tuple, Optional class Airtable(BasePlugin, QueryPlugin, PluginMetadataMixin, Formatter): """ Airtable class for interacting with Airtable API and fetching table data, schemas, and more. """ def __init__(self, connector_name : str, token:str, workspace:str): super().__init__(__name__) self.connection = { "base_url": "https://api.airtable.com/v0", } self.connector_name = connector_name.replace(' ','_') self.params = { 'token': token, 'base_id': workspace } def connect(self): """ Mocked connection method for Airtable. :return: Tuple containing connection status (True/False) and an error message if any. """ return True, None def healthcheck(self)-> Tuple[bool, Optional[str]]: """ Perform a health check by checking if the Airtable base is accessible. :return: Tuple containing the health status (True/False) and error message (if any). """ logger.info("health check for airtable") url = self.connection["base_url"]+ "/meta/bases/"+ self.params["base_id"]+"/tables" headers = { "Authorization": "Bearer "+self.params["token"] } try: response = requests.get(url, headers=headers) if response.status_code == 200: logger.info("Airtable health check passed.") return True, None else: logger.error(f"Health check failed: {response.status_code} {response.text}") return False, "Failed to connect with airtable" except Exception as e: logger.exception(f"Exception during health check: {str(e)}") return False, str(e) def configure_datasource(self, init_config): """ Configures the Airtable datasource. :param init_config: Initial configuration for the datasource. """ return None def fetch_data(self, query, params=None): """ Fetches data from Airtable based on the provided query. :param query: The Airtable API query. :param params: Optional query parameters. :return: A tuple containing the fetched data and an optional error message. """ logger.info("preparing query") try: parts = query.split("v0") if len(parts) <= 1: return [], "Invalid query format" query = parts[1].lstrip('/') first_part, second_part = query.split('/', 1) final_query = second_part url = self.connection.get("base_url")+"/"+self.params["base_id"]+"/"+final_query headers = { "Authorization": "Bearer "+self.params["token"] } logger.info(f"Generating URL for fetch_data: {url}") url_parts = urlsplit(url) query_params = parse_qs(url_parts.query) query_params.pop('api_key', None) query_params.pop('API_KEY', None) new_query_string = urlencode(query_params, doseq=True) url = urlunsplit((url_parts.scheme, url_parts.netloc, url_parts.path, new_query_string, url_parts.fragment)) logger.info(f"Final request URL: {url}") response = requests.get(url, headers=headers, params=params) if response.status_code == 200: return response.json(), None else: logger.error(f"Failed to fetch data: {response.status_code}, {response.text}") return [], "Failed to fetch" except Exception as e: logger.error(f"Failed to fetch data: {e}") return [], "Failed to fetch" def fetch_schema_details(self): """ Fetches the schema details (tables and columns) from Airtable. :return: A tuple containing the schema DDL as a list of strings and the table metadata. """ schema_ddl = [] table_metadata = [] base_id = self.params.get("base_id") token = self.params.get("token","") base_url = self.connection.get("base_url") url = f"{base_url}/meta/bases/{base_id}/tables" headers = { "Authorization": f"Bearer {token}" } response = requests.get(url, headers=headers) if response.status_code == 200: out = response.json() if "tables" in out and len(out["tables"])>0: tables = out["tables"] for table in tables: schema = { "table_id": str(uuid.uuid4()), "table_name": table["name"], "description": "", "columns": [] } fields= [] for field in table["fields"]: fields.append({ "column_id" : str(uuid.uuid4()), "column_name": field['name'], "column_type": field['type'], "description": "", }) schema["columns"] = fields schema_ddl.append(f"\nTable name: {table['name']}\n" + "\n".join([f['column_name'] for f in fields])) table_metadata.append(schema) return schema_ddl, table_metadata def create_ddl_from_metadata(self,table_metadata): """ Creates DDL from the provided table metadata. :param table_metadata: List of table metadata dictionaries. :return: List of schema DDL strings. """ schema_ddl = [] for table in table_metadata: ddl = f"\nTable name: {table['table_name']}\n" ddl += "\n".join([col.get("column_name","") for col in table["columns"]]) schema_ddl.append(ddl) return schema_ddl def validate(self, formatted_sql: str) -> None: """ Validates the provided SQL. :param formatted_sql: SQL string to validate. """ pass def close_connection(self) -> None: """ Closes the connection to Airtable. """ pass ================================================ FILE: app/plugins/bigquery/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'bigquery' __display_name__ = 'Bigquery' __description__ = 'Bigquery integration for handling Bigquery database operations.' __icon__ = '/assets/plugins/logos/bigquery.svg' __category__ = 2 # Connection arguments __connection_args__ = OrderedDict( project_id= ConnectionArgument( type = 1, generic_name= 'Project id', description = 'Google cloud project id', order= 1, required = True, value = None, slug = "project_id" ), service_account_json=ConnectionArgument( type= 7, generic_name= 'Service account JSON', description= 'Service account details', order= 2, required = True, value = None, slug = "service_account_json" ) ) # Prompt __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are an BigQuery SQL expert.Your job is to answer questions about a bigquery data. You must output the BigQuery SQL that answers the question using the SQL structure provided inside a BigQuery. go through the schema details given below - start db schema section-- {schema} -- end db schema section-- A brief description about the schema is given below: -- start db context section-- {context} -- end db context section-- Sample sql queries with their questions are given below -- start query samples section-- $suggestions -- end query samples section-- Adhere to these rules while generating query: 1.Do not hallucinate and give incorrect answer 2.Do not give incomplete answers """ }, "user_prompt":{ "template": """ generate a json in the following format without any formatting. extra explanation is strictly prohibited. { "explanation": "Explain how you finalized the nerd graphql query using the schemas and rules provided", "query" : "BigQuery SQL query to answer `$question` by strictly following the rules.", "operation_kind" : "aggregation|list", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "x-axis": ["fields that can be used as x axis"], "y-axis": ["field that can be used as y axis"], "title": "layout title name" }, "confidence" : "confidence in 100", "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", } """ }, "regeneration_prompt": { "template": """ You were trying to answer the following user question by writing SPL query to answer the question given in `[question][/question]` [question] $question [/question] You generated this query given in `[query][/query]` [query] {query_generated} [/query] But upon execution you encountered some error , error traceback is given in [query_error][/query_error] [query_error] {exception_log} [/query_error] Answer the given user question by writing an BigQuery SQL query by taking into account your previous errors and rectifying them. generate a json in the following format without any formatting. extra explanation is strictly prohibited. {{ "explanation": "Explain how you are going to finalize the SQL query by taking the previous generation details into account", "query" : "BigQuery SQL query to answer `$question` by strictly following the rules and based on schema and based on the previous query try to rectify the query error", "operation_kind" : "aggregation|list", "visualisation": { "chart": "chart which can be a bar chart, line chart, or pie chart, can be shown for the data only if operation_kind is 'aggregation'; otherwise, None", "x-axis": ["fields that can be used as x axis"], "y-axis": ["field that can be used as y axis"], "title": "layout title name" }, "confidence" : "confidence in 100", "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query" }} """ } }) __all__ = [ __version__, __display_name__, __plugin_name__, __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/bigquery/formatter.py ================================================ from typing import Any from loguru import logger class Formatter: def format(self, data: Any,input) -> (dict): """ Main entry point for formatting the data based on the input parameters. Handles different formatting strategies based on operation kind. :param data: The data to format. :param input_params: Dictionary containing operation and formatting details. :return: A dictionary containing the formatted response. """ response = {} self.main_entity = input.get("main_entity") self.kind = input.get("operation_kind", "").lower() self.general_message = input.get("general_message") self.empty_message = input.get("empty_message") logger.info("Formatting output using inference") if self.kind == "list": response = self.basic_formatter(data, input) elif self.kind == "aggregation": response = self.aggregation_formatter(data, input) else: response["data"] = data response["kind"] = "list" response.update({ "main_entity": self.main_entity, "main_format": self.kind, "role": "assistant", "content": self.general_message, "empty_message": self.empty_message, }) return response def basic_formatter(self, data: Any, input:Any) -> dict : """ Formats data as a list, handling cases for none, single, and multiple entries. :param data: The data to format. :return: A dictionary containing the formatted list response. """ logger.info("Formatting data as a list") if data is None: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "single"} else: response = {"data": data, "kind": "list"} return response def aggregation_formatter(self, data:Any, input:Any) -> dict : """ Formats data for aggregation visualisation, supporting table and chart formats. :param data: The data to format. :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type). :return: A dictionary containing the formatted aggregation response. """ logger.info("Formatting data as aggregation") visualisation = input.get("visualisation", {}) response = {} if data is None or len(data) == 0: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "table"} else: value_fields = visualisation.get("y-axis", []) key_fields = visualisation.get("x-axis", []) title = visualisation.get("title", "") visualisaton_kind = visualisation["type"].replace(" ", "_") if visualisation["type"] is not None else visualisation["type"] if visualisaton_kind.lower() in ["bar_chart", "line_chart", "pie_chart"] and len(value_fields) > 0 and len(key_fields) > 0: response["kind"] = visualisaton_kind response["data"] = data response["x"] = key_fields response["y"] = value_fields response["title"] = title else: response = {"kind": "table", "data": data} return response ================================================ FILE: app/plugins/bigquery/handler.py ================================================ from google.cloud import bigquery from google.oauth2 import service_account from .formatter import Formatter from loguru import logger import re from typing import List import json import uuid from app.base.base_plugin import BasePlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin from app.base.query_plugin import QueryPlugin class Bigquery(Formatter, BasePlugin, QueryPlugin, PluginMetadataMixin): def __init__(self, connector_name : str, project_id: str, service_account_json: str): super().__init__(__name__) self.connector_name = connector_name.replace(' ','_') self.params = { 'project' : project_id, 'credentials' : service_account.Credentials.from_service_account_info(json.loads(service_account_json)), } self.client = None self.schema = [] def connect(self): """ Establish a connection to BigQuery. :return: Tuple containing connection status and an optional error message. """ try: self.client = bigquery.Client(**self.params) logger.info("Connection to Google Bigquery successful.") return True, None except Exception as error: logger.error(f"Error connecting to Google Bigquery: {error}") return False, str(error) def healthcheck(self): """ Perform a health check by executing a simple query. :return: Tuple containing the health check status and an optional error message. """ if self.client is None: logger.warning("Connection to BigQuery is not established.") return False, "Connection to BigQuery is not established." try: datasets = list(self.client.list_datasets()) if datasets: dataset_id = datasets[0].dataset_id query = f"SELECT * FROM {dataset_id}.INFORMATION_SCHEMA.TABLES" query_job = self.client.query(query) results = query_job.result() if results.total_rows > 0: logger.info("Healthcheck successful: BigQuery connection is healthy.") return True, None logger.warning("Healthcheck failed: No results returned.") return False, "Healthcheck failed: No results returned." except Exception as error: logger.error(f"Healthcheck failed: {error}") return False, str(error) def configure_datasource(self, init_config): return None def fetch_data(self,query: str): """ Fetch data by executing a BigQuery SQL query. :param query: SQL query string. :return: Tuple of data rows and an optional error message. """ try: query = self.client.query(query) results = query.result() rows = [row for row in results] return rows, None except Exception as e: logger.critical(e) return None, e def fetch_schema_details(self): """ Fetch schema details for all tables in all datasets. :return: A tuple containing the schema DDLs and table metadata. """ schema_ddl = [] table_metadata = [] if self.client is None: logger.error("BigQuery client is not connected.") return schema_ddl, table_metadata datasets = list(self.client.list_datasets()) if not datasets: logger.critical("Project does not contain any datasets.") return schema_ddl, table_metadata for dataset in datasets: dataset_id = dataset.dataset_id schema_structure_query = f"SELECT * FROM {dataset_id}.INFORMATION_SCHEMA.TABLES" result, error = self.fetch_data(schema_structure_query) if result is not None: for res in result: schema = { "table_id": str(uuid.uuid4()), "table_name": f"{dataset.dataset_id}.{res[2]}", "description": "", "columns": [] } fields= [] ddl = res[11] # Regex to extract column names and data types pattern = r'`([^`]+)`\s(\w+)|(\w+)\s(\w+)' matches = re.findall(pattern, ddl) # Extract column names and data types from the matches columns = [match[0] or match[2] for match in matches] data_types = [match[1] or match[3] for match in matches] for index,(column, datatype) in enumerate(list(zip(columns, data_types))[1:]): fields.append({ "column_id" : str(uuid.uuid4()), "column_name": column, "column_type": datatype, "description": "", }) schema["columns"] = fields table_metadata.append(schema) schema_ddl.append(ddl) else: logger.critical(f"Error fetching schema:{error}") return schema_ddl, table_metadata def create_ddl_from_metadata(self, table_metadata: List[dict]): """ Create DDL statements from table metadata. :param table_metadata: List of table metadata. :return: List of DDL strings. """ schema_ddl = [] for table in table_metadata: tmp = f"CREATE TABLE '{table['table_name']}'" for index,field in enumerate(table["columns"]): if index == 0: tmp = f"{tmp} ({field.get('column_name','')} {field.get('column_type','')}" elif index < len(table['columns'])-1: tmp = f"{tmp},{field.get('column_name','')} {field.get('column_type','')}" else: tmp = f"{tmp},{field.get('column_name','')} {field.get('column_type','')});" schema_ddl.append(tmp) return schema_ddl def validate(self, formatted_query: str) -> None: """ Validate the formatted query (placeholder for actual implementation). :param formatted_query: SQL query string. """ pass ================================================ FILE: app/plugins/csv/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'CSV' __display_name__ = 'CSV Loader' __description__ = 'CSV loader for interacting with CSV data' __icon__ = '/assets/plugins/logos/csv.svg' __category__ = 5 # Connection arguments __connection_args__ = OrderedDict( document_files = ConnectionArgument( type = 8, generic_name= 'csv file', description = 'Supports only .csv file.', order = 1, required = True, value = None, slug = "document_files" ) ) __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are an Sqlite expert. Your job is to answer questions about a Sqlite database using only the provided schema details and rules. go through the schema details given below -- start db schema section-- {schema} -- end db schema section-- A brief description about the schema is given below -- start db context section-- {context} -- end db context section-- Sample sql queries with their questions are given below -- start query samples section-- $suggestions -- end query samples section-- Adhere to the given rules without failure -- start rules section -- - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`. - use LIKE operator with LOWER function for string comparison or equality - Always use alias/table name for fields in WHERE condition - Do not use non existing tables or fields - id columns are mandatory for all operations - Do not use JSON_BUILD_OBJECT operation - Do not use unwanted joins - Do not return incomplete queries - Adher to sqlite query syntax -- end rules section -- """ }, "user_prompt":{ "template": """ Follow these steps to generate query to solve the question `$question` 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Do only the task asked, Don't hallucinate and overdo the task 4. Strictly return all the fields in the schema during listing operations 5. Always enclose column names in double quotes ("") in SQL queries, even for single-word column names or variables, to ensure compatibility and prevent errors like no such column. 6. Strictly return at least 1 text fields and an id field during aggregation/group by operations 7. Generate a query to solve the problem using the schema, context, and strictly follow the rules 8. output in the given json format, extra explanation is strictly prohibited 9. If the table name contains hyphens (-), enclose the table name in double quotes (") { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "sqlite query", "operation_kind" : "aggregation|list", "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "x-axis": ["fields that can be used as x axis"], "y-axis": ["fields that can be used as y axis"], "title": "layout title name" }, "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ }, "regeneration_prompt": { "template": """ You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]` [question] $question [/question] You generated this query given in `[query][/query]` [query] {query_generated} [/query] But upon execution you encountered some error , error traceback is given in [query_error][/query_error] [query_error] {exception_log} [/query_error] Follow these steps to generate the query 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Use survey answers if available and include it in query for filtering values 4. Do only the task asked, Don't hallucinate and overdo the task 5. Strictly return all the fields in the schema during listing operations 6. Strictly return at least 1 text fields and an id field during aggregation/group by operations 7. Generate a query to solve the problem using the schema, context and the rules and based on the previous query try to rectify the query error 8. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "sqlite query", "operation_kind" : "aggregation|list", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "value_field": "fields in which values are stored", "x-axis": "field that can be used as x axis", "y-axis": "field that can be used as y axis", "title": "layout title name" }, "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ } }) __all__ = [ __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/csv/formatter.py ================================================ from typing import Any from loguru import logger class Formatter: def format(self, data: Any,input) -> (dict): """ Main entry point for formatting the data based on the input parameters. Handles different formatting strategies based on operation kind. :param data: The data to format. :param input_params: Dictionary containing operation and formatting details. :return: A dictionary containing the formatted response. """ response = {} self.main_entity = input.get("main_entity") self.kind = input.get("operation_kind", "").lower() self.general_message = input.get("general_message") self.empty_message = input.get("empty_message") logger.info("Formatting output using inference for sqlite") if self.kind == "list": response = self.basic_formatter(data, input) elif self.kind == "aggregation": response = self.aggregation_formatter(data, input) else: response["data"] = data response["kind"] = "list" response.update({ "main_entity": self.main_entity, "main_format": self.kind, "role": "assistant", "content": self.general_message, "empty_message": self.empty_message, }) return response def basic_formatter(self, data: Any, input:Any) -> dict : """ Formats data as a list, handling cases for none, single, and multiple entries. :param data: The data to format. :return: A dictionary containing the formatted list response. """ logger.info("Formatting data as a list") if data is None: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "single"} else: response = {"data": data, "kind": "list"} return response def aggregation_formatter(self, data:Any, input:Any) -> dict : """ Formats data for aggregation visualisation, supporting table and chart formats. :param data: The data to format. :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type). :return: A dictionary containing the formatted aggregation response. """ logger.info("Formatting data as aggregation") visualisation = input.get("visualisation", {}) title = visualisation.get("title", "") response = {} if data is None or len(data) == 0: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "table", "title": title} else: value_fields = visualisation.get("y-axis", []) key_fields = visualisation.get("x-axis", []) visualisaton_kind = visualisation["type"].replace(" ", "_") if visualisation["type"] is not None else "table" if visualisaton_kind.lower() in ["bar_chart", "line_chart", "pie_chart"] and len(value_fields) > 0 and len(key_fields) > 0: response["kind"] = visualisaton_kind response["data"] = data response["x"] = key_fields response["y"] = value_fields response["title"] = title else: response = {"kind": "table", "data": data, "title": title} return response ================================================ FILE: app/plugins/csv/handler.py ================================================ from .formatter import Formatter from loguru import logger import sqlite3 import pandas as pd from app.base.base_plugin import BasePlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin from typing import Tuple, Optional, List import uuid import sqlparse import sqlvalidator import os class CSVPlugin(BasePlugin, PluginMetadataMixin, Formatter): """ CSVPlugin class for interacting with CSV data and inserting it into an SQL database. """ def __init__(self, connector_name : str, document_files: List[str]): super().__init__(__name__) self.connector_name = connector_name.replace(' ','_') self.params = { 'csv_files': document_files, 'db_name': f"{self.connector_name}.sqlite", } self.connection = None self.max_limit = 10 def _dict_factory(self, cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d def connect(self) -> Tuple[bool, Optional[str]]: """ Establish a connection to the SQLite database, delete all tables, and insert data from CSV files. :return: Tuple containing connection status (True/False) and an error message if any. """ try: db_path = f"assets/datasource/csv_db/{self.params['db_name']}" if 'db_name' not in self.params or not self.params['db_name']: raise ValueError("Database name is missing or invalid in parameters.") if os.path.exists(db_path): # Delete the file os.remove(db_path) print(f"The database file '{db_path}' has been deleted successfully.") os.makedirs(os.path.dirname(db_path), exist_ok=True) self.connection = sqlite3.connect( db_path, uri=True, check_same_thread=False, timeout=8.0 ) self.connection.row_factory = self._dict_factory self.cursor = self.connection.cursor() logger.info(f"Connected to database: {db_path}") # Insert data from CSV files into the database for csv_file in self.params.get('csv_files', []): if 'file_name' not in csv_file or 'file_path' not in csv_file: logger.warning(f"Invalid CSV file entry: {csv_file}") continue table_name = csv_file['file_name'].rsplit('.', 1)[0].replace(' ','_') self._insert_csv_to_db(csv_file['file_path'], table_name) return True, None except Exception as e: logger.exception(f"Failed to connect to database: {type(e).__name__}, {e}") return False, f"{type(e).__name__}: {e}" def healthcheck(self): try: if self.connection is None: logger.warning("Connection to CSV is not established.") return False, "Connection to CSV is not established." self.cursor.execute("SELECT 1;") return True, None except sqlite3.Error as error: return False, error def _insert_csv_to_db(self, csv_file: str, table_name: str): """ Helper method to read a CSV file and insert its data into an SQLite table. :param csv_file: Path to the CSV file. :param table_name: Name of the table to insert data into. """ try: # Read CSV file using pandas df = pd.read_csv(csv_file) logger.info(f"Read CSV file: {csv_file} with {len(df)} rows.") # Write to the SQLite database df.to_sql(table_name, self.connection, if_exists='replace', index=False) logger.info(f"Data from {csv_file} inserted into table: {table_name}") except Exception as e: logger.exception(f"Failed to insert data from {csv_file} into table {table_name}: {str(e)}") def configure_datasource(self, init_config): pass def fetch_data(self, query, params=None): try: params = {} if params is None else params self.cursor.execute(query, params) if "limit" not in query.lower(): return self.cursor.fetchmany(self.max_limit), None else: return self.cursor.fetchall(), None except Exception as e: logger.critical(e) self.connection.rollback() return None, e def fetch_schema_details(self): #Creating ddl from table schema table_metadata = [] schema_ddl = [] table_schemas=self._fetch_table_schema() if len(table_schemas) != 0 : for table, columns in table_schemas.items(): table_ddl = "" schema = { "table_id": str(uuid.uuid4()), "table_name": table, "description": "", "columns": [] } fields= [] table_ddl = f"\n\nCREATE TABLE {table} (" for column in columns: fields.append({ "column_id" : str(uuid.uuid4()), "column_name": column['name'], "column_type": column['type'], "description": "", }) table_ddl +=f"\n{column['name']} {column['type']} ," table_ddl +=f");" schema["columns"] = fields table_metadata.append(schema) schema_ddl.append(table_ddl) return schema_ddl, table_metadata def create_ddl_from_metadata(self,table_metadata): schema_ddl = [] for table in table_metadata: tmp = f"\n\nCREATE TABLE {table['table_name']}" for field in table["columns"]: tmp = f"{tmp} {field.get('column_name','')} \n" schema_ddl.append(tmp) return schema_ddl def _fetch_table_schema(self): # Execute query to get all table names self.cursor.execute("SELECT name FROM sqlite_master") # Fetch all table names table_names = self.cursor.fetchall() table_schemas = {} for table in table_names: self.cursor.execute(f"SELECT name, type FROM pragma_table_info('{table['name']}')") columns = self.cursor.fetchall() table_schemas[table['name']] = columns return table_schemas def fetch_feedback(self): pass def validate(self,formated_sql): #validate sql using SQLParser queries = sqlparse.split(formated_sql) query = queries[0] formated_query = sqlparse.format(query, reindent=True, keyword_case='upper') parsed = sqlparse.parse(formated_query)[0] if parsed.get_type() != 'SELECT': return "Sorry, I am not designed for data manipulation operations" token_names = [p._get_repr_name() for p in parsed.tokens] if "DDL" in token_names: return "Sorry, I am not designed for data manipulation operations" sql_query = sqlvalidator.parse(formated_sql) try: if not sql_query.is_valid(): logger.info(sql_query.is_valid()) return "I didn't get you, Please reframe your question" except Exception as error: logger.critical(f"error:{error}") return None def close_conection(self): self.cursor.close() self.connection.close() ================================================ FILE: app/plugins/document/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'document' __display_name__ = 'Document Loader' __description__ = 'document integration for handling document data' __icon__ = '/assets/plugins/logos/document.svg' __category__ = 4 # Connection arguments __connection_args__ = OrderedDict( document_files= ConnectionArgument( type = 8, generic_name= 'document files', description = 'Supports only .pdf, .yaml, .txt, and .docx files.', order = 1, required = True, value = None, slug = "document_files" ) ) # Prompt __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are a Chatbot designed to answer user questions based only on the context given to you. Use the details enclosed in [context][/context] to generate answers. [context] {context} [/context] Adhere to these rules while generating answers: - Carefully read through the question and context word by word to appropriately answer the question. - Only use information provided in the context to answer questions. - Answer should not break the json format - If the answer cannot be found in the context, state that you don't have enough information to answer. - Present the answer in a human-readable Markdown format """ }, "user_prompt":{ "template": """ User question is "$question" Generate a JSON response in the following format without any formatting: { "explanation": "Explain how you determined the answer using the provided context", "general_message": "Answer in Markdown format to user question based on the context with all the details", } """ }, "regeneration_prompt": { "template": """ User question is "$question" Generate a JSON response in the following format without any formatting: { "explanation": "Explain how you determined the answer using the provided context", "general_message": "Answer in Markdown format to user question based on the context", } """ } }) __all__ = [ __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/document/formatter.py ================================================ from typing import Any, Dict from loguru import logger class Formatter: """ Formatter class to format the response based on the inference and data. """ def format(self, data: Dict[str, Any], inference: Dict[str, Any]) -> dict: """ Format the response using the given data and inference information. :param data: The data containing records to process. :param inference: Inference details including main entity and operation kind. :return: Formatted response dictionary. """ logger.info("Processing output using inference details") response = {} self.main_entity = inference.get("main_entity", "") self.kind = inference.get("operation_kind", "") self.general_message = inference.get("general_message", "Unable to process question, try again") response["content"] = self.general_message response["main_entity"] = self.main_entity response["main_format"] = self.kind response["role"] = "assistant" return response ================================================ FILE: app/plugins/document/handler.py ================================================ from .formatter import Formatter from loguru import logger import requests from app.base.base_plugin import BasePlugin from app.base.remote_data_plugin import RemoteDataPlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin from app.base.document_data_plugin import DocumentDataPlugin from typing import Tuple, Optional from app.readers.base_reader import BaseReader import os class Document(BasePlugin, PluginMetadataMixin,DocumentDataPlugin, Formatter): """ Document class for interacting with document data. """ def __init__(self, connector_name : str, document_files:str): super().__init__(__name__) self.connection = {} self.connector_name = connector_name.replace(' ','_') self.params = { 'document_files': document_files, } self.supported_types = {".pdf": "pdf", ".docx": "docx", ".txt": "text", ".yaml": "yaml"} def connect(self): """ Mocked connection method for pdf. :return: Tuple containing connection status (True/False) and an error message if any. """ return True, None def healthcheck(self)-> Tuple[bool, Optional[str]]: """ Perform a health check by checking if the document is accessible. :return: Tuple containing the health status (True/False) and error message (if any). """ logger.info("health check for documentations") try: data = [] for file_info in self.params.get("document_files", []): file_path = file_info.get("file_path") if not file_path: logger.error("File path is missing in the document file information.") continue # Check if it's a URL or a local file if file_path.startswith("http://") or file_path.startswith("https://"): try: response = requests.head(file_path, allow_redirects=True, timeout=5) if response.status_code >= 400: logger.error(f"URL not accessible: {file_path}") else: data.append(file_path) except Exception as e: logger.error(f"Error accessing URL {file_path}: {e}") else: if os.path.exists(file_path): data.append(file_path) else: logger.error(f"Local file does not exist: {file_path}") if not data: raise ValueError("No data fetched during health check") return True, None except Exception as e: logger.exception(f"Exception during fetching data: {str(e)}") return False, str(e) def fetch_data(self, params=None): data = [] for file_info in self.params.get("document_files", []): url = file_info.get("file_path") if url is None: logger.error("URL is missing in the document file information.") continue file_type = None for ext, typ in self.supported_types.items(): if url.endswith(ext): file_type = typ break if file_type is None: logger.error(f"Unsupported file format: {url}") continue base_reader = BaseReader({ "type": file_type, "path": [url] }) data.extend(base_reader.load_data()) return data ================================================ FILE: app/plugins/loader.py ================================================ from app.plugins.csv.handler import CSVPlugin from app.plugins.postgresql.handler import Postresql from app.plugins.mysql.handler import Mysql from app.plugins.mssql.handler import Mssql from app.plugins.bigquery.handler import Bigquery from app.plugins.airtable.handler import Airtable from app.plugins.website.handler import Website from app.plugins.document.handler import Document from app.plugins.sqlite.handler import Sqlite from app.plugins.maria.handler import Maria from loguru import logger class DSLoader: def __init__(self, configs): self.config = configs def load_ds(self): db_classes = { "postgres": Postresql, "mysql": Mysql, "mssql": Mssql, "bigquery": Bigquery, "airtable": Airtable, "website": Website, "document" : Document, "sqlite" : Sqlite, "CSV" : CSVPlugin, "maria": Maria, } db_type = self.config.get("type","") connection_params = self.config.get("params",{}) connector_name = self.config.get("connector_name","default") logger.info(f"initialising {db_type}") db_class = db_classes.get(db_type) if db_class: try: ds = db_class(connector_name=connector_name,**connection_params) return ds except Exception as e: raise e else: logger.warning("Invalid database type specified in configuration.") return None ================================================ FILE: app/plugins/maria/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'maria' __display_name__ = "MariaDB" __description__ = 'MariaDB integration for handling MariaDB database operations.' __icon__ = '/assets/plugins/logos/mariaDB.svg' __category__ = 2 # Connection arguments __connection_args__ = OrderedDict( db_name= ConnectionArgument( type = 1, generic_name= 'MariaDB Database name', description = 'Database name', order= 5, required = True, value = None, slug = "db_name" ), db_user=ConnectionArgument( type= 1, generic_name= 'MariaDB User name', description= 'Database username', order= 2, required = True, value = None, slug = "db_user" ), db_password=ConnectionArgument( type= 2, generic_name= 'MariaDB Password', description= 'Database password', order= 3, required = True, value = None, slug = "db_password" ), db_host=ConnectionArgument( type= 1, generic_name= 'MariaDB Database host', description= 'Database hostname', order= 1, required = True, value = None, slug = "db_host" ), db_port=ConnectionArgument( type= 3, generic_name= 'MariaDB Database port', description= 'Database port', order = 4, required = True, value = None, slug = "db_port" ), ) # Prompt __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are an MariaDB expert. Your job is to answer questions about a MariaDB database using only the provided schema details and rules. go through the schema details given below -- start db schema section-- {schema} -- end db schema section-- A brief description about the schema is given below -- start db context section-- {context} -- end db context section-- Sample sql queries with their questions are given below -- start query samples section-- $suggestions -- end query samples section-- Adhere to the given rules without failure -- start rules section -- - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`. - use LIKE operator with LOWER function for string comparison or equality - Always use alias/table name for fields in WHERE condition - Do not use non existing tables or fields - id columns are mandatory for all operations - Do not use JSON_BUILD_OBJECT operation - Do not use unwanted joins - Do not return incomplete queries - Adher to sysql query syntax -- end rules section -- """ }, "user_prompt":{ "template": """ Follow these steps to generate query to solve the question `$question` 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Do only the task asked, Don't hallucinate and overdo the task 4. Strictly return all the fields in the schema during listing operations 5. Strictly return at least 1 text fields and an id field during aggregation/group by operations 6. Generate a query to solve the problem using the schema, context, and strictly follow the rules 7. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "mariadb query", "operation_kind" : "aggregation|list", "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "x-axis": ["fields that can be used as x axis"], "y-axis": ["fields that can be used as y axis"], "title": "layout title name" }, "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ }, "regeneration_prompt": { "template": """ You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]` [question] $question [/question] You generated this query given in `[query][/query]` [query] {query_generated} [/query] But upon execution you encountered some error , error traceback is given in [query_error][/query_error] [query_error] {exception_log} [/query_error] Follow these steps to generate the query 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Use survey answers if available and include it in query for filtering values 4. Do only the task asked, Don't hallucinate and overdo the task 5. Strictly return all the fields in the schema during listing operations 6. Strictly return at least 1 text fields and an id field during aggregation/group by operations 7. Generate a query to solve the problem using the schema, context and the rules and based on the previous query try to rectify the query error 8. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "mariadb query", "operation_kind" : "aggregation|list", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "value_field": "fields in which values are stored", "x-axis": "field that can be used as x axis", "y-axis": "field that can be used as y axis", "title": "layout title name" }, "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ } }) __all__ = [ __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/maria/formatter.py ================================================ from typing import Any from loguru import logger class Formatter: def format(self, data: Any,input) -> (dict): """ Main entry point for formatting the data based on the input parameters. Handles different formatting strategies based on operation kind. :param data: The data to format. :param input_params: Dictionary containing operation and formatting details. :return: A dictionary containing the formatted response. """ response = {} self.main_entity = input.get("main_entity") self.kind = input.get("operation_kind", "").lower() self.general_message = input.get("general_message") self.empty_message = input.get("empty_message") logger.info("Formatting output using inference for mariadb") if self.kind == "list": response = self.basic_formatter(data, input) elif self.kind == "aggregation": response = self.aggregation_formatter(data, input) else: response["data"] = data response["kind"] = "list" response.update({ "main_entity": self.main_entity, "main_format": self.kind, "role": "assistant", "content": self.general_message, "empty_message": self.empty_message, }) return response def basic_formatter(self, data: Any, input:Any) -> dict : """ Formats data as a list, handling cases for none, single, and multiple entries. :param data: The data to format. :return: A dictionary containing the formatted list response. """ logger.info("Formatting data as a list") if data is None: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "single"} else: response = {"data": data, "kind": "list"} return response def aggregation_formatter(self, data:Any, input:Any) -> dict : """ Formats data for aggregation visualisation, supporting table and chart formats. :param data: The data to format. :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type). :return: A dictionary containing the formatted aggregation response. """ logger.info("Formatting data as aggregation") visualisation = input.get("visualisation", {}) response = {} if data is None or len(data) == 0: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "table"} else: value_fields = visualisation.get("y-axis", []) key_fields = visualisation.get("x-axis", []) title = visualisation.get("title", "") visualisaton_kind = visualisation["type"].replace(" ", "_") if visualisation["type"] is not None else "table" if visualisaton_kind.lower() in ["bar_chart", "line_chart", "pie_chart"] and len(value_fields) > 0 and len(key_fields) > 0: response["kind"] = visualisaton_kind response["data"] = data response["x"] = key_fields response["y"] = value_fields response["title"] = title else: response = {"kind": "table", "data": data} return response ================================================ FILE: app/plugins/maria/handler.py ================================================ import mariadb from loguru import logger import sqlvalidator import sqlparse from .formatter import Formatter import uuid from app.base.base_plugin import BasePlugin from app.base.query_plugin import QueryPlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin class Maria(Formatter, BasePlugin, QueryPlugin, PluginMetadataMixin): def __init__(self,connector_name : str, db_name:str, db_user:str="root", db_password:str="", db_host:str="localhost", db_port:int=3306): logger.info("Initializing datasource") super().__init__(__name__) db_port = int(db_port) self.connector_name = connector_name.replace(' ','_') # common self.params = { 'database': db_name, 'user': db_user, 'password': db_password, 'host': db_host, 'port': db_port, } self.connection = None # class specific self.cursor = None self.max_limit = 5 def connect(self): try: self.connection = mariadb.connect(**self.params) self.cursor = self.connection.cursor(dictionary=True) logger.info("Connection to MariaDB successful.") return True, None except mariadb.Error as error: logger.error(f"Error connecting to MariaDB: {error}") return False, error def healthcheck(self): try: if self.connection is None: logger.warning("Connection to MariaDB is not established.") return False, "Connection to MariaDB is not established." with self.connection.cursor() as cursor: cursor.execute("SELECT 1;") cursor.fetchall() return True, None except mariadb.Error as error: logger.error(f"Error during healthcheck: {error}") return False, error def configure_datasource(self, init_config): logger.info("Configuring datasource") if init_config is not None and "script" in init_config: try: self.cursor.execute(init_config["script"]) self.connection.commit() except Exception as e: return e return None def fetch_data(self, query, params=None): try: self.cursor.execute(query, params) if "limit" not in query.lower(): return self.cursor.fetchmany(self.max_limit), None else: return self.cursor.fetchall(), None except mariadb.Error as e: logger.critical(e) self.connection.rollback() return None, e def fetch_schema_details(self): #Creating ddl from table schema table_metadata = [] schema_ddl = [] table_schemas=self._fetch_table_schema() if len(table_schemas) != 0 : for table, columns in table_schemas.items(): table_ddl = "" schema = { "table_id": str(uuid.uuid4()), "table_name": table, "description": "", "columns": [] } fields= [] table_ddl = f"\n\nCREATE TABLE {table}" for column in columns: fields.append({ "column_id" : str(uuid.uuid4()), "column_name": column['column_name'], "column_type": column['data_type'], "description": "", }) table_ddl +=f"\n{column['column_name']} {column['data_type']} {column['character_maximum_length']}," table_ddl +=f");" schema["columns"] = fields table_metadata.append(schema) schema_ddl.append(table_ddl) return schema_ddl, table_metadata def create_ddl_from_metadata(self,table_metadata): schema_ddl = [] for table in table_metadata: tmp = f"\n\nCREATE TABLE {table['table_name']}" for field in table["columns"]: tmp = f"{tmp} {field.get('column_name','')} \n" schema_ddl.append(tmp) return schema_ddl def _fetch_table_schema(self): # Execute query to get all table names in the public schema self.cursor.execute("SHOW TABLES") # Fetch all table names table_names = self.cursor.fetchall() table_schemas = {} for table in table_names: table_name = next(iter(table.values())) self.cursor.execute(f"SELECT column_name, data_type, IFNULL(character_maximum_length, '') AS character_maximum_length FROM information_schema.columns WHERE table_name = '{table_name}'") columns = self.cursor.fetchall() table_schemas[table_name] = columns return table_schemas def fetch_feedback(self): sql_query = "SELECT chat_query, feedback_json FROM public.chat_histories WHERE feedback_status = 2 AND created_at >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY);" result = self.fetch_data(sql_query) logger.info(result) return result def validate(self,formated_sql): #validate sql using SQLParser queries = sqlparse.split(formated_sql) query = queries[0] formated_query = sqlparse.format(query, reindent=True, keyword_case='upper') parsed = sqlparse.parse(formated_query)[0] if parsed.get_type() != 'SELECT': return "Sorry, I am not designed for data manipulation operations" token_names = [p._get_repr_name() for p in parsed.tokens] if "DDL" in token_names: return "Sorry, I am not designed for data manipulation operations" sql_query = sqlvalidator.parse(formated_sql) if not sql_query.is_valid(): logger.info(sql_query.is_valid()) return "I didn't get you, Please reframe your question" return None def close_connection(self): self.cursor.close() self.connection.close() ================================================ FILE: app/plugins/mssql/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'mssql' __display_name__ = "MSSQL DB" __description__ = 'MSSQL integration for handling MSSQL database operations.' __icon__ = '/assets/plugins/logos/mssql.svg' __category__ = 2 # Connection arguments __connection_args__ = OrderedDict( db_name= ConnectionArgument( type = 1, generic_name= 'MSSQL Database name', description = 'Database name', order= 5, required = True, value = None, slug = "db_name" ), db_user=ConnectionArgument( type= 1, generic_name= 'MSSQL User name', description= 'Database username', order= 2, required = True, value = None, slug = "db_user" ), db_password=ConnectionArgument( type= 2, generic_name= 'MSSQL Password', description= 'Database password', order= 3, required = True, value = None, slug = "db_password" ), db_server=ConnectionArgument( type= 1, generic_name= 'MSSQL Database Server', description= 'Include port number with a comma in server eg: ip.aaaaaaa.com,9600', order= 1, required = True, value = None, slug = "db_server" ), db_port=ConnectionArgument( type= 3, generic_name= 'MSSQL Database port', description= 'Database port', order = 4, required = True, value = None, slug = "db_port" ), ) # Prompt __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are an Mssql expert. Your job is to answer questions about a Mssql database using only the provided schema details and rules. Conversation history is provided below: -- start chat_history section -- {recal_history} -- end chat_history section -- go through the schema details given below: -- start db schema section-- {schema} -- end db schema section-- A brief description about the schema is given below: -- start db context section-- {context} -- end db context section-- Sample sql queries with their questions are given below: -- start query samples section-- $suggestions -- end query samples section-- Adhere to the given rules without failure -- start rules section -- - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`. - use LIKE operator with LOWER function for string comparison or equality - Always use alias/table name for fields in WHERE condition - Do not use non existing tables or fields - id columns are mandatory for all operations - Do not use JSON_BUILD_OBJECT operation - Do not use unwanted joins - Do not return incomplete queries - Adher to sysql query syntax -- end rules section -- """ }, "user_prompt":{ "template": """ Follow these steps to generate query to solve the question `$question` 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Do only the task asked, Don't hallucinate and overdo the task 4. Strictly return all the fields in the schema during listing operations 5. Strictly return at least 1 text fields and an id field during aggregation/group by operations 6. Generate a query to solve the problem using the schema, context, and strictly follow the rules 7. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "mssql query", "operation_kind" : "aggregation|list", "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "x-axis": ["fields that can be used as x axis"], "y-axis": ["fields that can be used as y axis"], "title": "layout title name" }, "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ }, "regeneration_prompt": { "template": """ You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]` [question] $question [/question] You generated this query given in `[query][/query]` [query] {query_generated} [/query] But upon execution you encountered some error , error traceback is given in [query_error][/query_error] [query_error] {exception_log} [/query_error] Follow these steps to generate the query 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Use survey answers if available and include it in query for filtering values 4. Do only the task asked, Don't hallucinate and overdo the task 5. Strictly return all the fields in the schema during listing operations 6. Strictly return at least 1 text fields and an id field during aggregation/group by operations 7. Generate a query to solve the problem using the schema, context and the rules and based on the previous query try to rectify the query error 8. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "mssql query", "operation_kind" : "aggregation|list", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "value_field": "fields in which values are stored", "x-axis": "field that can be used as x axis", "y-axis": "field that can be used as y axis", "title": "layout title name" }, "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ } }) __all__ = [ __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/mssql/formatter.py ================================================ from typing import Any from loguru import logger class Formatter: def format(self, data: Any,input) -> (dict): """ Main entry point for formatting the data based on the input parameters. Handles different formatting strategies based on operation kind. :param data: The data to format. :param input_params: Dictionary containing operation and formatting details. :return: A dictionary containing the formatted response. """ response = {} self.main_entity = input.get("main_entity") self.kind = input.get("operation_kind", "").lower() self.general_message = input.get("general_message") self.empty_message = input.get("empty_message") logger.info("Formatting output using inference for mysql") if self.kind == "list": response = self.basic_formatter(data, input) elif self.kind == "aggregation": response = self.aggregation_formatter(data, input) else: response["data"] = data response["kind"] = "list" response.update({ "main_entity": self.main_entity, "main_format": self.kind, "role": "assistant", "content": self.general_message, "empty_message": self.empty_message, }) return response def basic_formatter(self, data: Any, input:Any) -> dict : """ Formats data as a list, handling cases for none, single, and multiple entries. :param data: The data to format. :return: A dictionary containing the formatted list response. """ logger.info("Formatting data as a list") if data is None: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "single"} else: response = {"data": data, "kind": "list"} return response def aggregation_formatter(self, data:Any, input:Any) -> dict : """ Formats data for aggregation visualisation, supporting table and chart formats. :param data: The data to format. :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type). :return: A dictionary containing the formatted aggregation response. """ logger.info("Formatting data as aggregation") visualisation = input.get("visualisation", {}) response = {} if data is None or len(data) == 0: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "table"} else: value_fields = visualisation.get("y-axis", []) key_fields = visualisation.get("x-axis", []) title = visualisation.get("title", "") visualisaton_kind = visualisation["type"].replace(" ", "_") if visualisation["type"] is not None else "table" if visualisaton_kind.lower() in ["bar_chart", "line_chart", "pie_chart"] and len(value_fields) > 0 and len(key_fields) > 0: response["kind"] = visualisaton_kind response["data"] = data response["x"] = key_fields response["y"] = value_fields response["title"] = title else: response = {"kind": "table", "data": data} return response ================================================ FILE: app/plugins/mssql/handler.py ================================================ import pyodbc from loguru import logger import sqlvalidator import sqlparse from .formatter import Formatter import uuid from app.base.base_plugin import BasePlugin from app.base.query_plugin import QueryPlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin class Mssql(Formatter, BasePlugin, QueryPlugin, PluginMetadataMixin): def __init__(self, connector_name : str, db_name:str, db_user:str, db_password:str, db_server:str="localhost", db_port:int=1433): logger.info("Initializing datasource") super().__init__(__name__) self.connector_name = connector_name.replace(' ','_') self.params = { 'database': db_name, 'user': db_user, 'password': db_password, 'server': db_server, 'port': db_port, } self.connection = None self.cursor = None self.max_limit = 10000 def connect(self): try: drivers = [driver for driver in pyodbc.drivers()] connection_string = ( f"DRIVER={{{drivers[0]}}};" f"SERVER={self.params['server']},{self.params['port']};" f"DATABASE={self.params['database']};" f"UID={self.params['user']};" f"PWD={self.params['password']};" f"TrustServerCertificate=yes;" ) self.connection = pyodbc.connect(connection_string) self.cursor = self.connection.cursor() logger.info("Connection to MsSQL DB successful.") return True, None except pyodbc.Error as error: logger.error(f"Error connecting to MsSQL DB: {error}") return False, str(error) def healthcheck(self): try: if self.connection is None: logger.warning("Connection to MsSQL DB is not established.") return False, "Connection to MsSQL DB is not established." with self.connection.cursor() as cursor: cursor.execute("SELECT 1;") cursor.fetchall() return True, None except pyodbc.Error as error: logger.error(f"Error during healthcheck: {error}") return False, str(error) def configure_datasource(self, init_config): pass def fetch_data(self, query, reconnect_attempt = True, params=None): try: self.cursor.execute(query) # Fetch column names column_names = [column[0] for column in self.cursor.description] # Fetch data if "TOP" not in query.upper(): rows = self.cursor.fetchmany(self.max_limit) else: rows = self.cursor.fetchall() # Map column names to row data result = [dict(zip(column_names, row)) for row in rows] return result, None except pyodbc.Error as error: logger.error(f"Error executing query: {error}") if '08S01' in str(error) and reconnect_attempt: logger.info("Attempting to reconnect...") self.connect() # Attempt to reconnect reconnect_attempt = False self.fetch_data(query, reconnect_attempt = False, params=None) return None, str(error) def fetch_schema_details(self): schema_ddl = [] table_metadata = [] # Fetch all table and view names self.cursor.execute(""" SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE IN ('BASE TABLE', 'VIEW') """) tables = self.cursor.fetchall() for table in tables: schema_name = table[0] table_name = table[1] table_type = table[2] logger.info(f"Fetching DDL for {table_type}: {schema_name}.{table_name}") schema = { "table_id": str(uuid.uuid4()), "table_name": f"{schema_name}.{table_name}", "description": "", "columns": [] } # Fetch column details self.cursor.execute(f""" SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{schema_name}' AND TABLE_NAME = '{table_name}'; """) columns = self.cursor.fetchall() ddl = f"CREATE { 'TABLE' if table_type == 'BASE TABLE' else 'VIEW' } {schema_name}.{table_name} (\n" fields = [] for column in columns: column_name = column[0] data_type = column[1] max_length = column[2] is_nullable = column[3] column_default = column[4] fields.append({ "column_id": str(uuid.uuid4()), "column_name": column_name, "column_type": data_type, "description": "", }) # Format data type with length if needed datatype_formatted = f"{data_type}({max_length})" if max_length else data_type nullable = "NULL" if is_nullable == "YES" else "NOT NULL" default = f"DEFAULT {column_default}" if column_default else "" ddl += f" {column_name} {datatype_formatted} {nullable} {default},\n" # Fix schema['columns'] once per table schema["columns"] = fields table_metadata.append(schema) # Clean up DDL (remove last comma) ddl = ddl.rstrip(",\n") + "\n);\n\n" schema_ddl.append(ddl) table_metadata = sorted(table_metadata, key=lambda x: x['table_name'].lower()) return schema_ddl, table_metadata def create_ddl_from_metadata(self,table_metadata): schema_ddl = [] for table in table_metadata: tmp = f"\n\nCREATE TABLE {table['table_name']}" for field in table["columns"]: tmp = f"{tmp} {field.get('column_name','')} \n" schema_ddl.append(tmp) return schema_ddl def fetch_feedback(self): pass def validate(self,formated_sql): #validate sql using SQLParser queries = sqlparse.split(formated_sql) query = queries[0] formated_query = sqlparse.format(query, reindent=True, keyword_case='upper') parsed = sqlparse.parse(formated_query)[0] if parsed.get_type() != 'SELECT': return "Sorry, I am not designed for data manipulation operations" token_names = [p._get_repr_name() for p in parsed.tokens] if "DDL" in token_names: return "Sorry, I am not designed for data manipulation operations" # sql_query = sqlvalidator.parse(formated_sql) # if not sql_query.is_valid(): # logger.info(sql_query.is_valid()) # return "I didn't get you, Please reframe your question" return None def close_connection(self): self.cursor.close() self.connection.close() ================================================ FILE: app/plugins/mysql/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'mysql' __display_name__ = "MySQL DB" __description__ = 'MySQL integration for handling MySQL database operations.' __icon__ = '/assets/plugins/logos/mysql.svg' __category__ = 2 # Connection arguments __connection_args__ = OrderedDict( db_name= ConnectionArgument( type = 1, generic_name= 'MySQL Database name', description = 'Database name', order= 5, required = True, value = None, slug = "db_name" ), db_user=ConnectionArgument( type= 1, generic_name= 'MySQL User name', description= 'Database username', order= 2, required = True, value = None, slug = "db_user" ), db_password=ConnectionArgument( type= 2, generic_name= 'MySQL Password', description= 'Database password', order= 3, required = True, value = None, slug = "db_password" ), db_host=ConnectionArgument( type= 1, generic_name= 'MySQL Database host', description= 'Database hostname', order= 1, required = True, value = None, slug = "db_host" ), db_port=ConnectionArgument( type= 3, generic_name= 'MySQL Database port', description= 'Database port', order = 4, required = True, value = None, slug = "db_port" ), ) # Prompt __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are an Mysql expert. Your job is to answer questions about a Mysql database using only the provided schema details and rules. go through the schema details given below -- start db schema section-- {schema} -- end db schema section-- A brief description about the schema is given below -- start db context section-- {context} -- end db context section-- Sample sql queries with their questions are given below -- start query samples section-- $suggestions -- end query samples section-- Adhere to the given rules without failure -- start rules section -- - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`. - use LIKE operator with LOWER function for string comparison or equality - Always use alias/table name for fields in WHERE condition - Do not use non existing tables or fields - id columns are mandatory for all operations - Do not use JSON_BUILD_OBJECT operation - Do not use unwanted joins - Do not return incomplete queries - Adher to sysql query syntax -- end rules section -- """ }, "user_prompt":{ "template": """ Follow these steps to generate query to solve the question `$question` 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Do only the task asked, Don't hallucinate and overdo the task 4. Strictly return all the fields in the schema during listing operations 5. Strictly return at least 1 text fields and an id field during aggregation/group by operations 6. Generate a query to solve the problem using the schema, context, and strictly follow the rules 7. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "mysql query", "operation_kind" : "aggregation|list", "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "x-axis": ["fields that can be used as x axis"], "y-axis": ["fields that can be used as y axis"], "title": "layout title name" }, "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ }, "regeneration_prompt": { "template": """ You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]` [question] $question [/question] You generated this query given in `[query][/query]` [query] {query_generated} [/query] But upon execution you encountered some error , error traceback is given in [query_error][/query_error] [query_error] {exception_log} [/query_error] Follow these steps to generate the query 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Use survey answers if available and include it in query for filtering values 4. Do only the task asked, Don't hallucinate and overdo the task 5. Strictly return all the fields in the schema during listing operations 6. Strictly return at least 1 text fields and an id field during aggregation/group by operations 7. Generate a query to solve the problem using the schema, context and the rules and based on the previous query try to rectify the query error 8. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "mysql query", "operation_kind" : "aggregation|list", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "value_field": "fields in which values are stored", "x-axis": "field that can be used as x axis", "y-axis": "field that can be used as y axis", "title": "layout title name" }, "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ } }) __all__ = [ __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/mysql/formatter.py ================================================ from typing import Any from loguru import logger class Formatter: def format(self, data: Any,input) -> (dict): """ Main entry point for formatting the data based on the input parameters. Handles different formatting strategies based on operation kind. :param data: The data to format. :param input_params: Dictionary containing operation and formatting details. :return: A dictionary containing the formatted response. """ response = {} self.main_entity = input.get("main_entity") self.kind = input.get("operation_kind", "").lower() self.general_message = input.get("general_message") self.empty_message = input.get("empty_message") logger.info("Formatting output using inference for mysql") if self.kind == "list": response = self.basic_formatter(data, input) elif self.kind == "aggregation": response = self.aggregation_formatter(data, input) else: response["data"] = data response["kind"] = "list" response.update({ "main_entity": self.main_entity, "main_format": self.kind, "role": "assistant", "content": self.general_message, "empty_message": self.empty_message, }) return response def basic_formatter(self, data: Any, input:Any) -> dict : """ Formats data as a list, handling cases for none, single, and multiple entries. :param data: The data to format. :return: A dictionary containing the formatted list response. """ logger.info("Formatting data as a list") if data is None: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "single"} else: response = {"data": data, "kind": "list"} return response def aggregation_formatter(self, data:Any, input:Any) -> dict : """ Formats data for aggregation visualisation, supporting table and chart formats. :param data: The data to format. :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type). :return: A dictionary containing the formatted aggregation response. """ logger.info("Formatting data as aggregation") visualisation = input.get("visualisation", {}) response = {} if data is None or len(data) == 0: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "table"} else: value_fields = visualisation.get("y-axis", []) key_fields = visualisation.get("x-axis", []) title = visualisation.get("title", "") visualisaton_kind = visualisation["type"].replace(" ", "_") if visualisation["type"] is not None else "table" if visualisaton_kind.lower() in ["bar_chart", "line_chart", "pie_chart"] and len(value_fields) > 0 and len(key_fields) > 0: response["kind"] = visualisaton_kind response["data"] = data response["x"] = key_fields response["y"] = value_fields response["title"] = title else: response = {"kind": "table", "data": data} return response ================================================ FILE: app/plugins/mysql/handler.py ================================================ import pymysql import mysql.connector from loguru import logger import sqlvalidator import sqlparse from .formatter import Formatter import uuid from app.base.base_plugin import BasePlugin from app.base.query_plugin import QueryPlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin class Mysql(Formatter, BasePlugin, QueryPlugin, PluginMetadataMixin): def __init__(self, connector_name : str, db_name:str, db_user:str="root", db_password:str="", db_host:str="localhost", db_port:int=3306): logger.info("Initializing datasource") super().__init__(__name__) self.connector_name = connector_name.replace(' ','_') # common self.params = { 'database': db_name, 'user': db_user, 'password': db_password, 'host': db_host, 'port': db_port, } self.connection = None # class specific self.cursor = None self.max_limit = 5 def connect(self): try: self.connection = mysql.connector.connect(**self.params) self.cursor = self.connection.cursor(dictionary=True) logger.info("Connection to MySQL DB successful.") return True, None except mysql.connector.Error as error: logger.error(f"Error connecting to MySQL DB: {error}") return False, error def healthcheck(self): try: if self.connection is None or not self.connection.is_connected(): logger.warning("Connection to MySQL DB is not established.") return False, "Connection to MySQL DB is not established." with self.connection.cursor() as cursor: cursor.execute("SELECT 1;") cursor.fetchall() return True, None except mysql.connector.Error as error: logger.error(f"Error during healthcheck: {error}") return False, error def configure_datasource(self, init_config): logger.info("Configuring datasource") if init_config is not None and "script" in init_config: try: self.cursor.execute(init_config["script"]) self.connection.commit() except Exception as e: return e return None def fetch_data(self, query, params=None): try: self.cursor.execute(query, params) if "limit" not in query.lower(): return self.cursor.fetchmany(self.max_limit), None else: return self.cursor.fetchall(), None except pymysql.Error as e: logger.critical(e) self.connection.rollback() return None, e def fetch_schema_details(self): #Creating ddl from table schema table_metadata = [] schema_ddl = [] table_schemas=self._fetch_table_schema() if len(table_schemas) != 0 : for table, columns in table_schemas.items(): table_ddl = "" schema = { "table_id": str(uuid.uuid4()), "table_name": table, "description": "", "columns": [] } fields= [] table_ddl = f"\n\nCREATE TABLE {table}" for column in columns: fields.append({ "column_id" : str(uuid.uuid4()), "column_name": column['COLUMN_NAME'], "column_type": column['DATA_TYPE'], "description": "", }) table_ddl +=f"\n{column['COLUMN_NAME']} {column['DATA_TYPE']} {column['CHARACTER_MAXIMUM_LENGTH']}," table_ddl +=f");" schema["columns"] = fields table_metadata.append(schema) schema_ddl.append(table_ddl) return schema_ddl, table_metadata def create_ddl_from_metadata(self,table_metadata): schema_ddl = [] for table in table_metadata: tmp = f"\n\nCREATE TABLE {table['table_name']}" for field in table["columns"]: tmp = f"{tmp} {field.get('column_name','')} \n" schema_ddl.append(tmp) return schema_ddl def _fetch_table_schema(self): # Execute query to get all table names in the public schema self.cursor.execute("SHOW TABLES") # Fetch all table names table_names = self.cursor.fetchall() table_schemas = {} for table in table_names: table_name = next(iter(table.values())) self.cursor.execute(f"SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = '{table_name}'") columns = self.cursor.fetchall() table_schemas[table_name] = columns return table_schemas def fetch_feedback(self): sql_query = "SELECT chat_query, feedback_json FROM public.chat_histories WHERE feedback_status = 2 AND created_at >= CURRENT_DATE - INTERVAL '7 days';" result = self.fetch_data(sql_query) logger.info(result) return result def validate(self,formated_sql): #validate sql using SQLParser queries = sqlparse.split(formated_sql) query = queries[0] formated_query = sqlparse.format(query, reindent=True, keyword_case='upper') parsed = sqlparse.parse(formated_query)[0] if parsed.get_type() != 'SELECT': return "Sorry, I am not designed for data manipulation operations" token_names = [p._get_repr_name() for p in parsed.tokens] if "DDL" in token_names: return "Sorry, I am not designed for data manipulation operations" sql_query = sqlvalidator.parse(formated_sql) if not sql_query.is_valid(): logger.info(sql_query.is_valid()) return "I didn't get you, Please reframe your question" return None def close_connection(self): self.cursor.close() self.connection.close() ================================================ FILE: app/plugins/postgresql/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'postgres' __display_name__ = "Postgres DB" __description__ = 'Postgres integration for handling Postgres database operations.' __icon__ = '/assets/plugins/logos/postgresql.svg' __category__ = 2 # Connection arguments __connection_args__ = OrderedDict( db_name= ConnectionArgument( type = 1, generic_name= 'Database name', description = 'Database name', order= 5, required = True, value = None, slug = "db_name" ), db_user=ConnectionArgument( type= 1, generic_name= 'User name', description= 'Database username', order= 2, required = True, value = None, slug = "db_user" ), db_password=ConnectionArgument( type= 2, generic_name= 'Password', description= 'Database password', order= 3, required = True, value = None, slug = "db_password" ), db_host=ConnectionArgument( type= 1, generic_name= 'Database host', description= 'Database hostname', order= 1, required = True, value = None, slug = "db_host" ), db_port=ConnectionArgument( type= 3, generic_name= 'Database port', description= 'Database port', order = 4, required = True, value = None, slug = "db_port" ), db_sslmode=ConnectionArgument( type= 6, generic_name= 'Database sslmode', description= 'SSL mode', order= 6, required = True, value=[{"label":"prefer", "value": "prefer"}, {"label":"disable", "value": "disable"}, {"label":"require", "value": "require"}], slug = "db_sslmode" ) ) # Prompt __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are an Postgresql expert. Your job is to answer questions about a Postgres database using only the provided schema details and rules. go through the schema details given below -- start db schema section-- {schema} -- end db schema section-- A brief description about the schema is given below -- start db context section-- {context} -- end db context section-- Sample sql queries with their questions are given below -- start query samples section-- $suggestions -- end query samples section-- Adhere to the given rules without failure -- start rules section -- - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`. - use LIKE operator with LOWER function for string comparison or equality - Always use alias/table name for fields in WHERE condition - Do not use non existing tables or fields - id columns are mandatory for all operations - Do not use JSON_BUILD_OBJECT operation - Do not use unwanted joins - Do not return incomplete queries - Adher to postgresql query syntax -- end rules section -- """ }, "user_prompt":{ "template": """ Follow these steps to generate query to solve the question `$question` 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Do only the task asked, Don't hallucinate and overdo the task 4. Strictly return all the fields in the schema during listing operations 5. Strictly return at least 1 text fields and an id field during aggregation/group by operations 6. Generate a query to solve the problem using the schema, context, and strictly follow the rules 7. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "postgresql query", "operation_kind" : "aggregation|list", "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "x-axis": ["fields that can be used as x axis"], "y-axis": ["fields that can be used as y axis"], "title": "layout title name" }, "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ }, "regeneration_prompt": { "template": """ You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]` [question] $question [/question] You generated this query given in `[query][/query]` [query] {query_generated} [/query] But upon execution you encountered some error , error traceback is given in [query_error][/query_error] [query_error] {exception_log} [/query_error] Follow these steps to generate the query 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Use survey answers if available and include it in query for filtering values 4. Do only the task asked, Don't hallucinate and overdo the task 5. Strictly return all the fields in the schema during listing operations 6. Strictly return at least 1 text fields and an id field during aggregation/group by operations 7. Generate a query to solve the problem using the schema, context and the rules and based on the previous query try to rectify the query error 8. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "postgresql query", "operation_kind" : "aggregation|list", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "value_field": "fields in which values are stored", "x-axis": "field that can be used as x axis", "y-axis": "field that can be used as y axis", "title": "layout title name" }, "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ } }) __all__ = [ __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/postgresql/formatter.py ================================================ from typing import Any from loguru import logger class Formatter: def format(self, data: Any,input) -> (dict): """ Main entry point for formatting the data based on the input parameters. Handles different formatting strategies based on operation kind. :param data: The data to format. :param input_params: Dictionary containing operation and formatting details. :return: A dictionary containing the formatted response. """ response = {} self.main_entity = input.get("main_entity") self.kind = input.get("operation_kind", "").lower() self.general_message = input.get("general_message") self.empty_message = input.get("empty_message") logger.info("Formatting output using inference for postgresql") if self.kind == "list": response = self.basic_formatter(data, input) elif self.kind == "aggregation": response = self.aggregation_formatter(data, input) else: response["data"] = data response["kind"] = "list" response.update({ "main_entity": self.main_entity, "main_format": self.kind, "role": "assistant", "content": self.general_message, "empty_message": self.empty_message, }) return response def basic_formatter(self, data: Any, input:Any) -> dict : """ Formats data as a list, handling cases for none, single, and multiple entries. :param data: The data to format. :return: A dictionary containing the formatted list response. """ logger.info("Formatting data as a list") if data is None: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "single"} else: response = {"data": data, "kind": "list"} return response def aggregation_formatter(self, data:Any, input:Any) -> dict : """ Formats data for aggregation visualisation, supporting table and chart formats. :param data: The data to format. :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type). :return: A dictionary containing the formatted aggregation response. """ logger.info("Formatting data as aggregation") visualisation = input.get("visualisation", {}) response = {} if data is None or len(data) == 0: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "table"} else: value_fields = visualisation.get("y-axis", []) key_fields = visualisation.get("x-axis", []) title = visualisation.get("title", "") visualisaton_kind = visualisation["type"].replace(" ", "_") if visualisation["type"] is not None else "table" if visualisaton_kind.lower() in ["bar_chart", "line_chart", "pie_chart"] and len(value_fields) > 0 and len(key_fields) > 0: response["kind"] = visualisaton_kind response["data"] = data response["x"] = key_fields response["y"] = value_fields response["title"] = title else: response = {"kind": "table", "data": data} return response ================================================ FILE: app/plugins/postgresql/handler.py ================================================ import psycopg2 from psycopg2 import sql, extras from loguru import logger import sqlvalidator import sqlparse from .formatter import Formatter import uuid from app.base.base_plugin import BasePlugin from app.base.query_plugin import QueryPlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin class Postresql(Formatter, BasePlugin, QueryPlugin, PluginMetadataMixin): def __init__(self, connector_name : str, db_name:str, db_user:str="postgres", db_password:str="", db_host:str="localhost", db_port:int=5432, db_sslmode:str="disable"): logger.info("Initializing datasource") super().__init__(__name__) self.connector_name = connector_name.replace(' ','_') # common self.params = { 'dbname': db_name, 'user': db_user, 'password': db_password, 'host': db_host, 'port': db_port, 'sslmode': db_sslmode } self.connection = None # class specific self.cursor = None self.max_limit = 5 def connect(self): try: self.connection = psycopg2.connect(**self.params) self.cursor = self.connection.cursor(cursor_factory = extras.RealDictCursor) logger.info("Connection to PostgreSQL DB successful.") return True, None except psycopg2.DatabaseError as error: logger.error(f"Error connecting to PostgreSQL DB: {error}") return False, error def healthcheck(self): try: if self.connection is None or self.connection.closed: logger.warning("Connection to PostgreSQL DB is not established.") return False, "Connection to PostgreSQL DB is not established." with self.connection.cursor() as cursor: cursor.execute("SELECT 1;") return True, None except psycopg2.DatabaseError as error: return False, error def configure_datasource(self, init_config): logger.info("Configuring datasource") if init_config is not None and "script" in init_config: try: self.cursor.execute(init_config["script"]) self.connection.commit() except Exception as e: return e return None def fetch_data(self, query, params=None): try: self.cursor.execute(query, params) if "limit" not in query.lower(): return self.cursor.fetchmany(self.max_limit), None else: return self.cursor.fetchall(), None except Exception as e: logger.critical(e) self.connection.rollback() return None, e def fetch_schema_details(self): #Creating ddl from table schema table_metadata = [] schema_ddl = [] table_schemas=self._fetch_table_schema() if len(table_schemas) != 0 : for table, columns in table_schemas.items(): table_ddl = "" schema = { "table_id": str(uuid.uuid4()), "table_name": table, "description": "", "columns": [] } fields= [] table_ddl = f"\n\nCREATE TABLE {table}" # logger.info(f"columns:{columns}") for column in columns: fields.append({ "column_id" : str(uuid.uuid4()), "column_name": column['column_name'], "column_type": column['data_type'], "description": "", }) table_ddl +=f"\n{column['column_name']} {column['data_type']} {column['character_maximum_length']}," table_ddl +=f");" schema["columns"] = fields table_metadata.append(schema) schema_ddl.append(table_ddl) return schema_ddl, table_metadata def create_ddl_from_metadata(self,table_metadata): schema_ddl = [] for table in table_metadata: tmp = f"\n\nCREATE TABLE {table['table_name']}" for field in table["columns"]: tmp = f"{tmp} {field.get('column_name','')} \n" schema_ddl.append(tmp) return schema_ddl def select_all_from_table(self, table_name): query = sql.SQL("SELECT * FROM {}").format(sql.Identifier(table_name)) return self.fetch_data(query) def _fetch_table_schema(self): # Execute query to get all table names in the public schema self.cursor.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'") # Fetch all table names table_names = self.cursor.fetchall() table_schemas = {} for table in table_names: # logger.info(f"table_name:{table['table_name']}") self.cursor.execute(f"SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = '{table['table_name']}'") columns = self.cursor.fetchall() table_schemas[table['table_name']] = columns return table_schemas def fetch_feedback(self): sql_query = "SELECT chat_query, feedback_json FROM public.chat_histories WHERE feedback_status = 2 AND created_at >= CURRENT_DATE - INTERVAL '7 days';" result = self.fetch_data(sql_query) logger.info(result) return result def validate(self,formated_sql): #validate sql using SQLParser queries = sqlparse.split(formated_sql) query = queries[0] formated_query = sqlparse.format(query, reindent=True, keyword_case='upper') parsed = sqlparse.parse(formated_query)[0] if parsed.get_type() != 'SELECT': return "Sorry, I am not designed for data manipulation operations" token_names = [p._get_repr_name() for p in parsed.tokens] if "DDL" in token_names: return "Sorry, I am not designed for data manipulation operations" sql_query = sqlvalidator.parse(formated_sql) if not sql_query.is_valid(): logger.info(sql_query.is_valid()) return "I didn't get you, Please reframe your question" return None def close_connection(self): self.cursor.close() self.connection.close() ================================================ FILE: app/plugins/sqlite/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'sqlite' __display_name__ = "SQLite DB" __description__ = 'SQLite integration for handling SQLite database operations.' __icon__ = '/assets/plugins/logos/sqlite.svg' __category__ = 2 # Connection arguments __connection_args__ = OrderedDict( db_name = ConnectionArgument( type = 1, generic_name= 'Sqlite Database Name', description = 'Database name', order= 1, required = True, value = None, slug = "db_name" ), ) # Prompt __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are an Sqlite expert. Your job is to answer questions about a Sqlite database using only the provided schema details and rules. go through the schema details given below -- start db schema section-- {schema} -- end db schema section-- A brief description about the schema is given below -- start db context section-- {context} -- end db context section-- Sample sql queries with their questions are given below -- start query samples section-- $suggestions -- end query samples section-- Adhere to the given rules without failure -- start rules section -- - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`. - use LIKE operator with LOWER function for string comparison or equality - Always use alias/table name for fields in WHERE condition - Do not use non existing tables or fields - id columns are mandatory for all operations - Do not use JSON_BUILD_OBJECT operation - Do not use unwanted joins - Do not return incomplete queries - Adher to sqlite query syntax -- end rules section -- """ }, "user_prompt":{ "template": """ Follow these steps to generate query to solve the question `$question` 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Do only the task asked, Don't hallucinate and overdo the task 4. Strictly return all the fields in the schema during listing operations 5. Strictly return at least 1 text fields and an id field during aggregation/group by operations 6. Generate a query to solve the problem using the schema, context, and strictly follow the rules 7. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "sqlite query", "operation_kind" : "aggregation|list", "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "x-axis": ["fields that can be used as x axis"], "y-axis": ["fields that can be used as y axis"], "title": "layout title name" }, "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ }, "regeneration_prompt": { "template": """ You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]` [question] $question [/question] You generated this query given in `[query][/query]` [query] {query_generated} [/query] But upon execution you encountered some error , error traceback is given in [query_error][/query_error] [query_error] {exception_log} [/query_error] Follow these steps to generate the query 1. Deliberately go through schema, context, rules deliberately 2. Understand the question and check whether it's doable with the given context 3. Use survey answers if available and include it in query for filtering values 4. Do only the task asked, Don't hallucinate and overdo the task 5. Strictly return all the fields in the schema during listing operations 6. Strictly return at least 1 text fields and an id field during aggregation/group by operations 7. Generate a query to solve the problem using the schema, context and the rules and based on the previous query try to rectify the query error 8. output in the given json format, extra explanation is strictly prohibited { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "query" : "sqlite query", "operation_kind" : "aggregation|list", "visualisation": { "type": "chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'", "value_field": "fields in which values are stored", "x-axis": "field that can be used as x axis", "y-axis": "field that can be used as y axis", "title": "layout title name" }, "schema": "used schema details separated by comma", "confidence" : "confidence in 100", "general_message": "a general message describing the answers like 'here is your list of incidents' or 'look what i found'", "main_entity" : "main entity for the query", "next_questions" : [Produce 3 related questions(maximum 8 words) aligned with the current question, db context and which can be answered with only two table . While creating questions strictly prohibit questions which tells to specify for a specific item] } """ } }) __all__ = [ __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/sqlite/formatter.py ================================================ from typing import Any from loguru import logger class Formatter: def format(self, data: Any,input) -> (dict): """ Main entry point for formatting the data based on the input parameters. Handles different formatting strategies based on operation kind. :param data: The data to format. :param input_params: Dictionary containing operation and formatting details. :return: A dictionary containing the formatted response. """ response = {} self.main_entity = input.get("main_entity") self.kind = input.get("operation_kind", "").lower() self.general_message = input.get("general_message") self.empty_message = input.get("empty_message") logger.info("Formatting output using inference for sqlite") if self.kind == "list": response = self.basic_formatter(data, input) elif self.kind == "aggregation": response = self.aggregation_formatter(data, input) else: response["data"] = data response["kind"] = "list" response.update({ "main_entity": self.main_entity, "main_format": self.kind, "role": "assistant", "content": self.general_message, "empty_message": self.empty_message, }) return response def basic_formatter(self, data: Any, input:Any) -> dict : """ Formats data as a list, handling cases for none, single, and multiple entries. :param data: The data to format. :return: A dictionary containing the formatted list response. """ logger.info("Formatting data as a list") if data is None: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "single"} else: response = {"data": data, "kind": "list"} return response def aggregation_formatter(self, data:Any, input:Any) -> dict : """ Formats data for aggregation visualisation, supporting table and chart formats. :param data: The data to format. :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type). :return: A dictionary containing the formatted aggregation response. """ logger.info("Formatting data as aggregation") visualisation = input.get("visualisation", {}) response = {} if data is None or len(data) == 0: response = {"data": [], "kind": "none"} elif len(data) == 1: response = {"data": data, "kind": "table"} else: value_fields = visualisation.get("y-axis", []) key_fields = visualisation.get("x-axis", []) title = visualisation.get("title", "") visualisaton_kind = visualisation["type"].replace(" ", "_") if visualisation["type"] is not None else "table" if visualisaton_kind.lower() in ["bar_chart", "line_chart", "pie_chart"] and len(value_fields) > 0 and len(key_fields) > 0: response["kind"] = visualisaton_kind response["data"] = data response["x"] = key_fields response["y"] = value_fields response["title"] = title else: response = {"kind": "table", "data": data} return response ================================================ FILE: app/plugins/sqlite/handler.py ================================================ import sqlite3 import pathlib import urllib from loguru import logger import sqlvalidator import sqlparse from .formatter import Formatter import uuid from app.base.base_plugin import BasePlugin from app.base.query_plugin import QueryPlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin class Sqlite(Formatter, BasePlugin, QueryPlugin, PluginMetadataMixin): def __init__(self, connector_name : str, db_name:str, db_parent_path:str=''): logger.info("Initializing datasource") super().__init__(__name__) self.connector_name = connector_name.replace(' ','_') self.params = { 'db_name': db_name, 'db_parent_path': db_parent_path, } self.connection = None # class specific self.cursor = None self.max_limit = 5 def _dict_factory(self, cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d def _path_to_uri(self, path): path = pathlib.Path(path) if path.is_absolute(): return path.as_uri() return 'file:' + urllib.parse.quote(path.as_posix(), safe=':/') def connect(self): try: db_path = pathlib.Path(self.params['db_parent_path']).joinpath(self.params['db_name']).as_posix() uri_filename = f"{self._path_to_uri(db_path)}?mode=rw" self.connection = sqlite3.connect(uri_filename, uri=True, check_same_thread=False, timeout= 8.0) self.connection.row_factory = self._dict_factory self.cursor = self.connection.cursor() logger.info("Connection to SQLite DB successful.") return True, None except sqlite3.Error as error: logger.error(f"Error connecting to SQLite DB: {error}") return False, error def healthcheck(self): try: if self.connection is None: logger.warning("Connection to SQLite DB is not established.") return False, "Connection to SQLite DB is not established." self.cursor.execute("SELECT 1;") return True, None except sqlite3.Error as error: return False, error def configure_datasource(self, init_config): logger.info("Configuring datasource") if init_config is not None and "script" in init_config: try: self.cursor.execute(init_config["script"]) self.connection.commit() except Exception as e: return e return None def fetch_data(self, query, params=None): try: params = {} if params is None else params self.cursor.execute(query, params) if "limit" not in query.lower(): return self.cursor.fetchmany(self.max_limit), None else: return self.cursor.fetchall(), None except Exception as e: logger.critical(e) self.connection.rollback() return None, e def fetch_schema_details(self): #Creating ddl from table schema table_metadata = [] schema_ddl = [] table_schemas=self._fetch_table_schema() if len(table_schemas) != 0 : for table, columns in table_schemas.items(): table_ddl = "" schema = { "table_id": str(uuid.uuid4()), "table_name": table, "description": "", "columns": [] } fields= [] table_ddl = f"\n\nCREATE TABLE {table} (" # logger.info(f"columns:{columns}") for column in columns: fields.append({ "column_id" : str(uuid.uuid4()), "column_name": column['name'], "column_type": column['type'], "description": "", }) table_ddl +=f"\n{column['name']} {column['type']} ," table_ddl +=f");" schema["columns"] = fields table_metadata.append(schema) schema_ddl.append(table_ddl) return schema_ddl, table_metadata def create_ddl_from_metadata(self,table_metadata): schema_ddl = [] for table in table_metadata: tmp = f"\n\nCREATE TABLE {table['table_name']}" for field in table["columns"]: tmp = f"{tmp} {field.get('column_name','')} \n" schema_ddl.append(tmp) return schema_ddl def _fetch_table_schema(self): # Execute query to get all table names self.cursor.execute("SELECT name FROM sqlite_master") # Fetch all table names table_names = self.cursor.fetchall() table_schemas = {} for table in table_names: # logger.info(f"table_name:{table['name']}") self.cursor.execute(f"SELECT name, type FROM pragma_table_info('{table['name']}')") columns = self.cursor.fetchall() table_schemas[table['name']] = columns return table_schemas def fetch_feedback(self): pass def validate(self,formated_sql): #validate sql using SQLParser queries = sqlparse.split(formated_sql) query = queries[0] formated_query = sqlparse.format(query, reindent=True, keyword_case='upper') parsed = sqlparse.parse(formated_query)[0] if parsed.get_type() != 'SELECT': return "Sorry, I am not designed for data manipulation operations" token_names = [p._get_repr_name() for p in parsed.tokens] if "DDL" in token_names: return "Sorry, I am not designed for data manipulation operations" sql_query = sqlvalidator.parse(formated_sql) if not sql_query.is_valid(): logger.info(sql_query.is_valid()) return "I didn't get you, Please reframe your question" return None def close_conection(self): self.cursor.close() self.connection.close() ================================================ FILE: app/plugins/website/__init__.py ================================================ from app.models.prompt import Prompt from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __plugin_name__ = 'website' __display_name__ = 'Website Loader' __description__ = 'Website integration for handling website data' __icon__ = '/assets/plugins/logos/website.svg' __category__ = 1 # Connection arguments __connection_args__ = OrderedDict( website_url= ConnectionArgument( type = 4, generic_name= 'Website URL', description = 'URL of website', order = 1, required = True, value = None, slug = "website_url" ), headers=ConnectionArgument( type= 7, generic_name= 'Headers to be used', description= 'Provide required headers', order= 2, required = False, value = {}, slug = "headers" ), depth=ConnectionArgument( type= 3, generic_name= 'Depth of scanning', description= 'Choose the depth of scanning for child URLs. Set to 0 to scan all', order= 3, required = True, value=1, slug = "depth" ) ) # Prompt __prompt__ = Prompt(**{ "base_prompt": "{system_prompt}{user_prompt}", "system_prompt": { "template": """ You are an Chatbot designed to answer user questions based only on the context given to you. Use the details enclosed in `[context][/context]` to generate answer [context] {context} [/context] Adhere to these rules while generating query: - Deliberately go through the question and context word by word to appropriately answer the question """ }, "user_prompt":{ "template": """ User question is "$question" generate a json in the following format without any formatting. { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "operation_kind" : "none", "general_message": "Answer to user question in human readable Markdown format based on the context", "confidence" : "confidence in 100", "main_entity": "document" } """ }, "regeneration_prompt": { "template": """ User question is "$question" generate a json in the following format without any formatting. { "explanation": "Explain how you finalized the sql query using the schemas and rules provided", "operation_kind" : "none", "general_message": "Answer to user question in human readable Markdown format based on the context", "confidence" : "confidence in 100", "main_entity": "document" } """ } }) __all__ = [ __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__ ] ================================================ FILE: app/plugins/website/formatter.py ================================================ from typing import Any, Dict from loguru import logger class Formatter: """ Formatter class to format the response based on the inference and data. """ def format(self, data: Dict[str, Any], inference: Dict[str, Any]) -> dict: """ Format the response using the given data and inference information. :param data: The data containing records to process. :param inference: Inference details including main entity and operation kind. :return: Formatted response dictionary. """ logger.info("Processing output using inference details") response = {} self.main_entity = inference.get("main_entity", "") self.kind = inference.get("operation_kind", "") self.general_message = inference.get("general_message", "Unable to process question, try again") response["content"] = self.general_message response["main_entity"] = self.main_entity response["main_format"] = self.kind response["role"] = "assistant" return response ================================================ FILE: app/plugins/website/handler.py ================================================ from .formatter import Formatter from loguru import logger import requests import json from app.base.base_plugin import BasePlugin from app.base.remote_data_plugin import RemoteDataPlugin from app.base.plugin_metadata_mixin import PluginMetadataMixin from typing import Tuple, Optional from app.readers.base_reader import BaseReader class Website(BasePlugin, PluginMetadataMixin,RemoteDataPlugin, Formatter): """ Website class for interacting with website data. """ def __init__(self, connector_name : str, website_url:str, depth : int = 1, headers: str = "{}"): super().__init__(__name__) self.connection = {} self.connector_name = connector_name.replace(' ','_') self.params = { 'url': website_url, "depth": depth, "headers": headers, } def connect(self): """ Mocked connection method for Website. :return: Tuple containing connection status (True/False) and an error message if any. """ return True, None def healthcheck(self)-> Tuple[bool, Optional[str]]: """ Perform a health check by checking if the Website is accessible. :return: Tuple containing the health status (True/False) and error message (if any). """ logger.info("health check for website") url = self.params["url"] headers = {} try: headers = json.loads(self.params.get("headers", "{}")) except Exception as e: return False, str("Provide valid json for headers") try: response = requests.get(url,headers=headers) if response.status_code == 200: logger.info("Website health check passed.") return True, None else: logger.error(f"Health check failed: {response.status_code} {response.text}") return False, "Failed to connect with airtable" except Exception as e: logger.exception(f"Exception during health check: {str(e)}") return False, str(e) def fetch_data(self, params=None): headers = {} try: headers = json.loads(self.params.get("headers", "{}")) except Exception as e: logger.exception(e) base_reader = BaseReader({ "type": "url", "path": [self.params.get('url')], "depth": int(self.params.get("depth", 1)), "headers": headers, }) data = base_reader.load_data() return data ================================================ FILE: app/providers/cache_manager.py ================================================ from collections import OrderedDict from app.providers.config import configs class CacheManager(object): _instance = None _cache_store = OrderedDict() _cache_limit = configs.config_cache_limit def __init__(self): raise RuntimeError("Call get_instance() instead") @classmethod def get_instance(cls): if cls._instance is None: cls._instance = cls.__new__(cls) return cls._instance def set(self, key, value): if key in self._cache_store: self._cache_store.move_to_end(key) elif len(self._cache_store) >= self._cache_limit: self._cache_store.popitem(last=False) self._cache_store[key] = value def get(self, key): return self._cache_store.get(key) def clear(self, key): if key in self._cache_store: del self._cache_store[key] cache_manager = CacheManager.get_instance() ================================================ FILE: app/providers/clustering.py ================================================ import random class Clustering: def _initialize_centroids(self,data, k): return random.sample(data, k) def _assign_clusters(self, data, centroids): clusters = [] for point in data: distances = [abs(point - centroid) for centroid in centroids] clusters.append(distances.index(min(distances))) return clusters def _recalculate_centroids(self, data, clusters, k): new_centroids = [] for i in range(k): cluster_points = [data[j] for j in range(len(data)) if clusters[j] == i] if cluster_points: new_centroids.append(sum(cluster_points) / len(cluster_points)) else: new_centroids.append(random.choice(data)) return new_centroids def _get_clustered_values(self, data, clusters, k): clustered_values = [[] for _ in range(k)] for i, point in enumerate(data): clustered_values[clusters[i]].append(point) return clustered_values def kmeans(self, data, k, max_iterations=100): if len(data) > 1: centroids = self._initialize_centroids(data, k) for _ in range(max_iterations): clusters = self._assign_clusters(data, centroids) new_centroids = self._recalculate_centroids(data, clusters, k) if new_centroids == centroids: break centroids = new_centroids clustered_values = self._get_clustered_values(data, clusters, k) # Sort clusters based on their minimum value clustered_values.sort(key=lambda cluster: (cluster[0] if cluster else float('inf'))) return clustered_values else: return [data] ================================================ FILE: app/providers/config.py ================================================ import os from typing import List from dotenv import load_dotenv from pydantic_settings import BaseSettings load_dotenv() class Configs(BaseSettings): # base ENV: str = os.getenv("ENV", "dev") API: str = "/api" PROJECT_NAME: str = "raggenie" DATABASE_URL: str = "sqlite:///raggenie.db" PROJECT_ROOT: str = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # CORS BACKEND_CORS_ORIGINS: List[str] = ["*"] # database logging_enabled: bool = os.getenv("ENABLE_FILE_LOGGING", False) inference_llm_model:str = os.getenv("INFERENCE_LLM_MODEL", "gpt") # Auth auth_enabled: bool = os.getenv("AUTH_ENABLED",False) default_username: str = os.getenv("DEFAULT_USERNAME", "Admin") client_private_key_file_path: str = os.getenv("CLIENT_PRIVATE_KEY_FILE_PATH", "app/providers/client-key-file.json") zitadel_token_url: str = os.getenv("ZITADEL_TOKEN_URL", "http://localhost:8080/oauth/v2/token") zitadel_domain: str = os.getenv("ZITADEL_DOMAIN", "http://localhost:8080") retry_limit:int = os.getenv("RETRY_LIMIT",0) application_port: int = os.getenv("APP_PORT", 8001) application_server: str = os.getenv("APP_SERVER", "http://localhost:8001") # Cache config_cache_limit: int = os.getenv("CONFIG_CACHE_LIMIT", 10) configs = Configs() ================================================ FILE: app/providers/container.py ================================================ from dependency_injector import containers, providers from app.plugins.loader import DSLoader from app.providers.clustering import Clustering from app.vectordb.loader import VectorDBLoader class Container(containers.DeclarativeContainer): config = providers.Configuration() datasources = providers.Callable(lambda config: {ds['name']: DSLoader( ds ).load_ds() for ds in config["datasources"]} if config and config.get("datasources") else None, config) vectorstore = providers.Singleton(VectorDBLoader, config = config.vector_db) clustering = providers.Singleton(Clustering) ================================================ FILE: app/providers/context_storage.py ================================================ from app.models.db import Base from app.utils.database import get_db from fastapi import Depends from sqlalchemy.orm import Session class ContextStorage: def __init__(self,db: Session=Depends(get_db)): self.session = db self.engine = self.session.get_bind() def create_table(self): Base.metadata.create_all(self.engine) def insert_data(self, data): self.session.add(data) self.session.commit() def update_data(self, model, filters, updates): self.session.query(model).filter_by(**filters).update(updates) self.session.commit() def query_data(self, model, filters=None, limit=None): query = self.session.query(model) if filters: query = query.filter_by(**filters) if limit: query = query.limit(limit) results = query.all() return results ================================================ FILE: app/providers/data_preperation.py ================================================ from loguru import logger from langchain.text_splitter import RecursiveCharacterTextSplitter class SourceDocuments: def __init__(self,schema_details, schema_configs, documentation): self.documentation = [] logger.info("Fetching schema details") self.schema_details = schema_details self.schema_configs = schema_configs self.documentation.extend(documentation) for schema_config in schema_configs: table_doc = '' table_doc = f"Table Name: {schema_config['table_name']} - {schema_config['description']}\n column are given below\n" for column in schema_config['columns']: table_doc = f"{table_doc} {column.get('column_name','')} - {column['description']}\n" self.documentation.append({'content': table_doc, 'metadata': {}}) def get_source_documents(self): chunked_docs = [] chunked_schema = [] try: text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=20,separators=["\n\n","\'\")"]) text_splitter_doc = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=20,separators=["##"]) splitted_schema = list(map(lambda item: f"'{item}'", self.schema_details)) load_schema = text_splitter.create_documents(splitted_schema) for docs in self.documentation: temp_docs = text_splitter_doc.create_documents([str(docs["content"])]) chunks = text_splitter_doc.split_documents(temp_docs) for chunk in chunks: chunk.metadata = docs["metadata"] if "metadata" in docs else {} chunked_docs.extend(chunks) chunked_schema = text_splitter.split_documents(load_schema) except Exception as e: logger.critical(e) return chunked_docs, chunked_schema ================================================ FILE: app/providers/middleware.py ================================================ from datetime import datetime, timezone import json from app.providers.zitadel import Zitadel import requests from app.utils.jwt import JWTUtils from app.providers.config import configs from fastapi import Request, status, HTTPException, Cookie from fastapi import Request, HTTPException, status from typing import Optional async def verify_token(request: Request, session_data: Optional[str] = Cookie(None)): if configs.auth_enabled: zitadel = Zitadel() try: session_data = json.loads(session_data) # This handles None and invalid JSON session_id = session_data.get("session_id") session_token = session_data.get("session_token") user_id = session_data.get("user_id") if not session_id or not session_token: raise ValueError("missing session data") response = zitadel.get_user_info(session_id) session_expiry = response.get("session").get("expirationDate") session_expiry_utc = datetime.fromisoformat(session_expiry.rstrip("Z")).replace(tzinfo=timezone.utc) now_utc = datetime.now(timezone.utc) if (session_expiry_utc - now_utc).total_seconds() < 300: zitadel.refresh_session(session_id) except (TypeError, json.JSONDecodeError, AttributeError, ValueError): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or missing session data" ) except requests.exceptions.RequestException as e: # Handles request errors (e.g., network issues, 404) raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=f"Session validation failed: {str(e)}", ) return {"session_id": session_id, "user_id": user_id} else: return {"session_id": '1', "user_id": '1', "username": configs.default_username} ================================================ FILE: app/providers/reranker.py ================================================ from sentence_transformers import CrossEncoder class Reranker: def __init__(self,model_name): self.cross_encoder = CrossEncoder(model_name) def predict(self,pairs): return self.cross_encoder.predict(pairs) ================================================ FILE: app/providers/zitadel.py ================================================ import json import requests import time from app.providers.config import configs from app.schemas.common import CommonResponse from fastapi.responses import JSONResponse, RedirectResponse from jwt import encode class Zitadel: def __init__(self): self.base_url = configs.zitadel_domain with open(configs.client_private_key_file_path, "r") as f: json_data = json.load(f) self.private_key = json_data["key"] self.kid = json_data["keyId"] self.user_id = json_data["userId"] self.token = None # Will store the access token self.token_expiry = 0 # Timestamp when token expires self._refresh_token() # Generate initial token self.headers = { "Authorization": f"Bearer {self.token}", "Content-Type": "application/json", } def _generate_jwt(self): """Generate a signed JWT.""" header = {"alg": "RS256", "kid": self.kid} payload = { "iss": self.user_id, "sub": self.user_id, "aud": configs.zitadel_domain, "iat": int(time.time()), "exp": int(time.time()) + 3600 # 1-hour expiry } return encode(payload, self.private_key, algorithm="RS256", headers=header) def _refresh_token(self): """Fetch a new OAuth access token using the JWT.""" jwt_token = self._generate_jwt() data = { "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "scope": f"openid email profile urn:zitadel:iam:org:project:id:zitadel:aud", "assertion": jwt_token } response = requests.post(configs.zitadel_token_url, data=data) if response.status_code == 200: token_data = response.json() self.token = token_data["access_token"] self.token_expiry = int(time.time()) + 3500 else: raise Exception(f"Failed to fetch access token: {response.text}") def _ensure_valid_token(self): """Ensure the token is valid, refreshing if expired.""" if time.time() >= self.token_expiry: self._refresh_token() self.headers["Authorization"] = f"Bearer {self.token}" def create_user_session(self , user_id: str, idp_intent_id: str, token: str): """ create session for a user and sets the session cookie.""" self._ensure_valid_token() try: response = requests.post( f"{self.base_url}/v2/sessions", json={ "checks": { "user": { "userId": user_id }, "idpIntent": { "idpIntentId": idp_intent_id, "idpIntentToken": token } }, "lifetime": "1800.000000000s" }, headers=self.headers ) response.raise_for_status() session_data = response.json() session_id = session_data.get("sessionId") session_token = session_data.get("sessionToken") if not session_id or not session_token: return JSONResponse( status_code=500, content={"error": "Session ID or token not found in response"} ) json_response = JSONResponse( status_code=201, content={"message": "Session created successfully", "session_id": session_id, "user_id": user_id}, ) json_response.set_cookie( key="session_data", value=json.dumps({"session_id": session_id, "session_token": session_token, "user_id": user_id}), httponly=True, secure=False, samesite="Lax", max_age=1800, path="/", ) return json_response except requests.RequestException as e: return JSONResponse( status_code=500, content={ "error": "Failed to create session", "details": str(e) } ) def create_user(self, user_data: dict, idp_intent_id: str, token: str): """ Create a user from IDP authentication data """ # ONLY WORKS WITH GOOGLE IDP AUTHENTICATION DATA NOW NEED TO MAKE MODIFICATION self._ensure_valid_token() idp_info = user_data.get("idpInformation", {}) raw_info = idp_info.get("rawInformation", {}) user_info = raw_info.get("User", {}) payload = { "username": user_info.get("email", ""), "profile": { "givenName": user_info.get("given_name", ""), "familyName": user_info.get("family_name", ""), "displayName": user_info.get("name", "") }, "email": { "email": user_info.get("email", ""), "isVerified": user_info.get("email_verified", False), }, "idpLinks": [ { "idpId": idp_info.get("idpId"), "userId": idp_info.get("userId"), "userName": user_info.get("name", "") } ], } try: response = requests.post( f"{self.base_url}/v2/users/human", json=payload, headers=self.headers ) response.raise_for_status() created_user_data = response.json() user_id = created_user_data.get("userId") if not user_id: return JSONResponse( status_code=500, content={"error": "User creation failed"} ) return self.create_user_session(user_id, idp_intent_id, token) except requests.RequestException as e: return JSONResponse( status_code=500, content={"error": "Failed to create user", "details": str(e)} ) def redirect_to_idp(self, idp_id: int): """ Generate an authentication url for idp login and redirect user to the url """ # need to set successurl and failureUrl domain dynamically ***** self._ensure_valid_token() try: response = requests.post( f"{self.base_url}/v2/idp_intents", json={ "idpId": f"{idp_id}", "urls": { "successUrl": f"{configs.application_server}/api/v1/auth/idp/success", "failureUrl": f"{configs.application_server}/ui/login" } }, headers=self.headers ) response.raise_for_status() auth_url = response.json().get('authUrl') if auth_url: return RedirectResponse(url=auth_url) return JSONResponse(status_code=400, content={"error": "authUrl not found"}) except requests.exceptions.RequestException as e: return JSONResponse( status_code=500, content={"error": "Failed to retrieve IDP auth URL", "details": str(e)} ) def get_user_info(self, session_id: int): """ get user info from the current session """ # need to add error handling when there is no userinfo retreived from the # session self._ensure_valid_token() try: response = requests.get( f"{self.base_url}/v2/sessions/{session_id}", headers=self.headers ) response.raise_for_status() session_info = response.json() return session_info except requests.exceptions.RequestException as e: return CommonResponse( status=False, status_code=500, message="User info retrieval failed", data=None, error=str(e), ) def get_idp_intent_data(self,idp_intent_id: int, idp_token: str): self._ensure_valid_token() try: response = requests.post( f"{self.base_url}/v2/idp_intents/{idp_intent_id}", json={"idpIntentToken": idp_token}, headers=self.headers ) response.raise_for_status() return response except requests.exceptions.RequestException as e: return JSONResponse( status_code=500, content={"error": "Failed to fetch user data with idp_intend_id", "details": str(e)} ) def list_idp_providers(self): self._ensure_valid_token() try: response = requests.post( f"{self.base_url}/management/v1/idps/templates/_search", json={ "query": { "offset": "0", "limit": 100, "asc": True } }, headers=self.headers ) response.raise_for_status() idp_data = response.json() idp_list = [{"id" : item.get('id'), "type" : item.get('type')} for item in idp_data.get('result', [])] return { "idp_list" : idp_list } except requests.exceptions.RequestException as e: return {"error": "Failed to retrieve identity provider info", "details": str(e)}, 500 def login_with_username_password(self, username: str, password: str): """Login user with username and password.""" self._ensure_valid_token() try: response = requests.post( f"{self.base_url}/v2/sessions", json={ "checks": { "user": { "loginName": username } } }, headers=self.headers, ) response.raise_for_status() session_data = response.json() session_id = session_data.get("sessionId") session_token = session_data.get("sessionToken") validate_response = requests.patch( f"{self.base_url}/v2/sessions/{session_id}", json={ "checks": { "password": { "password": password } }, "lifetime": "1800.000000000s" }, headers=self.headers, ) validate_response.raise_for_status() user_info = self.get_user_info(session_id) user_id = user_info.get("session").get("factors").get("user").get("id") username = user_info.get("session").get("factors").get("user").get("displayName") json_response = JSONResponse( status_code=201, content={"message": "Session created successfully", "session_id": session_id, "user_id": user_id, "username": username}, ) json_response.set_cookie( key="session_data", value=json.dumps({"session_id": session_id, "session_token": session_token, "user_id": user_id}), httponly=True, secure=False, samesite="Lax", max_age=1800, path="/", ) return json_response except requests.RequestException as e: return JSONResponse( status_code=500, content={ "error": "Failed to create session", "details": str(e) } ) def logout_user(self, session_id: str): """Logout user by deleting the session.""" self._ensure_valid_token() try: response = requests.delete( f"{self.base_url}/v2/sessions/{session_id}", headers=self.headers, ) response.raise_for_status() return CommonResponse( status=True, status_code=response.status_code, message="Logout Successful" if response.status_code == 200 else "Logout Unsuccessful", data=response.json(), error=None, ) except requests.RequestException as e: return CommonResponse( status=False, status_code=500, message="Logout Failed", data=None, error=str(e), ) ================================================ FILE: app/readers/base_reader.py ================================================ from app.readers.text_reader import TxtLoader from app.readers.docx_reader import DocxReader from app.readers.yaml_reader import YamlLoader from app.readers.url_reader import UrlReader from app.readers.pdf_reader import PDFLoader from loguru import logger class BaseReader: def __init__(self, source): logger.info(f"initializing docs {source}") self.source = source def load_data(self): type = self.source["type"] if "type" in self.source else "" match type: case "text": loader = TxtLoader(source=self.source) case "yaml": loader = YamlLoader(source=self.source) case "docx": loader = DocxReader(source=self.source) case "url": loader = UrlReader(source=self.source) case "pdf": loader = PDFLoader(source=self.source) case _: raise ValueError(f"Documentation in given format '{type}' not supported.") return loader.load() ================================================ FILE: app/readers/docs_reader.py ================================================ class DocsReader: def __init__(self, source): self.source = source def load(self): raise NotImplementedError("load method must be implemented in subclass") ================================================ FILE: app/readers/docx_reader.py ================================================ from app.readers.docs_reader import DocsReader from loguru import logger # import textract class DocxReader(DocsReader): def load(self): out = [] if "path" in self.source: paths = self.source["path"] for path in paths: try: # text = textract.process(path) text = "" metadata = { "path": path } out.append({"content": str(text), "metadata": metadata}) except Exception as e: logger.error(e) return out ================================================ FILE: app/readers/pdf_reader.py ================================================ from app.readers.docs_reader import DocsReader from loguru import logger from docling.document_converter import DocumentConverter, PdfFormatOption from docling.datamodel.base_models import InputFormat from docling.datamodel.pipeline_options import PdfPipelineOptions, RapidOcrOptions from docling.backend.docling_parse_v4_backend import DoclingParseV4DocumentBackend pipeline_options = PdfPipelineOptions() pipeline_options.ocr_options = RapidOcrOptions() pipeline_options.do_ocr = True pipeline_options.do_table_structure = True pipeline_options.table_structure_options.do_cell_matching = True converter = DocumentConverter( format_options={ InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options, backend=DoclingParseV4DocumentBackend) } ) class PDFLoader(DocsReader): def load(self): out = [] if "path" in self.source: paths = self.source["path"] for path in paths: try: metadata = {"path":path} result = converter.convert(path) temp = {} temp["content"] = result.document.export_to_markdown() temp["metadata"] = metadata if len(temp["content"]) > 0: out.append(temp) except Exception as e: logger.error(e) return out ================================================ FILE: app/readers/text_reader.py ================================================ from app.readers.docs_reader import DocsReader from loguru import logger class TxtLoader(DocsReader): def load(self): out = [] if "path" in self.source: paths = self.source["path"] for path in paths: try: metadata = {"path":path} temp = {} with open(path, 'r', encoding='utf-8') as file: content = file.read() temp["content"] = str(content) temp["metadata"] = metadata out.append(temp) except Exception as e: logger.error(e) elif "value" in self.source: if self.source["value"] is not None: out.append( { "content": self.source["value"], "metadata": { } } ) return out ================================================ FILE: app/readers/url_reader.py ================================================ from app.readers.docs_reader import DocsReader from loguru import logger import requests from bs4 import BeautifulSoup from urllib.parse import urljoin from typing import Dict from urllib.parse import urlparse class UrlReader(DocsReader): def __init__(self, source): self.source = source self.visited_url = set() def load(self): out = [] max_depth = self.source.get("depth", 1) depth_map: Dict[str, int] = {} url_queue = [] if "path" in self.source: urls = self.source["path"] for url in urls: url_queue.append(url) depth_map[url] = 1 base_domain = urlparse(urls[0]).netloc while url_queue : url = url_queue.pop(0) current_depth = depth_map.get(url, 1) logger.info(f"scanning url {url}") if url in self.visited_url or current_depth > max_depth: continue logger.info(f"urls in queue {len(url_queue)} visited {len(self.visited_url)}") self.visited_url.add(url) try: response = requests.get(url, headers=self.source.get("headers", {})) if response.status_code == 200: soup = BeautifulSoup(response.content, 'html.parser') for a in soup.find_all('a', href = True) : absolute_url = urljoin(url, a['href']) if absolute_url not in self.visited_url and urlparse(absolute_url).netloc == base_domain and absolute_url not in url_queue: if current_depth + 1 <= max_depth or max_depth == 0: url_queue.append(absolute_url) depth_map[absolute_url] = current_depth + 1 tag = soup.body text = ''.join(list(tag.strings)[:-1]) metadata = { "path": url } out.append({"content": str(text), "metadata": metadata}) else: logger.critical(f"Failed to retrieve content, status code: {response.status_code}") except Exception as e: logger.error(e) return out ================================================ FILE: app/readers/yaml_reader.py ================================================ from app.readers.docs_reader import DocsReader from loguru import logger import yaml class YamlLoader(DocsReader): def load(self): out = [] if "path" in self.source: paths = self.source["path"] for path in paths: try: metadata = {"path":path} temp = {} with open(path, 'r', encoding='utf-8') as file: content = file.read() body = yaml.safe_load(content) temp["content"] = yaml.dump(body) temp["metadata"] = metadata out.append(temp) except Exception as e: logger.error(e) return out ================================================ FILE: app/repository/connector.py ================================================ from sqlalchemy.orm import Session, joinedload import app.models.connector as models import app.models.provider as prov_models import app.schemas.connector as schemas from sqlalchemy.exc import SQLAlchemyError from typing import List from app.models.environment import UserEnvironmentMapping def get_connectors_by_configuration_id(configuration_id: int, db: Session): try: connectors = ( db.query(models.Connector) .join(models.ConfigurationConnectorMapping, models.Connector.id == models.ConfigurationConnectorMapping.connector_id) .filter(models.ConfigurationConnectorMapping.configuration_id == configuration_id) .all() ) return connectors, False except Exception as e: return None, str(e) def get_all_connectors(db: Session, user_id: str): try: active_env = (db.query(UserEnvironmentMapping) .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True) .first()) connectors = ( db.query(models.Connector) .filter(models.Connector.environment_id == active_env.id) .options(joinedload(models.Connector.provider)) .all() ) return connectors, False except SQLAlchemyError as e: return str(e), True def get_connector_by_id(connector_id: int, db: Session): try: return db.query(models.Connector).options(joinedload(models.Connector.provider)).filter(models.Connector.id == connector_id).first(), False except SQLAlchemyError as e: return str(e), True def create_new_connector(connector: schemas.ConnectorBase, db: Session, user_id: str): try: active_env = (db.query(UserEnvironmentMapping) .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True) .first()) db_connector = models.Connector(**connector.model_dump(),environment_id=active_env.id) db.add(db_connector) db.commit() db.refresh(db_connector) return db_connector, False except SQLAlchemyError as e: db.rollback() return str(e), True def update_existing_connector(connector_id: int, connector: schemas.ConnectorUpdate, db: Session): try: db_connector = db.query(models.Connector).filter(models.Connector.id == connector_id).first() if db_connector: for key, value in connector.model_dump(exclude_unset=True).items(): setattr(db_connector, key, value) db.commit() db.refresh(db_connector) return db_connector, False except SQLAlchemyError as e: db.rollback() return str(e), True def update_schemas(connector_id: int, connector: schemas.ConnectorUpdate, db: Session): try: db_connector = db.query(models.Connector).filter(models.Connector.id == connector_id).first() if db_connector and connector.schema_config: db_connector.schema_config = connector.schema_config db.commit() db.refresh(db_connector) return db_connector, False except SQLAlchemyError as e: db.rollback() return str(e), True def delete_connector_by_id(connector_id: int, db: Session): try: db_connector = db.query(models.Connector).filter(models.Connector.id == connector_id).first() if db_connector: db.delete(db_connector) db.commit() return db_connector, False except SQLAlchemyError as e: db.rollback() return str(e), True def get_all_configurations(db: Session, user_id: str): try: active_env = (db.query(UserEnvironmentMapping) .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True) .first()) return ( db.query(models.Configuration) .filter(models.Configuration.environment_id == active_env.id) .options( joinedload(models.Configuration.capabilities), joinedload(models.Configuration.inference_mapping).joinedload(models.Inferenceconfigmapping.inference), joinedload(models.Configuration.vectordb_config_mapping).joinedload(prov_models.VectorDBConfigMapping.vector_db), joinedload(models.Configuration.connectors).joinedload(models.ConfigurationConnectorMapping.connector) ) .all(), False ) except SQLAlchemyError as e: return str(e), True def get_inference_by_config(config_id: int, db: Session): """ Retrieves the Inference based on the config_id, using joinedload to load related data. Args: config_id (int): The configuration ID to query. db (Session): Database session object. Returns: Tuple: Inference instance, error message (if any). """ try: result = db.query(models.Inferenceconfigmapping).options(joinedload(models.Inferenceconfigmapping.inference)).options(joinedload(models.Inferenceconfigmapping.configuration)).filter(models.Inferenceconfigmapping.config_id == config_id).first() if result: return result.inference, False else: return None, "Inference not found for the given config_id" except SQLAlchemyError as e: db.rollback() return None, str(e) def getbotconfiguration(db:Session): try: return ( db.query(models.Configuration).filter(models.Configuration.status == 2).first() ), False except SQLAlchemyError as e: return str(e), True def create_new_configuration(configuration: schemas.ConfigurationCreation, db: Session, user_id: str): try: active_env = (db.query(UserEnvironmentMapping) .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True) .first()) db_configuration = models.Configuration( name=configuration.name, short_description=configuration.short_description, long_description=configuration.long_description, status=configuration.status, environment_id=active_env.id ) db.add(db_configuration) db.commit() db.refresh(db_configuration) for capability_id in configuration.capabilities: db_capability = db.query(models.Capabilities).get(capability_id) if db_capability: db_capability.config_id = db_configuration.id db.add(db_capability) db.commit() if configuration.connectors: link_configuration_to_connectors(db_configuration.id, configuration.connectors, db) return db_configuration, False except SQLAlchemyError as e: db.rollback() return str(e), True def link_configuration_to_connectors(config_id: int, connector_ids: list[int], db: Session): """ Links a configuration with selected connectors. """ try: for connector_id in connector_ids: existing_mapping = ( db.query(models.ConfigurationConnectorMapping) .filter_by(configuration_id=config_id, connector_id=connector_id) .first() ) if not existing_mapping: mapping = models.ConfigurationConnectorMapping(configuration_id=config_id, connector_id=connector_id) db.add(mapping) db.commit() return True, None except SQLAlchemyError as e: db.rollback() return False, str(e) def update_existing_configuration(config_id: int, configuration: schemas.ConfigurationUpdate, db: Session): try: db_configuration = db.query(models.Configuration).filter(models.Configuration.id == config_id).first() if db_configuration is None: return None, True db_configuration.name = configuration.name if configuration.name else db_configuration.name db_configuration.short_description = configuration.short_description if configuration.short_description else db_configuration.short_description db_configuration.long_description = configuration.long_description if configuration.long_description else db_configuration.long_description db_configuration.status = configuration.status if configuration.status else db_configuration.status db.commit() db.refresh(db_configuration) if configuration.capabilities is not None: db.query(models.Capabilities).filter(models.Capabilities.config_id == config_id).update( {models.Capabilities.config_id: None}, synchronize_session=False ) db.commit() for capability_id in configuration.capabilities: query = db.query(models.Capabilities).filter(models.Capabilities.id == capability_id).first() if query: query.config_id = config_id db.add(query) db.commit() db.refresh(query) if configuration.connectors is not None: """ fetch existing connector mapping """ existing_connector_ids = { mapping.connector_id for mapping in db.query(models.ConfigurationConnectorMapping) .filter(models.ConfigurationConnectorMapping.configuration_id == config_id) .all() } new_connector_ids = set(configuration.connectors) connectors_to_remove = existing_connector_ids - new_connector_ids if connectors_to_remove: db.query(models.ConfigurationConnectorMapping).filter( models.ConfigurationConnectorMapping.configuration_id == config_id, models.ConfigurationConnectorMapping.connector_id.in_(connectors_to_remove) ).delete(synchronize_session=False) db.commit() connector_to_add = new_connector_ids - existing_connector_ids if connector_to_add: link_configuration_to_connectors(db_configuration.id, connector_to_add, db) return db_configuration, False except SQLAlchemyError as e: db.rollback() return str(e), True def get_configuration_by_id(config_id: int, db: Session): try: return ( db.query(models.Configuration) .filter(models.Configuration.id == config_id) .options( joinedload(models.Configuration.capabilities), joinedload(models.Configuration.inference_mapping).joinedload(models.Inferenceconfigmapping.inference), joinedload(models.Configuration.vectordb_config_mapping).joinedload(prov_models.VectorDBConfigMapping.vector_db), joinedload(models.Configuration.connectors).joinedload(models.ConfigurationConnectorMapping.connector) # 🔹 Include connectors ) .first(), False ) except SQLAlchemyError as e: return str(e), True def delete_configuration_by_id(configuration_id: int, db: Session): try: db_configuration = db.query(models.Configuration).filter(models.Configuration.id == configuration_id).options(joinedload(models.Configuration.capabilities)).first() if db_configuration: db.delete(db_configuration) db.commit() return db_configuration, False except SQLAlchemyError as e: db.rollback() return str(e), True def update_configuration_status(config_id: int,status: int, db: Session): try: db_config, is_error = get_configuration_by_id(config_id, db) if db_config and not is_error: db_config.status = status db.commit() db.refresh(db_config) return db_config, False else: return None, True except (SQLAlchemyError, ValueError) as e: db.rollback() return str(e), True def default_configuration_status(db: Session): try: db.query(models.Configuration).filter( models.Configuration.status == 2 ).update({"status": 1}) db.commit() return True, False except (SQLAlchemyError, ValueError) as e: db.rollback() return str(e), True def create_capability(capability: schemas.CapabilitiesBase, db: Session): try: new_capability = models.Capabilities( name=capability.name, description=capability.description, requirements=capability.requirements, config_id=capability.config_id if capability.config_id else None, enable=True ) db.add(new_capability) db.commit() db.refresh(new_capability) return new_capability, False except SQLAlchemyError as e: db.rollback() return str(e), True def create_capability_action_mappings(capability_id: int, action_ids: List[int], db: Session): try: for action_id in action_ids: mapping = models.CapActionsMapping( capability_id=capability_id, action_id=action_id, enable=True ) db.add(mapping) db.commit() return True, False # Successful creation, no error except SQLAlchemyError as e: db.rollback() return str(e), True # Error occurred def get_all_capabilities(db: Session): try: capabilities = db.query(models.Capabilities).options( joinedload(models.Capabilities.cap_actions_mapping).joinedload(models.CapActionsMapping.actions) ).all() return capabilities, False except SQLAlchemyError as e: return str(e), True def update_capability(cap_id: int, capability: schemas.CapabilitiesUpdateBase, db: Session): try: capability_record = db.query(models.Capabilities).filter(models.Capabilities.id == cap_id).first() if capability_record: capability_record.name = capability.name if capability.name else capability_record.name capability_record.description = capability.description if capability.description else capability_record.description capability_record.requirements = capability.requirements if capability.requirements else capability_record.requirements capability_record.config_id = capability.config_id if capability.config_id else capability_record.config_id if capability.actions_list: db.query(models.CapActionsMapping).filter(models.CapActionsMapping.capability_id == cap_id).delete() for action_id in capability.actions_list: new_mapping = models.CapActionsMapping( capability_id=cap_id, action_id=action_id, enable=True ) db.add(new_mapping) db.commit() db.refresh(capability_record) return capability_record, False return None, True except SQLAlchemyError as e: db.rollback() return str(e), True def delete_capability(cap_id: int, db: Session): try: capability_record = db.query(models.Capabilities).filter(models.Capabilities.id == cap_id).first() if capability_record: db.query(models.CapActionsMapping).filter(models.CapActionsMapping.capability_id == cap_id).delete() db.delete(capability_record) db.commit() return True, False return False, True except SQLAlchemyError as e: db.rollback() return str(e), True def get_inference_by_id(inference_id: int, db: Session): try: return db.query(models.Inference).filter(models.Inference.id == inference_id).first(), False except SQLAlchemyError as e: return str(e), True def create_inference(inference: schemas.InferenceBase, db: Session): try: db_inference = models.Inference( name=inference.name, apikey=inference.apikey, llm_provider=inference.llm_provider, model=inference.model, endpoint=inference.endpoint ) db.add(db_inference) db.commit() db.refresh(db_inference) db_mapping = models.Inferenceconfigmapping( inference_id=db_inference.id, config_id=inference.config_id, enable=True ) db.add(db_mapping) db.commit() db.refresh(db_inference) return db_inference, False except SQLAlchemyError as e: db.rollback() return str(e), True def update_inference(inference_id: int, inference: schemas.InferenceBaseUpdate, db: Session): try: db_inference = db.query(models.Inference).filter(models.Inference.id == inference_id).first() if db_inference is None: return "Data is None", True db_inference.name = inference.name if inference.name else db_inference.name db_inference.apikey = inference.apikey if inference.apikey else db_inference.apikey db_inference.llm_provider = inference.llm_provider if inference.llm_provider else db_inference.llm_provider db_inference.model = inference.model if inference.model else db_inference.model db_inference.endpoint = inference.endpoint if inference.endpoint else db_inference.endpoint db.commit() db.refresh(db_inference) if inference.config_id: db_mapping = db.query(models.Inferenceconfigmapping).filter(models.Inferenceconfigmapping.inference_id == inference_id).first() if db_mapping: db_mapping.config_id = inference.config_id else: db_mapping = models.Inferenceconfigmapping( inference_id=inference_id, config_id=inference.config_id, enable=True ) db.add(db_mapping) db.commit() db.refresh(db_mapping) return db_inference, False except SQLAlchemyError as e: db.rollback() return str(e), True def get_inferences_by_config_id(config_id: int, db: Session): try: return db.query(models.Inferenceconfigmapping).options(joinedload(models.Inferenceconfigmapping.inference)).filter(models.Inferenceconfigmapping.config_id == config_id).all(), False except SQLAlchemyError as e: return str(e), True def list_actions(db:Session): try: return db.query(models.Actions).all(), False except SQLAlchemyError as e: return str(e), def get_action_by_id(action_id:int, db:Session): try: return db.query(models.Actions).filter(models.Actions.id == action_id).first(), False except SQLAlchemyError as e: return str(e), def get_actions_by_connector(connector_id:int, db:Session): try: return db.query(models.Actions).filter(models.Actions.connector_id == connector_id).all(), False except SQLAlchemyError as e: return str(e), True def create_action(action:schemas.Actions, db:Session): try: db_action = models.Actions( name=action.name, description=action.description if action.description else None, types=action.types, connector_id = action.connector_id, condition = action.condition if action.condition else None, table = action.table if action.table else None, body = action.body ) db.add(db_action) db.commit() db.refresh(db_action) return db_action, False except SQLAlchemyError as e: db.rollback() return str(e), True def update_action(action_id: int, action: schemas.ActionsUpdate, db: Session): try: db_action = db.query(models.Actions).filter(models.Actions.id == action_id).first() if db_action is None: return "Data is None", True db_action.name = action.name if action.name else db_action.name db_action.description = action.description if action.description else db_action.description db_action.types = action.types if action.types else db_action.types db_action.connector_id = action.connector_id if action.connector_id else db_action.connector_id db_action.condition = action.condition if action.condition else db_action.condition db_action.table = action.table if action.table else db_action.table db_action.body = action.body if action.body else db_action.body db.commit() db.refresh(db_action) return db_action, False except SQLAlchemyError as e: db.rollback() return str(e), True def delete_action_by_id(action_id: int, db: Session): try: db_action = db.query(models.Actions).filter(models.Actions.id == action_id).first() if db_action is None: return "Data is None", True db.delete(db_action) db.commit() return True, False except SQLAlchemyError as e: db.rollback() return str(e), True ================================================ FILE: app/repository/environment.py ================================================ from sqlalchemy.orm import Session import app.models.environment as models import app.schemas.environment as schemas from sqlalchemy.exc import SQLAlchemyError def create_environment(name: str, db: Session): """ creates a new environment with a given name""" new_env = models.Environment(name=name) db.add(new_env) db.commit() db.refresh(new_env) return new_env def get_or_create_default_environment(db: Session): default_env = db.query(models.Environment).filter(models.Environment.name == "Default Environment").first() if not default_env: default_env = models.Environment(name="Default Environment", is_active=True) db.add(default_env) db.commit() db.refresh(default_env) return default_env def assign_user_to_environment(user_id: int, environment_id: int, db: Session): try: user_env_mapping = models.UserEnvironmentMapping(user_id=user_id, environment_id=environment_id, is_active=True) db.add(user_env_mapping) db.commit() return user_env_mapping, None except SQLAlchemyError as e: db.rollback() return None, str(e) def get_current_env_id(user_id: int, db: Session): try: active_env = (db.query(models.UserEnvironmentMapping) .filter(models.UserEnvironmentMapping.user_id == user_id, models.UserEnvironmentMapping.is_active == True) .first()) return active_env.id, None except SQLAlchemyError as e: return None, str(e) ================================================ FILE: app/repository/llmchat.py ================================================ from sqlalchemy.orm import Session from app.models.llmchat import ChatHistory from app.schemas import llmchat as schemas from sqlalchemy.exc import SQLAlchemyError def get_chat_by_context_and_id(chat_context_id: str, chat_id: int, db: Session): try: chat = db.query(ChatHistory).filter(ChatHistory.chat_context_id == chat_context_id, ChatHistory.chat_id == chat_id).first() return chat, False except SQLAlchemyError as e: return e, True def create_new_chat(chat: schemas.ChatHistoryCreate, db: Session): try: existing_chat = db.query(ChatHistory).filter(ChatHistory.chat_context_id == chat.chat_context_id).first() chat.primary_chat=existing_chat is None db_chat = ChatHistory( **chat.model_dump() ) db.add(db_chat) db.commit() db.refresh(db_chat) return db_chat, False except SQLAlchemyError as e: db.rollback() return str(e), True # based on feedback def update_chat_feedback(feedback: schemas.FeedbackCreate, db: Session): chat, is_error = get_chat_by_context_and_id(feedback.chat_context_id, feedback.chat_id, db) if is_error: return chat, True if not chat: return None, False chat.feedback_status = feedback.feedback_status chat.feedback_json = feedback.feedback_json try: db.commit() db.refresh(chat) return chat, False except SQLAlchemyError as e: return e, True def get_primary_chat(env_id: int, db: Session): try: data = db.query(ChatHistory).filter(ChatHistory.primary_chat == True, ChatHistory.environment_id == env_id).distinct(ChatHistory.chat_context_id).all() return data, False except SQLAlchemyError as e: return e, True def get_all_chats_by_context_id(context_id: str, db: Session): try: data = db.query(ChatHistory).filter(ChatHistory.chat_context_id == context_id).all() return data, False except SQLAlchemyError as e: return e, True ================================================ FILE: app/repository/provider.py ================================================ from sqlalchemy.orm import Session import app.models.provider as models import app.models.connector as conn_model from sqlalchemy.orm import joinedload from sqlalchemy.exc import SQLAlchemyError from typing import Any, Dict import app.schemas.provider as schemas from app.models.environment import UserEnvironmentMapping def insert_or_update_data(db: Session, model: Any, filters: Dict[str, Any], data: Dict[str, Any]) -> tuple: try: existing_record = db.query(model).filter_by(**filters).first() if existing_record: for key, value in data.items(): setattr(existing_record, key, value) db.commit() db.refresh(existing_record) return existing_record, False else: new_record = model(**data) db.add(new_record) db.commit() db.refresh(new_record) return new_record, False except SQLAlchemyError as e: db.rollback() db.expunge_all() return str(e), True def get_all_providers(db: Session): try: return db.query(models.Provider).options(joinedload(models.Provider.providerconfig)).all(), False except SQLAlchemyError as e: return e, True def get_provider_by_id(provider_id: int, db: Session): try: provider = db.query(models.Provider).options(joinedload(models.Provider.providerconfig)).filter(models.Provider.id == provider_id).first() return provider, False except SQLAlchemyError as e: return e, True def get_vector_db_config(db: Session, key: str): try: return db.query(models.VectorDBConfig).filter(models.VectorDBConfig.key==key).first(), False except SQLAlchemyError as e: return e, True def get_vectordb_providers(db:Session): try: return db.query(models.VectorDBConfig).all(), False except SQLAlchemyError as e: return e, True def get_config_types(provider_id: int, db:Session): try: return db.query(models.ProviderConfig).filter(models.ProviderConfig.provider_id==provider_id).all(), False except SQLAlchemyError as e: return e, True def get_sql_by_connector(id:int, db:Session): try: return db.query(models.SampleSQL).filter(models.SampleSQL.connector_id == id).all(), False except SQLAlchemyError as e: return e, True def list_sql(db:Session, user_id: str): try: active_env = (db.query(UserEnvironmentMapping) .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True) .first()) sql = ( db.query(models.SampleSQL) .filter(models.SampleSQL.environment_id == active_env.id) .all() ) return sql, False except SQLAlchemyError as e: return e, True def get_sql(id:int,db:Session): try: return db.query(models.SampleSQL).filter(models.SampleSQL.id == id).first(), False except SQLAlchemyError as e: return e, True def create_sql(sql:schemas.SampleSQLBase, db:Session, user_id: str): try: active_env = (db.query(UserEnvironmentMapping) .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True) .first()) db_sql = models.SampleSQL( description=sql.description, sql_metadata=sql.sql_metadata, connector_id = sql.connector_id, environment_id = active_env.id ) db.add(db_sql) db.commit() db.refresh(db_sql) return db_sql, False except SQLAlchemyError as e: db.rollback() return str(e), True def update_sql(sql_id:int, sql:schemas.SampleSQLUpdate, db:Session): try: db_sql = db.query(models.SampleSQL).filter(models.SampleSQL.id == sql_id).first() if db_sql is None: return "Data is None", True db_sql.description = sql.description if sql.description else db_sql.description db_sql.sql_metadata = sql.sql_metadata if sql.sql_metadata else db_sql.sql_metadata db_sql.connector_id = sql.connector_id if sql.connector_id else db_sql.connector_id db.commit() return db_sql, False except SQLAlchemyError as e: db.rollback() return str(e), True def delete_sql(sql_id:int, db: Session): try: db_sql = db.query(models.SampleSQL).filter(models.SampleSQL.id == sql_id).first() if db_sql is None: return "Data is None", True db.delete(db_sql) db.commit() return None, False except SQLAlchemyError as e: db.rollback() return str(e), True def get_sql_by_key(key: str, db: Session): try: return db.query(models.SampleSQL).options(joinedload(models.SampleSQL.connectors)).filter(conn_model.Connector.connector_name == key).first(), False except SQLAlchemyError as e: db.rollback() return str(e),True def revoke_existing_vectordb_confg(id: int, db: Session): """ Revoke (delete) existing VectorDB configurations based on vector_db_id. Args: id (int): The vector_db_id to delete the mappings for. db (Session): Database session object. Returns: Tuple: (Success message or error, Boolean indicating if an error occurred) """ try: existing_mappings = db.query(models.VectorDB).join(models.VectorDBConfigMapping)\ .filter(models.VectorDBConfigMapping.vector_db_id == id).all() for mapping in existing_mappings: db.delete(mapping) db.commit() return "VectorDB configurations revoked successfully", False except SQLAlchemyError as e: db.rollback() return str(e), True def create_vectordb_with_embedding(key,id, vectordb, db: Session): if key == "update": result, is_error = revoke_existing_vectordb_confg(id, db) if is_error: return result, True try: db_vectordb = models.VectorDB( vectordb=vectordb.vectordb, vectordb_config=vectordb.vectordb_config, ) db.add(db_vectordb) db.commit() db.refresh(db_vectordb) db_vectordb_mapping = models.VectorDBConfigMapping( vector_db_id=db_vectordb.id, config_id=vectordb.config_id, ) db.add(db_vectordb_mapping) db.commit() db.refresh(db_vectordb_mapping) if vectordb.embedding_config: db_embedding = models.Embeddings( provider=vectordb.embedding_config['provider'], config=vectordb.embedding_config['params'], ) db.add(db_embedding) db.commit() db.refresh(db_embedding) db_embedding_mapping = models.VectorEmbeddingMapping( vector_db_id=db_vectordb.id, embedding_id=db_embedding.id, ) db.add(db_embedding_mapping) db.commit() db.refresh(db_embedding_mapping) return { 'vectordb': db_vectordb, 'vectordb_mapping': db_vectordb_mapping, 'embedding': db_embedding, }, False except SQLAlchemyError as e: db.rollback() return str(e), True def get_vectordb_instance(id: int, db: Session): """ Retrieves a VectorDB instance by its ID, along with its associated VectorDBConfigMapping, using joinedload. Args: id (int): The ID of the VectorDB instance. db (Session): Database session object. Returns: Tuple: The VectorDB instance and its associated config mapping, or an error message. """ try: db_vectordb = db.query(models.VectorDB).join(models.VectorDBConfigMapping)\ .options(joinedload(models.VectorDB.vectordb_config_mapping))\ .filter(models.VectorDBConfigMapping.config_id == id).first() embedding = db.query(models.Embeddings).join(models.VectorEmbeddingMapping)\ .filter(models.VectorEmbeddingMapping.vector_db_id == db_vectordb.id).first() if not db_vectordb: return "VectorDB not found", True if not embedding: return "No embedding found for VectorDB", True return (db_vectordb, embedding), False except SQLAlchemyError as e: return str(e), True def get_mapped_vector_store(db: Session, config_id: int): try: vectordb = db.query(models.VectorDB).join(models.VectorDBConfigMapping, models.VectorDB.id == models.VectorDBConfigMapping.vector_db_id)\ .options(joinedload(models.VectorDB.vectordb_config_mapping))\ .filter(models.VectorDBConfigMapping.config_id == config_id).first() if not vectordb: return None, False embedding = db.query(models.Embeddings).join(models.VectorEmbeddingMapping, models.Embeddings.id == models.VectorEmbeddingMapping.embedding_id)\ .filter(models.VectorEmbeddingMapping.vector_db_id == vectordb.id).first() embedding_details = { "vectordb": vectordb.vectordb, "vectordb_config": vectordb.vectordb_config, } if embedding: embedding_details.update({ "em_provider": embedding.provider, "embedding_config": embedding.config }) return embedding_details, False except SQLAlchemyError as e: db.rollback() return str(e), True ================================================ FILE: app/repository/user.py ================================================ from sqlalchemy.orm import Session import app.models.user as models import app.schemas.user as schemas from sqlalchemy.exc import SQLAlchemyError def create_user(user: schemas.UserCreate, db: Session): try: db_user = models.User(**user.model_dump()) db.add(db_user) db.commit() db.refresh(db_user) return db_user, False except SQLAlchemyError as e: db.rollback() return str(e), True def get_user_by_id(user_id: int, db: Session): try: return db.query(models.User).filter(models.User.id == user_id).first(), False except SQLAlchemyError as e: return str(e), True ================================================ FILE: app/schemas/common.py ================================================ from pydantic import BaseModel from typing import Optional, Any class DBConfig(BaseModel): host: str port: int username: str password: str dbname: str class CommonResponse(BaseModel): status: bool status_code: int data: Optional[Any] = None message: Optional[str] = None error: Optional[str] = None class LoginData(BaseModel): username: str password: str ================================================ FILE: app/schemas/connector.py ================================================ from pydantic import BaseModel from typing import List, Dict, Optional, Union from app.schemas.provider import VectorDBResponse class ConnectorBase(BaseModel): connector_type: int connector_name: str connector_description: Optional[str] = None connector_config: dict schema_config: Optional[Union[List[Dict], Dict]] = None connector_docs: Optional[str]= None enable: Optional[bool] = True class ConnectorResponse(ConnectorBase): connector_id:int connector_key :Optional[str]=None icon:Optional[str]=None provider_id: Optional[int] = None class ConnectorUpdate(BaseModel): connector_type: Optional[int] = None connector_name: Optional[str] = None connector_description: Optional[str] = None connector_config: Optional[dict] = None connector_docs: Optional[str]= None schema_config: Optional[List[Dict]] = None class SchemaUpdate(BaseModel): schema_config : Optional[List[Dict]]=None class CapabilitiesBase(BaseModel): id:Optional[int]=None name:str description:str requirements:List[Dict] config_id:Optional[int]=None actions_list: Optional[List[int]]=None actions:Optional[List[Dict]]=None class CapabilitiesArray(BaseModel): capabilities:List[CapabilitiesBase] class CapabilitiesUpdateBase(BaseModel): id:Optional[int]=None name:Optional[str]=None description:Optional[str]=None requirements:Optional[List[Dict]]=None config_id:Optional[int]=None actions_list: Optional[List[int]]=None class ConfigurationBase(BaseModel): short_description: str long_description: Optional[str] name:str status: int class ConfigurationCreation(ConfigurationBase): capabilities: List[int] connectors: List[int] class ConfigurationUpdate(BaseModel): name:Optional[str]=None short_description: Optional[str] = None long_description: Optional[str] = None status: Optional[int] = 0 capabilities: Optional[List[int]]=None connectors: List[int] class InferenceBase(BaseModel): name:str apikey:str llm_provider:str model:str config_id:Optional[int]=None endpoint:str class InferenceBaseUpdate(BaseModel): name:Optional[str]=None apikey:Optional[str]=None llm_provider:Optional[str]=None model:Optional[str]=None config_id:Optional[int]=None endpoint:Optional[str]=None class InferenceResponse(InferenceBase): id:int class ConfigurationResponse(ConfigurationBase): id: int capabilities: List[CapabilitiesBase] inference: Optional[List[InferenceResponse]]=None vectordb: Optional[List[VectorDBResponse]]=None connector: Optional[List[ConnectorResponse]]=None class Actions(BaseModel): name: str description: Optional[str] = None types: str condition: Optional[Dict] = None table : Optional[str] = None connector_id: Optional[int] = None body : Dict class ActionsResponse(Actions): id: int enable: Optional[bool] =True class ActionsUpdate(BaseModel): name: Optional[str] = None description: Optional[str] = None types: Optional[str] = None condition: Optional[Dict] = None table : Optional[str] = None connector_id: Optional[int] = None body : Optional[Dict] = None class LLMProviderBase(BaseModel): key:str api_key:str kind:Optional[str]=None unique_name: Optional[str]=None ================================================ FILE: app/schemas/environment.py ================================================ from pydantic import BaseModel from datetime import datetime from typing import Optional class EnvironmentBase(BaseModel): name: str class EnvironmentResponse(EnvironmentBase): id: int is_active: bool class UserEnvironmentMappingBase(BaseModel): user_id: int environment_id: int class UserEnvironmentMappingResponse(UserEnvironmentMappingBase): id: int ================================================ FILE: app/schemas/llmchat.py ================================================ from pydantic import BaseModel from typing import Optional, Dict from datetime import datetime class ChatHistoryBase(BaseModel): chat_context_id: str chat_query: str chat_answer: dict chat_summary: str chat_status: Optional[int]=None feedback_status: Optional[int]=None feedback_json: Optional[dict] = None user_id: Optional[int]=None primary_chat: Optional[bool]=False configuration_id: Optional[int]=None environment_id: Optional[int]=None class ChatHistoryCreate(ChatHistoryBase): pass class ChatHistory(ChatHistoryBase): chat_id: int class ChatResponse(ChatHistory): created_at: datetime updated_at: Optional[datetime] = None class FeedbackCreate(BaseModel): chat_context_id: str chat_id: int feedback_status: int feedback_json: Optional[Dict] = None class ListPrimaryContext(BaseModel): chat_context_id: str chat_query: str chat_answer: Dict user_id: int primary_chat: bool ================================================ FILE: app/schemas/provider.py ================================================ from pydantic import BaseModel from typing import List, Optional, Any, Dict from datetime import datetime class ProviderConfigBase(BaseModel): name: str description: str field: str slug: str provider_id: int config_type:int order:int required:bool value:Any class ProviderConfigResponse(ProviderConfigBase): id: int class ProviderBase(BaseModel): name: str description: str icon: str category_id: int enable: Optional[bool] = True class ProviderResp(ProviderBase): id:int key: str configs: List[ProviderConfigResponse] class ProviderCreate(ProviderBase): pass class ProviderUpdate(ProviderBase): pass class ProviderInDBBase(ProviderBase): id: int created_at: datetime updated_at: Optional[datetime] = None deleted_at: Optional[datetime] = None class Provider(ProviderInDBBase): pass class ProviderList(BaseModel): providers: List[Provider] class CategoryBase(BaseModel): name: str description: str enable: Optional[bool] = True class CategoryResponse(CategoryBase): id: int class CategoryCreate(CategoryBase): pass class CategoryList(BaseModel): categories: List[CategoryResponse] class ProviderConfigBase(BaseModel): name: str description: str field: str slug: str enable: Optional[bool] = True provider_id: int class ProviderConfigResponse(ProviderConfigBase): id: int class ProviderConfigList(BaseModel): category: List[ProviderConfigResponse] class TestCredentials(BaseModel): provider_config: Dict[str, Any] connector_name: str class TestVectorDBCredentials(BaseModel): vectordb_config: Dict[str, Any] embedding_config: Optional[Dict[str, Any]] = None class SampleSQLBase(BaseModel): description: str sql_metadata: Optional[Dict] = None connector_id: int class SampleSQLUpdate(BaseModel): description: Optional[str] = None sql_metadata: Optional[Dict] = None connector_id: Optional[int] = None class SampleSQLResponse(SampleSQLBase): id: int class CredentialsHelper(BaseModel): provider_config: Dict[str, Any] class VectorDBConfigBase(BaseModel): name: str description: str key: str icon: str config: List[Dict[str,Any]] class VectorDBConfigResponse(VectorDBConfigBase): id: int class VectorDBUpdateBase(BaseModel): vectordb: Optional[str] = None vectordb_config : Optional[Dict[str,Any]] = None config_id: Optional[int] = None embedding_config: Optional[Dict[str,Any]] = None class VectorDBBase(BaseModel): vectordb: Optional[str] = None vectordb_config : Optional[Dict[str,Any]] = None config_id: int embedding_config: Optional[Dict[str,Any]] = None class VectorDBResponse(VectorDBBase): id: int ================================================ FILE: app/schemas/user.py ================================================ from datetime import datetime from typing import Optional from pydantic import BaseModel class UserBase(BaseModel): id: int username: str class UserResponse(UserBase): role: Optional[str] = None created_at: Optional[datetime] = None updated_at: Optional[datetime] = None class UserCreate(UserBase): # Used when creating a new user pass ================================================ FILE: app/services/connector.py ================================================ from sqlalchemy.orm import Session import app.repository.connector as repo import app.repository.provider as config_repo import app.schemas.connector as schemas from app.services import provider as provider_svc from app.schemas.provider import VectorDBResponse import requests import os import uuid from loguru import logger from app.services.connector_details import get_plugin_metadata from fastapi import Request from app.providers.data_preperation import SourceDocuments from app.loaders.base_loader import BaseLoader def list_connectors(db: Session, user_id: str): """ Retrieves all connector records from the database. Args: db (Session): Database session object. Returns: Tuple: List of connector responses and error message (if any). """ connectors, is_error = repo.get_all_connectors(db, user_id) if is_error: return connectors, "DB Error" if not connectors: return [], None connectors_response = [schemas.ConnectorResponse( connector_id=connector.id, connector_type=connector.connector_type, connector_name=connector.connector_name, connector_description=connector.connector_description, connector_config=connector.connector_config, schema_config=connector.schema_config, connector_docs=connector.connector_docs, connector_key=connector.provider.key, enable=connector.enable, icon=connector.provider.icon, provider_id=connector.provider.category_id ) for connector in connectors] return connectors_response, None def list_connectors_by_provider_category(category_ids: int, db: Session, user_id: str): """ Retrieves all connector records from the database filtered by provider category. Args: category_id (int): The ID of the provider category. db (Session): Database session object. Returns: Tuple: List of connector responses and error message (if any). """ connectors, error = list_connectors(db, user_id) if error: return [], error filtered_connectors = [] for category_id in category_ids: filtered_connectors.extend([connector for connector in connectors if connector.provider_id == category_id]) return filtered_connectors, None def get_connector(connector_id: int, db: Session): """ Retrieves the details of a specific connector by its ID. Args: connector_id (int): The ID of the connector. db (Session): Database session object. Returns: Tuple: Connector response and error message (if any). """ connector, is_error = repo.get_connector_by_id(connector_id, db) if is_error: return connector, "DB Error" if connector is None: return [], None connector_response = schemas.ConnectorResponse( connector_id=connector.id, connector_type=connector.connector_type, connector_name=connector.connector_name, connector_description=connector.connector_description, connector_config=connector.connector_config, connector_key=connector.provider.key, schema_config=connector.schema_config, connector_docs=connector.connector_docs, enable=connector.enable, icon=connector.provider.icon ) return connector_response, None def download_and_save_pdf(connector_name: str, url: str) -> str: """ Downloads the PDF from the specified URL and saves it to the assets directory. Args: connector_name (str): Name of the connector. url (str): URL of the PDF to download. Returns: str: Path of the saved PDF file. str: Error message (if any). """ response = requests.get(url) connector_name = connector_name.replace(" ", "_") file_path = f"./assets/source_{connector_name}.pdf" with open(file_path, 'wb') as file: file.write(response.content) return file_path async def fileValidation(file): """ Validates the uploaded file for format and size constraints. Args: file (UploadFile): The uploaded document file. Returns: Tuple[str, int]: An error message if validation fails, or the size of the file if it passes. """ if not file.filename.endswith((".pdf", ".txt", ".yaml", ".docx",".csv")): return "Invalid file format", None content = await file.read() file_size = len(content) await file.seek(0) max_file_size_bytes = 100 * 1024 * 1024 if file_size > max_file_size_bytes: return "File size exceeds the limit", None return None, file_size async def upload_pdf(file): """ Uploads a document file to the specified connector. Args: file (UploadFile): The uploaded document file. Returns: Tuple: Connector response and error message (if any). """ uuid_str = str(uuid.uuid4()) file_path = f"./assets/datasource/documents/{uuid_str}/{file.filename}" try: os.makedirs(os.path.dirname(file_path), exist_ok=True) with open(file_path, 'wb') as f: f.write(await file.read()) return {"file_path": file_path,"file_id":uuid_str}, None except Exception as e: return None, f"Failed to write file: {str(e)}" def create_connector(connector: schemas.ConnectorBase, db: Session, user_id: str): """ Creates a new connector record in the database. Args: connector (ConnectorBase): The data for the new connector. db (Session): Database session dependency. Returns: Tuple: Connector response and error message (if any). """ provider, is_error = config_repo.get_provider_by_id(connector.connector_type, db) if is_error: return provider, "DB Error" provider_configs, is_error = config_repo.get_config_types(connector.connector_type, db) if is_error: return None, "DB Error" match provider.category_id: case 2 | 5: logger.info("creating plugin with category database") schema_details, is_error = get_plugin_metadata(provider_configs, connector.connector_config, connector.connector_name, provider.key) if is_error is None: connector.schema_config = schema_details else: return None, "Failed to create connector" case 1: logger.info("creating plugin with category remote documents") case 4: logger.info("creating plugin with category offline documents") case _: return None, "Invalid Connector Type." new_connector, is_error = repo.create_new_connector(connector, db, user_id) if is_error: return None, "Failed to create connector" connector_response = schemas.ConnectorResponse( connector_id=new_connector.id, connector_type=new_connector.connector_type, connector_name=new_connector.connector_name, connector_description=new_connector.connector_description, connector_config=new_connector.connector_config, connector_key=new_connector.provider.key, schema_config=new_connector.schema_config, connector_docs=new_connector.connector_docs, enable=new_connector.enable ) return connector_response, None def update_connector(connector_id: int, connector: schemas.ConnectorUpdate, db: Session): """ Updates an existing connector based on its ID. Args: connector_id (int): The ID of the connector to update. connector (ConnectorUpdate): The updated data for the connector. db (Session): Database session dependency. Returns: Tuple: Connector response and error message (if any). """ updated_connector, is_error = repo.update_existing_connector(connector_id, connector, db) if is_error: return updated_connector, "DB Error" if updated_connector is None: return [], None connector_response = schemas.ConnectorResponse( connector_id=updated_connector.id, connector_type=updated_connector.connector_type, connector_name=updated_connector.connector_name, connector_description=updated_connector.connector_description, connector_config=updated_connector.connector_config, schema_config=updated_connector.schema_config, connector_docs=updated_connector.connector_docs, enable=updated_connector.enable ) return connector_response, None def delete_connector(connector_id: int, db: Session): """ Deletes a connector based on its ID. Args: connector_id (int): The ID of the connector to delete. db (Session): Database session dependency. Returns: Tuple: Connector response and error message (if any). """ deleted_connector, is_error = repo.delete_connector_by_id(connector_id, db) if is_error: return deleted_connector, "DB Error" if deleted_connector is None: return [], None connector_response = schemas.ConnectorResponse( connector_id=deleted_connector.id, connector_type=deleted_connector.connector_type, connector_name=deleted_connector.connector_name, connector_description=deleted_connector.connector_description, connector_config=deleted_connector.connector_config, schema_config=deleted_connector.schema_config, connector_docs=deleted_connector.connector_docs, enable=deleted_connector.enable ) return connector_response, None def updateschemas(connector_id: int, connector: schemas.SchemaUpdate, db: Session): """ Updates the schema configuration for a connector. Args: connector_id (int): The ID of the connector. connector (SchemaUpdate): The updated schema configuration for the connector. db (Session): Database session dependency. Returns: Tuple: Schema update response and error message (if any). """ updated_connector, is_error = repo.update_existing_connector(connector_id, connector, db) if is_error: return updated_connector, "DB Error" if updated_connector is None: return [], None connector_response = schemas.SchemaUpdate( schema_config=updated_connector.schema_config, ) return connector_response, None def get_inference_by_config_id(config_id:int , db:Session): """ Retrieves the inference configuration based on the configuration ID. Args: config_id (int): The ID of the configuration. db (Session): Database session dependency. Returns: Tuple: Inference configuration response and error message (if any). """ inference_mapping, is_error = repo.get_inference_by_config(config_id, db) if is_error: return inference_mapping, "DB Error" if inference_mapping is None: return schemas.InferenceResponse(), None return schemas.InferenceResponse( id=inference_mapping.inference.id, name=inference_mapping.inference.name, apikey=inference_mapping.inference.apikey, config_id=inference_mapping.inference.config_id, llm_provider=inference_mapping.inference.llm_provider, model=inference_mapping.inference.model, endpoint=inference_mapping.inference.endpoint, ), None def list_configurations(db: Session, user_id: str): """ Retrieves all configurations from the database. Args: db (Session): Database session dependency. Returns: Tuple: List of configuration responses and error message (if any). """ configurations, is_error = repo.get_all_configurations(db, user_id) if is_error: return configurations, "DB Error" if not configurations: return [], None config_list = [schemas.ConfigurationResponse( id=config.id, name=config.name, short_description=config.short_description, long_description=config.long_description, status=config.status, capabilities=[schemas.CapabilitiesBase( id=capabilities.id, name=capabilities.name, requirements=capabilities.requirements, description=capabilities.description, config_id=capabilities.config_id, ) for capabilities in config.capabilities], inference=[schemas.InferenceResponse( id=inference_mapping.inference.id, name=inference_mapping.inference.name, apikey=inference_mapping.inference.apikey, llm_provider=inference_mapping.inference.llm_provider, model=inference_mapping.inference.model, endpoint=inference_mapping.inference.endpoint, config_id=inference_mapping.config_id ) for inference_mapping in config.inference_mapping], vectordb=[VectorDBResponse( id= vector_db.vector_db.id, vectordb=vector_db.vector_db.vectordb, vectordb_config=vector_db.vector_db.vectordb_config, config_id=config.id, ) for vector_db in config.vectordb_config_mapping if vector_db.vector_db] ) for config in configurations] return config_list, None def get_configuration(db: Session, config_id: int): """ Retrieves a configuration by its ID. Args: db (Session): Database session dependency. config_id (int): ID of the configuration to retrieve. Returns: Tuple: Configuration response and error message (if any). """ configuration, is_error = repo.get_configuration_by_id(config_id, db) if is_error: return configuration, "DB Error" if not configuration: return None, "Configuration not found" config_response = schemas.ConfigurationResponse( id=configuration.id, name=configuration.name, short_description=configuration.short_description, long_description=configuration.long_description, status=configuration.status, connector=[ schemas.ConnectorResponse( connector_id=connector.connector.id, connector_type=connector.connector.connector_type, connector_name=connector.connector.connector_name, connector_description=connector.connector.connector_description, connector_config=connector.connector.connector_config, schema_config=connector.connector.schema_config, connector_docs=connector.connector.connector_docs, enable=connector.connector.enable ) for connector in configuration.connectors ], capabilities=[ schemas.CapabilitiesBase( id=capabilities.id, name=capabilities.name, requirements=capabilities.requirements, description=capabilities.description, config_id=capabilities.config_id, ) for capabilities in configuration.capabilities ], inference=[ schemas.InferenceResponse( id=inference_mapping.inference.id, name=inference_mapping.inference.name, apikey=inference_mapping.inference.apikey, llm_provider=inference_mapping.inference.llm_provider, model=inference_mapping.inference.model, endpoint=inference_mapping.inference.endpoint, config_id=inference_mapping.config_id ) for inference_mapping in configuration.inference_mapping ], vectordb=[ VectorDBResponse( id=vector_db.vector_db.id, vectordb=vector_db.vector_db.vectordb, vectordb_config=vector_db.vector_db.vectordb_config, config_id=configuration.id, ) for vector_db in configuration.vectordb_config_mapping if vector_db.vector_db ] ) return config_response, None def delete_configuration(db: Session, config_id: int): """ Deletes a configuration by its ID. Args: db (Session): Database session dependency. config_id (int): ID of the configuration to retrieve. Returns: Tuple: Configuration response and error message (if any). """ configuration, is_error = repo.delete_configuration_by_id(config_id, db) if is_error: return configuration, "DB Error" if not configuration: return None, "Configuration not found" config_response = schemas.ConfigurationResponse( id=configuration.id, name=configuration.name, short_description=configuration.short_description, long_description=configuration.long_description, status=configuration.status, capabilities=[ schemas.CapabilitiesBase( id=capabilities.id, name=capabilities.name, requirements=capabilities.requirements, description=capabilities.description, config_id=capabilities.config_id, ) for capabilities in configuration.capabilities ], ) return config_response, None def create_configuration(configuration: schemas.ConfigurationCreation, db: Session, user_id: str): """ Creates a new configuration in the database. Args: configuration (ConfigurationCreation): The data for the new configuration. db (Session): Database session dependency. Returns: Tuple: Configuration response and error message (if any). """ new_config, is_error = repo.create_new_configuration(configuration, db, user_id) if is_error: return new_config, "DB Error" if not new_config: return [], None config_response = schemas.ConfigurationResponse( id=new_config.id, name=new_config.name, short_description=new_config.short_description, long_description=new_config.long_description, status=new_config.status, capabilities=[schemas.CapabilitiesBase( id=capabilities.id, name=capabilities.name, requirements=capabilities.requirements, description=capabilities.description, config_id=capabilities.config_id, ) for capabilities in new_config.capabilities], ) return config_response, None def update_configuration(config_id: int, configuration: schemas.ConfigurationUpdate, db: Session): """ Updates an existing configuration based on its ID. Args: config_id (int): The ID of the configuration to update. configuration (ConfigurationUpdate): The updated data for the configuration. db (Session): Database session dependency. Returns: Tuple: Configuration response and error message (if any). """ updated_config, is_error = repo.update_existing_configuration(config_id, configuration, db) if is_error: return updated_config, "DB Error" if updated_config is None: return [], None config_response = schemas.ConfigurationResponse( id=updated_config.id, name=updated_config.name, short_description=updated_config.short_description, long_description=updated_config.long_description, status=updated_config.status, capabilities=[schemas.CapabilitiesBase( id=capabilities.id, name=capabilities.name, requirements=capabilities.requirements, description=capabilities.description, config_id=capabilities.config_id, ) for capabilities in updated_config.capabilities], ) return config_response, None def create_capabilities(capabilities: schemas.CapabilitiesBase, db: Session): """ Creates a new capability in the database. Args: capabilities (CapabilitiesBase): The data for the new capability. db (Session): Database session dependency. Returns: Tuple: Capability response and error message (if any). """ new_capability, is_error = repo.create_capability(capabilities, db) if is_error: return new_capability, "DB Error" if capabilities.actions_list: result, is_mapping_error = repo.create_capability_action_mappings( capability_id=new_capability.id, action_ids=capabilities.actions_list, db=db ) if is_mapping_error: return result, "DB Error while creating capability-action mappings" capability_response = schemas.CapabilitiesBase( id=new_capability.id, name=new_capability.name, description=new_capability.description, requirements=new_capability.requirements, config_id=new_capability.config_id, actions=[{ "id": mapping.actions.id, "name": mapping.actions.name, "description": mapping.actions.description, "types": mapping.actions.types, "table": mapping.actions.table, "enable": mapping.actions.enable, } for mapping in new_capability.cap_actions_mapping] ) return capability_response, None def get_all_capabilities(db: Session): """ Retrieves all capabilities from the database. Args: db (Session): Database session dependency. Returns: Tuple: List of capability responses and error message (if any). """ capabilities, is_error = repo.get_all_capabilities(db) if is_error: return capabilities, "DB Error" if not capabilities: return [], None capabilities_response = [] for cap in capabilities: capabilities_response.append( schemas.CapabilitiesBase( id=cap.id, name=cap.name, description=cap.description, requirements=cap.requirements, config_id=cap.config_id, actions=[{ "id": mapping.actions.id, "name": mapping.actions.name, "description": mapping.actions.description, "types": mapping.actions.types, "table": mapping.actions.table, "enable": mapping.actions.enable, } for mapping in cap.cap_actions_mapping] ) ) return capabilities_response, None def update_capability(cap_id: int, capability: schemas.CapabilitiesUpdateBase, db: Session): """ Updates an existing capability based on its ID. Args: cap_id (int): The ID of the capability to update. capability (CapabilitiesUpdateBase): The updated data for the capability. db (Session): Database session dependency. Returns: Tuple: Capability response and error message (if any). """ updated_capability, is_error = repo.update_capability(cap_id, capability, db) if is_error: return updated_capability, "DB Error" if not updated_capability: return [], None capability_response = schemas.CapabilitiesBase( id=updated_capability.id, name=updated_capability.name, description=updated_capability.description, requirements=updated_capability.requirements, config_id=updated_capability.config_id, actions=[{ "id": mapping.actions.id, "name": mapping.actions.name, "description": mapping.actions.description, "types": mapping.actions.types, "table": mapping.actions.table, "enable": mapping.actions.enable, } for mapping in updated_capability.cap_actions_mapping] ) return capability_response, None def delete_capability(cap_id: int, db: Session): """ Deletes a capability from the database based on its ID. Args: cap_id (int): The ID of the capability to delete. db (Session): Database session dependency. Returns: Tuple: Boolean indicating whether the deletion was successful and error message (if any). """ deleted, is_error = repo.delete_capability(cap_id, db) if is_error: return deleted, "DB Error" if not deleted: return [], None return True, None def update_datasource_documentations(db: Session, vector_store, datasources, id_name_mappings, config_id, index): logger.info("Updating datasource documentations") repo.update_configuration_status(config_id, 1, db) active_datsources = {} vector_store.clear_collection(config_id) for key, datasource in datasources.items(): connector_details = id_name_mappings.get(key, {}) if "id" not in connector_details: logger.warning("Connector not found") continue logger.info(f"initialising datasource {key}") logger.info("mappings connector_details, id:{}".format(connector_details["id"])) datasource.connect() success, err = datasource.healthcheck() if not success: logger.error(f"Datasource health failed for {key}, cause: {err}") logger.warning(f"skipping datasource initialization for {key}") continue active_datsources[key] = datasource logger.info("Pushing plugin metadata to vector store") sd = SourceDocuments([], [], []) queries = [] if index: match datasource.__category__: case 1: documentations = datasource.fetch_data() sd = SourceDocuments([], [], documentations) case 2 | 5: schema_config = connector_details.get("schema_config",[]) schema_details, metadata = datasource.fetch_schema_details() sd = SourceDocuments(schema_details, schema_config, []) queries = get_all_connector_samples(connector_details.get("id"), db) case 4: documentations = datasource.fetch_data() sd = SourceDocuments([], [], documentations) chunked_document, chunked_schema = sd.get_source_documents() vector_store.prepare_data(key, chunked_document,chunked_schema, queries, int(config_id)) repo.update_configuration_status(config_id, 2, db) return active_datsources, None def get_inference_and_plugin_configurations(db: Session, config_id: int): """ Retrieves all inference and plugin configurations from the database. Args: db (Session): Database session dependency. Returns: Tuple: Configuration response and error message (if any). """ configuration={} connectors, status = repo.get_connectors_by_configuration_id(config_id, db) if status: return configuration configs, is_error = repo.get_configuration_by_id(config_id, db) if configs is None: configuration["models"]=[] else: inference, is_error = create_inference_yaml(configs.id, db) configuration["models"] = inference datasources = [] mappings = {} for conn in connectors: provider, is_error = config_repo.get_provider_by_id(conn.connector_type, db) if is_error: continue datasource = formatting_datasource(conn, provider) if datasource: datasource['name'] = str(conn.connector_name).replace(" ", "_").lower() mappings[datasource['name']] = { "id": conn.id, "schema_config": conn.schema_config } datasource['description'] = conn.connector_description datasources.append(datasource) configuration["datasources"] = datasources configuration["mappings"] = mappings return configuration def create_inference_yaml(config_id:int, db:Session): """ Creates a YAML file for inference configurations based on the given configuration ID. Args: config_id (int): The ID of the configuration. db (Session): Database session dependency. Returns: Tuple: List of inference configurations and error message (if any). """ inference, is_error = repo.get_inferences_by_config_id(config_id, db) if is_error: return inference, "Inference configuration not found" inference_yaml = [] for inf in inference: model_data = { "unique_name": inf.inference.name, "name": inf.inference.model, "api_key": inf.inference.apikey, "endpoint": inf.inference.endpoint, "kind": inf.inference.llm_provider, } inference_yaml.append(model_data) return inference_yaml, None def get_all_connector_samples(connector_id: int, db: Session): sqls, is_error = provider_svc.getsqlbyconnector(connector_id, db) if is_error: logger.error(f"Error getting SQL from connector {connector_id}:{is_error}") queries = [] for sql in sqls: queries.append({ "description": sql.description, "metadata": sql.sql_metadata }) return queries def create_yaml_file(request:Request, config_id: int, db: Session): """ Creates a YAML file for configurations based on the given configuration ID. Args: request (Request): Request object for logging purposes. config_id (int): The ID of the configuration. db (Session): Database session dependency. Returns: Tuple: Configuration YAML and error message (if any). """ configuration, is_error = repo.get_configuration_by_id(config_id, db) if (configuration == [] or configuration==None) or is_error: return None, None, "Configuration Not Found" inferences, is_error = repo.get_inferences_by_config_id(config_id, db) if (inferences == [] or inferences==None) or is_error: return None, None, "Inference configuration not found" connectors, is_error = repo.get_connectors_by_configuration_id(config_id, db) if (connectors == [] or connectors==None) or is_error: return None, None, "Connector not found" datasources = [] for conn in connectors: provider, is_error = config_repo.get_provider_by_id(conn.connector_type, db) if is_error: continue datasource = formatting_datasource(conn, provider) if datasource: datasource['name'] = str(conn.connector_name).replace(" ", "_").lower() datasource['description'] = conn.connector_description datasource['mappings'] = {"id": conn.id, "schema_config":conn.schema_config} datasources.append(datasource) use_case = dict({ 'short_description': configuration.short_description, 'long_description': configuration.long_description, 'capabilities': [ { "name": cap.name if cap.name else "default", "description": cap.description if cap.description else "No description provided", "requirements": cap.requirements if cap.requirements else [], "analysis": [], "action": {} } for cap in configuration.capabilities ] }) return datasources, use_case, None def formatting_datasource(connector, provider): """ Formats the datasource based on the provider category. Args: connector (Connector): The connector object. provider (Provider): The provider object. Returns: dict: Formatted datasource or None if the provider category is not recognized. """ if provider.category_id == 1: return { 'type': provider.key, 'params': connector.connector_config, 'documentations': [{'type': 'text', 'value': connector.connector_docs}] } elif provider.category_id == 2 or provider.category_id == 5: return { 'type': provider.key, 'params': connector.connector_config, 'documentations': [{'type': 'text', 'value': connector.connector_docs}] } elif provider.category_id == 4: return { 'type': provider.key, 'params': connector.connector_config } else: return None def get_llm_provider_models(llm_provider: schemas.LLMProviderBase): """ Retrieves the models available for a given LLM provider. Args: llm_provider (schemas.LLMProviderBase): The LLM provider object. Returns: Tuple: List of models and error message (if any). """ if llm_provider.key: llm_provider.kind = llm_provider.key llm_provider.unique_name = llm_provider.key return BaseLoader(model_configs=[dict(llm_provider)]).load_model(unique_name=llm_provider.key).get_models() else: return None, "Missing LLM provider key" def get_inference(inference_id: int, db: Session): """ Retrieves an inference from the database based on its ID. Args: inference_id (int): The ID of the inference. db (Session): Database session dependency. Returns: Tuple: Inference response and error message (if any). """ inference, is_error = repo.get_inference_by_id(inference_id, db) if is_error: return inference, "DB Error" if inference is None: return [], None data = schemas.InferenceResponse( name=inference.name, apikey=inference.apikey, model=inference.model, endpoint=inference.endpoint, llm_provider=inference.llm_provider, id=inference.id ) return data, None def create_inference(inference: schemas.InferenceBase, db: Session): """ Creates a new inference in the database. Args: inference (schemas.InferenceBase): The inference object to be created. db (Session): Database session dependency. Returns: Tuple: Inference response and error message (if any). """ inference_created, is_error = repo.create_inference(inference, db) if is_error: return inference_created, "DB Error" data = schemas.InferenceResponse( name=inference_created.name, apikey=inference_created.apikey, model=inference_created.model, endpoint=inference_created.endpoint, llm_provider=inference_created.llm_provider, id=inference_created.id ) return data, None def update_inference(inference_id: int, inference: schemas.InferenceBaseUpdate, db: Session): """ Updates an inference in the database based on its ID. Args: inference_id (int): The ID of the inference to be updated. inference (schemas.InferenceBaseUpdate): The inference object with updated values. db (Session): Database session dependency. Returns: Tuple: Inference response and error message (if any). """ updated_inference, is_error = repo.update_inference(inference_id, inference, db) if is_error: return updated_inference, "DB Error" if updated_inference is None: return [], None data = schemas.InferenceResponse( name=updated_inference.name, apikey=updated_inference.apikey, model=updated_inference.model, endpoint=updated_inference.endpoint, llm_provider=updated_inference.llm_provider, id=updated_inference.id ) return data, None def list_actions(db:Session): """ Retrieves all actions from the database. Args: db (Session): Database session dependency. Returns: Tuple: List of actions and error message (if any). """ actions, is_error = repo.list_actions(db) if is_error: return actions, "DB Error" if actions is None: return [], None return [ schemas.ActionsResponse( id=action.id, name=action.name, description=action.description, types=action.types, condition=action.condition, table = action.table, connector_id=action.connector_id, body = action.body, enable = action.enable, ) for action in actions], False def get_actions(action_id:int, db:Session): """ Retrieves an action from the database based on its ID. Args: action_id (int): The ID of the action. db (Session): Database session dependency. Returns: Tuple: Action response and error message (if any). """ action, is_error = repo.get_action_by_id(action_id, db) if is_error: return action, "DB Error" if action is None: return [], None return schemas.ActionsResponse( id=action.id, name=action.name, description=action.description, types=action.types, condition=action.condition, table = action.table, connector_id=action.connector_id, enable = action.enable, body = action.body, ), False def get_actions_by_connector(connector_id:int, db:Session): """ Retrieves all actions associated with a specific connector from the database. Args: connector_id (int): The ID of the connector. db (Session): Database session dependency. Returns: Tuple: List of actions and error message (if any). """ actions, is_error = repo.get_actions_by_connector(connector_id, db) if is_error: return actions, "DB Error" if actions is None: return [], None return [ schemas.ActionsResponse( id=action.id, name=action.name, description=action.description, types=action.types, condition=action.condition, table = action.table, connector_id=action.connector_id, enable = action.enable, body = action.body, ) for action in actions], False def create_action(action: schemas.Actions, db:Session): """ Creates a new action in the database. Args: action (schemas.Actions): The action object to be created. db (Session): Database session dependency. Returns: Tuple: Action response and error message (if any). """ action_created, is_error = repo.create_action(action, db) if is_error: return action_created, "DB Error" return schemas.ActionsResponse( id=action_created.id, name=action_created.name, description=action_created.description, types=action_created.types, condition=action_created.condition, table = action_created.table, connector_id=action_created.connector_id, enable = action_created.enable, body = action.body, ), False def update_action(action_id: int, action: schemas.ActionsUpdate, db: Session): """ Updates an action in the database based on its ID. Args: action_id (int): The ID of the action to be updated. action (schemas.ActionsUpdate): The action object with updated values. db (Session): Database session dependency. Returns: Tuple: Action response and error message (if any). """ updated_action, is_error = repo.update_action(action_id, action, db) if is_error: return updated_action, "DB Error" if updated_action is None: return [], None return schemas.ActionsResponse( id=updated_action.id, name=updated_action.name, description=updated_action.description, types=updated_action.types, condition=updated_action.condition, table = updated_action.table, connector_id=updated_action.connector_id, enable = updated_action.enable, body = updated_action.body, ), False def delete_action(action_id: int, db: Session): """ Deletes an action from the database based on its ID. Args: action_id (int): The ID of the action to be deleted. db (Session): Database session dependency. Returns: Tuple: Action response and error message (if any). """ result, is_error = repo.delete_action_by_id(action_id, db) if is_error: return None, "DB Error" return result, False def get_use_cases(db: Session): """ Retrieves all use cases from the database. Args: db (Session): Database session dependency. Returns: Tuple: List of use cases and error message (if any). """ configurations, status = repo.get_all_configurations(db) use_cases = [] for conf in configurations: use_case = {} use_case['short_description'] = conf.short_description use_case['long_description'] = conf.long_description use_case['capabilities'] = [] capabilities = [cap for cap in conf.capabilities] for cap in capabilities: capability = {} capability['name'] = cap.name capability['description'] = cap.description capability['requirements'] = cap.requirements use_case['capabilities'].append(capability) use_cases.append(use_case) if len(use_cases) > 0: return use_cases[0] else: return { "short_description": "", "long_description": "", "capabilities": [] } ================================================ FILE: app/services/connector_details.py ================================================ from typing import Any from app.plugins.loader import DSLoader from loguru import logger from app.repository import connector as repo from sqlalchemy.orm import Session from app.vectordb import chromadb, mongodb, loader def test_plugin_connection(db_configs, config, provider_class): params = {} for conf in db_configs: if conf.slug not in config.provider_config: return None, f"Missing required config key: {conf.slug}" else: params[conf.field] = config.provider_config[conf.slug] params = { "type" : provider_class, "connector_name" : config.connector_name, "params": params, } datasource = DSLoader(params).load_ds() success, err = datasource.connect() if not success and err: return None, f"Test Credentials Failed: {str(err)}" success, err = datasource.healthcheck() if not success and err: return None, f"Connection to {provider_class} is not established: {str(err)}" return True, "Test Credentials successfully completed" def get_plugin_metadata(db_configs, config, connector_name, provider_class): params = {} for conf in db_configs: if conf.slug not in config: return {}, Exception(f"Missing required config key: {conf.slug}") else: params[conf.field] = config.get(conf.slug, "") params = { "type" : provider_class, "connector_name" : connector_name, "params": params, } datasource = DSLoader( params ).load_ds() success, err=datasource.connect() if not success and err: return {}, Exception("Test Credentials Failed") success, err = datasource.healthcheck() if not success and err: logger.warning("Datasource health failed") return {}, Exception("Connection to "+provider_class+" is not established") schema_ddl, schema_config = datasource.fetch_schema_details() if len(schema_config) > 0: return schema_config, None else: return {}, Exception("Failed to fetch schema details") def check_configurations_availability(db: Session)-> Any: conf, is_error = repo.getbotconfiguration(db) if (conf == [] or conf==None) or is_error: return "Configuration Not Found" inference, is_error = repo.get_inference_by_id(conf.id,db) if (inference == [] or inference==None) or is_error: return "Inference configuration not found" connectors, is_error = repo.get_all_connectors(db) if (connectors == [] or connectors==None) or is_error: return "Connector not found" return None def test_vector_db_credentials(db_config, config, key): if isinstance(db_config.config, list): configs = [i.get("slug") for i in db_config.config if isinstance(i, dict)] flag = any(con == d_conf for con in configs for d_conf in config.vectordb_config) if not flag: return f"Missing required config key: {db_config.key}", True vectordb_config = config.vectordb_config.copy() vectordb_config.pop("key", None) vectorloader = loader.VectorDBLoader(config={"name":db_config.key, "params":vectordb_config}).load_class() err = vectorloader.connect() if err is not None: return f"Failed to connect to {db_config.key}: {err}", True err = vectorloader.health_check() if err is not None: return f"Failed to connect to {db_config.key}: {err}", True return f"{db_config.key} Test Credential Successfully Completed", False ================================================ FILE: app/services/llmchat.py ================================================ from sqlalchemy.orm import Session from app.repository import llmchat as repo from app.schemas import llmchat as schemas def create_chat(chat: schemas.ChatHistoryCreate, db: Session): """ Creates a new chat record in the database. Args: chat (schemas.ChatHistoryCreate): Data required to create a new chat. db (Session): Database session object. Returns: Tuple: Chat history schema and error message (if any). """ result, is_error = repo.create_new_chat(chat, db) if is_error: return result, "DB Error" data = schemas.ChatHistory( chat_context_id=result.chat_context_id, chat_answer=result.chat_answer, chat_id=result.chat_id, chat_query=result.chat_query, chat_status=result.chat_status, chat_summary=result.chat_summary, primary_chat=result.primary_chat, feedback_json=result.feedback_json, feedback_status=result.feedback_status, user_id=result.user_id ) return data, None def create_feedback(feedback: schemas.FeedbackCreate, db: Session): """ Updates an existing chat record with feedback data. Args: feedback (schemas.FeedbackCreate): Feedback data to update the chat record. db (Session): Database session object. Returns: Tuple: Updated chat history schema and error message (if any). """ result, is_error = repo.update_chat_feedback(feedback, db) if is_error: return result, "DB Error" if result is None: return [], None data = schemas.ChatHistory( chat_context_id=result.chat_context_id, chat_answer=result.chat_answer, chat_id=result.chat_id, chat_query=result.chat_query, chat_status=result.chat_status, chat_summary=result.chat_summary, primary_chat=result.primary_chat, feedback_json=result.feedback_json, feedback_status=result.feedback_status, user_id=result.user_id ) return data, None def list_chats_by_context(env_id: int, db: Session): """ Retrieves the primary chat records from the database. Args: db (Session): Database session object. Returns: Tuple: List of chat responses and error message (if any). """ result, is_error = repo.get_primary_chat(env_id, db) if is_error: return result, "DB Error" if not result: return [], None chat_data = [ schemas.ChatResponse( chat_context_id=chat.chat_context_id, chat_answer=chat.chat_answer, chat_id=chat.chat_id, chat_query=chat.chat_query, chat_status=chat.chat_status, chat_summary=chat.chat_summary, primary_chat=chat.primary_chat, feedback_json=chat.feedback_json, feedback_status=chat.feedback_status, user_id=chat.user_id, configuration_id=chat.configuration_id, created_at=chat.created_at, updated_at=chat.updated_at ) for chat in result ] return chat_data, None def list_all_chats_by_context_id(context_id: str, db: Session): """ Retrieves all chat records based on the context ID from the database. Args: context_id (str): The ID of the context to filter chats. db (Session): Database session object. Returns: Tuple: List of chat responses and error message (if any). """ result, is_error = repo.get_all_chats_by_context_id(context_id, db) if is_error: return result, "DB Error" if not result: return [], None chat_data = [ schemas.ChatResponse( chat_context_id=chat.chat_context_id, chat_answer=chat.chat_answer, chat_id=chat.chat_id, chat_query=chat.chat_query, chat_status=chat.chat_status, chat_summary=chat.chat_summary, primary_chat=chat.primary_chat, feedback_json=chat.feedback_json, feedback_status=chat.feedback_status, user_id=chat.user_id, created_at=chat.created_at, updated_at=chat.updated_at ) for chat in result ] return chat_data, None ================================================ FILE: app/services/provider.py ================================================ from sqlalchemy.orm import Session import app.repository.provider as repo import app.schemas.provider as schemas import app.schemas.connector as conn_schemas from app.services.connector_details import test_plugin_connection, test_vector_db_credentials from app.loaders.base_loader import BaseLoader from app.repository import connector as conn_repo from fastapi import Request from app.utils.module_reader import get_plugin_providers, get_vectordb_providers from app.models.provider import Provider, ProviderConfig, VectorDBConfig from loguru import logger from app.utils.module_reader import get_llm_providers, get_all_embedding from app.vectordb.loader import VectorDBLoader from app.embeddings.loader import EmLoader def test_inference_credentials(inference: conn_schemas.InferenceBase): """ Tests the connection credentials for a specific LLM inference based on its provider. Args: inference (conn_schemas.InferenceBase): A configuration object containing the provider details for testing the credentials. Returns: Tuple[bool, str]: - (True, "Test Credentials successfully completed") if the credentials are valid and the test is successful. - (None, error_message) if there was an error during the test or inference. - (False, "Unsupported Inference") if the LLM provider is not recognized or unsupported. """ model_configs = [{ "unique_name": inference.name, "name": inference.model, "api_key": inference.apikey, "endpoint": inference.endpoint, "kind" : inference.llm_provider, }] try: inference_model = BaseLoader(model_configs= model_configs).load_model(inference.name) except Exception as error: return None, str(error) output, response_metadata = inference_model.do_inference( "hi", [] ) if output['error'] is not None: return None, output['error'] return True, "Test Credentials successfully completed" def initialize_vectordb_provider(db:Session): """ Initializes the vector database by fetching the vector database data and inserting or updating their details in the database. Args: db (Session): Database session used for performing transactions. """ vector_dbs = get_vectordb_providers() for i in vector_dbs: data, is_error = repo.insert_or_update_data(db,VectorDBConfig, {"key":i['vectordb_name']},{ "name":i["display_name"], "description":i["description"], "icon":i["icon"], "key":i["vectordb_name"], "config": i["config"] if i["config"] is not None else None }) if is_error: logger.error(f"Error inserting {i['vectordb_name']} {data}") def initialize_embeddings(db:Session): pass def initialize_plugin_providers(db:Session): """ Initializes the plugin providers by fetching the plugin provider data and inserting or updating their details in the database. It also updates the provider configuration for each plugin. Args: db (Session): Database session used for performing transactions. """ providers = get_plugin_providers() for i in providers: data, is_error = repo.insert_or_update_data(db,Provider,{"key":i['plugin_name']},{ "name":i["display_name"], "description":i["description"], "icon":i["icon"], "category_id":i["category"], "key":i["plugin_name"] }) if is_error: logger.error(f"Error inserting {i['plugin_name']} {data}") else: for conf in i["args"].values(): confdata, is_error = repo.insert_or_update_data(db,ProviderConfig, {"provider_id":data.id,"slug":conf.slug},{ "provider_id":data.id, "name":conf.generic_name, "description":conf.description, "field":conf.slug, "slug":conf.slug, "value":conf.value, "order":conf.order, "required":conf.required, "config_type":conf.type }) if is_error: logger.error("Error inserting", conf.name, confdata) def list_providers(db: Session): """ Lists all available providers from the database and returns their details along with configurations. Args: db (Session): Database session used for performing transactions. Returns: (List[schemas.ProviderResp], str | None): List of provider details or an error message. """ providers, is_error = repo.get_all_providers(db) if is_error: return providers, "DB Error" if not providers: return [],None provider_list = [ schemas.ProviderResp( id=provider.id, name=provider.name, description=provider.description, enable=provider.enable, icon=provider.icon, category_id=provider.category_id, key = provider.key, configs=[ { 'id': config.id, 'name': config.name, 'description': config.description, 'field': config.field, 'slug': config.slug, 'provider_id': config.provider_id, 'config_type': config.config_type, 'order': config.order, 'required':config.required, 'value':config.value } for config in provider.providerconfig ] ) for provider in providers ] return provider_list, None def get_provider(provider_id: int,db: Session): """ Retrieves the details of a specific provider by its ID. Args: provider_id (int): The unique identifier of the provider. db (Session): Database session used for performing transactions. Returns: (schemas.ProviderResp, str | None): The provider details or an error message. """ provider, is_error = repo.get_provider_by_id(provider_id,db) if is_error: return provider, "DB Error" if not provider: return {}, None provider_data = { 'id': provider.id, 'name': provider.name, 'description': provider.description, 'enable': provider.enable, 'icon': provider.icon, 'category_id': provider.category_id, 'key': provider.key, 'configs': [ { 'id': config.id, 'name': config.name, 'description': config.description, 'field': config.field, 'slug': config.slug, 'provider_id': config.provider_id, 'config_type': config.config_type, 'order': config.order, 'required':config.required, 'value':config.value } for config in provider.providerconfig ] } provider_resp = schemas.ProviderResp(**provider_data) return provider_resp, None def test_vectordb_credentials(config:schemas.TestVectorDBCredentials, db:Session): """ Tests the credentials of a specific vector database based on its configuration. Args: config (schemas.TestVectorDBCredentials): Credentials to test. db (Session): Database session used for performing transactions. Returns: (str, str | None): A success message or an error message if unsupported. """ db_config, is_error = repo.get_vector_db_config(db, config.vectordb_config["key"]) if is_error: return None, db_config # if config.embedding_config: # config.embedding_config["vectordb"] = config.vectordb_config["key"] return vector_embedding_connector(config, db_config) def vector_embedding_connector(config, db_config): # if config.embedding_config: # err = EmLoader(config.embedding_config).load_embclass().health_check() # if err: # return err, False match config.vectordb_config["key"]: case ("chroma" | "mongodb"): return test_vector_db_credentials(db_config,config, config.vectordb_config["key"]) case _: return None, "Unsupported Vector Database Provider" def test_credentials(provider_id: int, config: schemas.TestCredentials, db: Session): """ Tests the credentials of a specific provider based on its configuration. Args: provider_id (int): The unique identifier of the provider. config (schemas.TestCredentials): Credentials to test. db (Session): Database session used for performing transactions. Returns: (str, str | None): A success message or an error message if unsupported. """ provider, is_error = repo.get_provider_by_id(provider_id, db) if provider is None or is_error: return provider, "Provider Not Found" provider_configs, is_error = repo.get_config_types(provider_id, db) if is_error: return provider_configs, "Failed to get provider configurations" match provider.category_id: case 1: return test_plugin_connection(provider_configs, config, provider.key) case 2: return test_plugin_connection(provider_configs, config, provider.key) case 4: return test_plugin_connection(provider_configs, config, provider.key) case 5: return test_plugin_connection(provider_configs, config, provider.key) case _: return None, "Unsupported Provider" def getvectordbs(db: Session): """ Returns a list of available vector databases. Args: request (Request): Request object used for handling incoming requests. Returns: dict: List of available vector databases. """ vector_dbs,is_error = repo.get_vectordb_providers(db) if is_error: return vector_dbs, "DB Error" if not vector_dbs: return [], None resp = [ schemas.VectorDBConfigResponse( id=db.id, name=db.name, description=db.description, icon=db.icon, key=db.key, config=db.config if db.config is not None else [], ) for db in vector_dbs ] return resp, None def getllmproviders(request: Request): """ Returns a list of available LLM providers. Args: request (Request): Request object used for handling incoming requests. Returns: dict: List of available LLM providers. """ providers = get_llm_providers() return {"providers": providers}, None def getsqlbyconnector(id:int, db:Session): """ Retrieves SQL metadata based on a connector ID. Args: id (int): The unique identifier of the connector. db (Session): Database session used for performing transactions. Returns: (List[schemas.SampleSQLResponse], str | None): List of SQL metadata or an error message. """ sqls, is_error = repo.get_sql_by_connector(id, db) if is_error: return sqls, "DB Error" if not sqls: return [], None sql_list = [ schemas.SampleSQLResponse( id=sql.id, description=sql.description, sql_metadata=sql.sql_metadata, connector_id=sql.connector_id, ) for sql in sqls ] return sql_list, None def listsql(db:Session, user_id: str): """ Retrieves a list of SQL samples from the database. Args: db (Session): Database session object. Returns: Tuple: List of SampleSQLResponse schemas and error message (if any). """ sqls, is_error = repo.list_sql(db, user_id) if is_error: return sqls, "DB Error" if not sqls: return [], None sql_list = [ schemas.SampleSQLResponse( id=sql.id, description=sql.description, sql_metadata=sql.sql_metadata, connector_id=sql.connector_id, ) for sql in sqls ] return sql_list, None def getsql(id:int, db:Session): """ Retrieves a specific SQL sample by its ID from the database. Args: id (int): ID of the SQL sample to retrieve. db (Session): Database session object. Returns: Tuple: SampleSQLResponse schema and error message (if any). """ sqls, is_error = repo.get_sql(id,db) if is_error: return sqls, "DB Error" if not sqls: return {}, None sql_data = { 'id': sqls.id, 'description': sqls.description, 'sql_metadata': sqls.sql_metadata, 'connector_id': sqls.connector_id, } sql_resp = schemas.SampleSQLResponse(**sql_data) return sql_resp, None def create_sql(request: Request,sql:schemas.SampleSQLBase,db:Session, user_id: str): """ Creates a new SQL sample in the database and updates the vector store. Args: request (Request): Request object to access app components. sql (schemas.SampleSQLBase): Data for the new SQL sample. db (Session): Database session object. Returns: Tuple: SampleSQLResponse schema and error message (if any). """ sql, is_error = repo.create_sql(sql,db,user_id) if is_error: return sql, "DB Error" if not sql: return [], None insert_vector_store(request, sql, db) return schemas.SampleSQLResponse( description=sql.description, sql_metadata=sql.sql_metadata, connector_id=sql.connector_id, id= sql.id, ), False def update_sql(request: Request, sql_id: int, sql: schemas.SampleSQLUpdate, db: Session): """ Updates an existing SQL sample in the database and updates the vector store. Args: request (Request): Request object to access app components. sql_id (int): ID of the SQL sample to update. sql (schemas.SampleSQLUpdate): Updated data for the SQL sample. db (Session): Database session object. Returns: Tuple: SampleSQLResponse schema and error message (if any). """ sql, is_error = repo.update_sql(sql_id, sql, db) if is_error: return sql, "DB Error" if not sql: return {}, None insert_vector_store(request, sql, db) return schemas.SampleSQLResponse( description=sql.description, sql_metadata=sql.sql_metadata, connector_id=sql.connector_id, id= sql.id, ), False def delete_sql(sql_id: int, db: Session): """ Deletes an SQL sample by its ID from the database. Args: sql_id (int): ID of the SQL sample to delete. db (Session): Database session object. Returns: Tuple: SampleSQLResponse schema and error message (if any). """ sql, is_error = repo.delete_sql(sql_id, db) if is_error: return sql, "DB Error" if not sql: return {}, None return schemas.SampleSQLResponse( description=sql.description, sql_metadata=sql.sql_metadata, connector_id=sql.connector_id, id=sql.id, ), False def get_quries_by_key(key:str, db: Session): """ Retrieves SQL samples based on a specific key. Args: key (str): Key to filter SQL samples (Connector Name). db (Session): Database session object. Returns: Tuple: List of dictionaries containing SQL descriptions and metadata, and error message (if any). """ sql, is_error = repo.get_sql_by_key(key, db) if is_error: return sql, "DB Error" if not sql: return {}, None return [ { "description": sql.description, "metadata": sql.sql_metadata } ], None def insert_vector_store(request, sql, db: Session): """ Inserts SQL data into the vector store. Args: request (Request): Request object to access app components. sql: SQL sample data to be inserted. db (Session): Database session object. Returns: str: Error message if an exception occurs, otherwise None. """ datasource, is_error = conn_repo.get_connector_by_id(sql.connector_id, db) vector_store = request.app.vector_store queries = [ { "description": sql.description, "metadata": sql.sql_metadata } ] try : vector_store.prepare_data(datasource_name=datasource.connector_name, queries=queries, chunked_document = None, chunked_schema = None) except Exception as e: return str(e) def create_vector_db_default_config(vectordb): if vectordb.embedding_config is None: vectordb.embedding_config = {"provider": "default", "params": {}} if not vectordb.vectordb: vectordb.vectordb = "chroma" vectordb.vectordb_config = {"path": "./vector_db"} return vectordb def attach_vector_config_if_missing(vectordb, db): inference, is_error = conn_repo.get_inference_by_config(vectordb.config_id, db) if is_error: return "Inference not found", is_error if vectordb.embedding_config.get("provider") == inference.llm_provider and not vectordb.embedding_config["params"].get("api_key"): vectordb.embedding_config["params"]["api_key"] = inference.apikey return vectordb, None def create_vectordb_and_embedding(key,id,vectordb, db): """ Creates a new VectorDB instance and inserts an embedding into the vector store. Args: vectordb (schemas.VectorDB): VectorDB instance data. db (Session): Database session object. Returns: Tuple: VectorDBResponse schema and error message (if any). """ vectordb = create_vector_db_default_config(vectordb) vectordb, is_error = attach_vector_config_if_missing(vectordb, db) if is_error: return vectordb, is_error db_data, is_error = repo.create_vectordb_with_embedding(key,id, vectordb, db) if is_error: return vectordb, "DB Error" response_data = { 'id': db_data['vectordb'].id, 'vectordb': db_data['vectordb'].vectordb, 'vectordb_config': db_data['vectordb'].vectordb_config, 'config_id': db_data['vectordb_mapping'].config_id, } return schemas.VectorDBResponse(**response_data), None def get_vectordb_instance(id: int, db: Session): """ Retrieves a VectorDB instance by its ID. Args: id (int): The ID of the VectorDB instance. db (Session): Database session object. Returns: Tuple: VectorDBResponse schema and error message (if any). """ (vectordb_instance, embedding), is_error = repo.get_vectordb_instance(id, db) if is_error: return vectordb_instance, "DB Error" return schemas.VectorDBResponse( id=vectordb_instance.id, vectordb=vectordb_instance.vectordb, vectordb_config=vectordb_instance.vectordb_config, config_id=vectordb_instance.vectordb_config_mapping[0].config_id, embedding_config={"provider": embedding.provider,"config": embedding.config} ), None def delete_vectordb_instance(id: int, db: Session): """ Deletes a VectorDB instance and its associated config mapping by ID. Args: id (int): The ID of the VectorDB instance to delete. db (Session): Database session object. Returns: Tuple: Success message and error message (if any). """ success, is_error = repo.revoke_existing_vectordb_confg(id, db) if is_error: return success, "DB Error or VectorDB not found" return success, None def create_vectorstore_instance(db:Session, config_id: int): """ Creates a new vector store instance. Args: db (Session): Database session object. Returns: Tuple: VectorStoreConfigResponse schema and error message (if any). """ configs, is_error = conn_repo.get_configuration_by_id(config_id, db) vector_store_formatting=None vector_store = None if is_error: return configs, "DB Error" if configs: vector_store, is_error = repo.get_mapped_vector_store(db, configs.id) if vector_store: vector_store_formatting = { "name": vector_store.get("vectordb"), "params": {**vector_store.get("vectordb_config", {})} } vectordb_config = vector_store.get("vectordb_config", {}) if vectordb_config: embeddings = vector_store.get("embedding_config", {}) vector_store_formatting["embeddings"] = { **embeddings, "provider": vector_store.get("em_provider"), "vectordb": vector_store.get("vectordb") } vector_store_formatting={**vector_store_formatting,**vectordb_config} vectorloader = VectorDBLoader(vector_store_formatting) if vector_store_formatting else VectorDBLoader(config={"name":"chroma", "params":{"path":"./chromadb"}}) return vectorloader.load_class(), None def get_all_embeddings(): """ Returns a list of available LLM providers. Args: request (Request): Request object used for handling incoming requests. Returns: dict: List of available LLM providers. """ embeddings = get_all_embedding() return embeddings, None ================================================ FILE: app/services/user.py ================================================ from sqlalchemy.orm import Session import app.repository.user as repo import app.repository.environment as env_repo import app.schemas.user as schemas def get_or_create_user(user: schemas.UserCreate, db: Session): """ Retrieves an existing user or creates a new one if not found. Args: user (UserBase): The data for the new user. db (Session): Database session dependency. Returns: Tuple: UserResponse object and error message (if any). """ existing_user, is_error = repo.get_user_by_id(user.id, db) if existing_user: return existing_user, None new_user, is_error = repo.create_user(user, db) if is_error: return None, "Failed to create user" unique_env = env_repo.create_environment(f"{new_user.username} env", db) assign_result, env_error = env_repo.assign_user_to_environment(new_user.id, unique_env.id, db) if env_error: return None, f"User created but failed to assign environment: {env_error}" user_response = schemas.UserResponse( id=new_user.id, username=new_user.username, ) return user_response, None def get_users_active_env(user_id: int, db: Session): env_id, error = env_repo.get_current_env_id(user_id, db) if error: return None, "Failed to get user's current active env_id" return env_id, None ================================================ FILE: app/utils/database.py ================================================ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import declarative_base from app.providers.config import configs DATABASE_URL = configs.DATABASE_URL engine = create_engine(DATABASE_URL) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() def get_db(): db = SessionLocal() try: yield db finally: db.close() ================================================ FILE: app/utils/jwt.py ================================================ import jwt from jwt import PyJWTError from datetime import datetime, timedelta class JWTUtils: def __init__(self, secret_key, algorithm="HS256"): self.SECRET_KEY = secret_key self.ALGORITHM = algorithm def create_jwt_token(self, data: dict, expires_delta: timedelta = timedelta(minutes=30)): to_encode = data.copy() expire = datetime.now() + expires_delta to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, self.SECRET_KEY, algorithm=self.ALGORITHM) return encoded_jwt def decode_jwt_token(self, token: str): try: payload = jwt.decode(token, self.SECRET_KEY, algorithms=[self.ALGORITHM]) return payload except PyJWTError: return None ================================================ FILE: app/utils/module_reader.py ================================================ from loguru import logger import importlib import pkgutil def get_vectordb_providers(): vectordb = importlib.import_module("app.vectordb") modules = [] for module_info in pkgutil.iter_modules(vectordb.__path__): try: module = importlib.import_module(f"{vectordb.__name__}.{module_info.name}") modules.append({ "icon": getattr(module, '__icon__'), "vectordb_name": getattr(module, '__vectordb_name__'), "display_name": getattr(module, '__display_name__'), "description": getattr(module, '__description__'), "config": getattr(module, "__connection_args__") }) except Exception as e: if module_info.name!= "loader": logger.warning(f"failed loading {module_info.name} {e}") return modules def get_plugin_providers(): plugins = importlib.import_module("app.plugins") modules = [] for module_info in pkgutil.iter_modules(plugins.__path__): module_name = f"{plugins.__name__}.{module_info.name}" try: module = importlib.import_module(module_name) modules.append({ "version": getattr(module, '__version__'), "icon": getattr(module, '__icon__'), "plugin_name": getattr(module, '__plugin_name__'), "display_name": getattr(module, '__display_name__'), "description": getattr(module, '__description__'), "category": getattr(module, '__category__'), "args": getattr(module, "__connection_args__") }) except Exception as e: if module_info.name != "loader": logger.warning(f"failed loading {module_info.name} {e}") return modules def get_llm_providers(): plugins = importlib.import_module("app.loaders") modules = [] for module_info in pkgutil.iter_modules(plugins.__path__): module_name = f"{plugins.__name__}.{module_info.name}" try: module = importlib.import_module(module_name) modules.append({ "display_name": getattr(module, '__display_name__'), "unique_name": getattr(module, '__unique_name__'), "icon": getattr(module, '__icon__') }) except Exception as e: if module_info.name != "base_loader": logger.info(f"failed loading {module_info.name} cause {e}") return modules def get_all_embedding(): embeddings = importlib.import_module("app.embeddings") modules = [] for module_info in pkgutil.iter_modules(embeddings.__path__): module_name = f"{embeddings.__name__}.{module_info.name}" try: module = importlib.import_module(module_name) modules.append({ "provider": getattr(module, '__provider_name__'), "vector_dbs": getattr(module, '__vectordb_name__'), "config": getattr(module, '__connection_args__'), "icon": getattr(module, '__icon__') }) except Exception as e: logger.info(f"failed loading {module_info.name} cause {e}") return modules ================================================ FILE: app/utils/parser.py ================================================ import json from loguru import logger def parse_llm_response(body): text = body.replace("\\n","") text = text.replace("\n","") text = text.replace("\\_","_") if '\\"' not in text: text = text.replace("\\","") text = text.removeprefix("```json") text = text.removesuffix("```") text = text.removesuffix("User:") try: out = json.loads(text) except Exception as e: logger.info("error parsing llm response") logger.critical(e) out = {} return out def markdown_parse_llm_response(body): # text = body.replace("\\n","") # text = text.replace("\n","") # text = text.replace("\\","") # text = text.replace("\\_","_") # if '\\"' not in text: # text = text.replace("\\","") text = body.removeprefix("```json") text = text.removesuffix("```") text = text.removesuffix("User:") try: out = json.loads(text) except Exception as e: logger.info("error parsing llm response") logger.critical(e) out = {} return out ================================================ FILE: app/utils/read_config.py ================================================ import yaml from loguru import logger def read_yaml_file(config_file) -> dict: """ Reads a YAML file and returns its contents as a dictionary. :param file_path: Path to the YAML file. :return: Dictionary containing the file contents. """ try: # Read YAML config file with open(config_file, "r") as yaml_file: yaml_config = yaml.safe_load(yaml_file) return yaml_config except Exception as e: logger.warning(e) return {} ================================================ FILE: app/vectordb/loader.py ================================================ from app.vectordb.chromadb.handler import ChromaDataBase from app.vectordb.mongodb.handler import AltasMongoDB from loguru import logger class VectorDBLoader: def __init__(self, config): self.config = config def load_class(self): vectordb_classes = { "chroma": ChromaDataBase, "mongodb": AltasMongoDB, } vectordb_provider = self.config.get('name',{}) connection_params = self.config.get('params',{}) vectordb_class = vectordb_classes.get(vectordb_provider) logger.info(f"vectordb provider: {vectordb_provider}") logger.info(f"connection_params:{connection_params}") if vectordb_class: return vectordb_class(**connection_params) else: logger.info("No specified vectordb providers") return ChromaDataBase() ================================================ FILE: app/vectordb/mongodb/__init__.py ================================================ from collections import OrderedDict from app.models.request import ConnectionArgument # Plugin Metadata __version__ = '1.0.0' __vectordb_name__ = 'mongodb' __display_name__ = 'MongoDB Atlas' __description__ = 'MongoDB for Vector Storage' __icon__ = '/assets/vectordb/logos/mongodb.svg' __connection_args__ = [ { "config_type": 1, "name": "MongoDB URI", "description": "URI to connect to MongoDB", "order": 1, "required": True, "slug": "uri", "field": "uri", "placeholder": "mongodb+srv://admin:@cluster0.lwqw4z.mongodb.net/", } ] __all__ = [ __version__, __vectordb_name__, __display_name__ , __description__, __icon__, __connection_args__ ] ================================================ FILE: app/vectordb/mongodb/handler.py ================================================ import pymongo from loguru import logger from app.base.base_vectordb import BaseVectorDB import certifi class AltasMongoDB(BaseVectorDB): def __init__(self, uri: str , embeddings: dict={"provider": "default", "vectordb": "mongodb"}): self.uri = uri self.client = None self.embeddings = embeddings self.EMBEDDING_FIELD_NAME = "embeddings" def connect(self): try: self.client = pymongo.MongoClient(self.uri, tlsCAFile=certifi.where()) logger.info(f"Connected to Altas MongoDB Vector Database") self.db = self.client.get_database('context_store') self.schema_collection = self.db.get_collection('schema') self.doc_collection = self.db.get_collection('documents') self.cache_collection = self.db.get_collection('cache') self.schema_index_name = "schema" self.doc_index_name = "doc" self.cache_index_name = "cache" self.emf = self.load_embeddings_function() return None except Exception as e: logger.critical(f"Failed connecting Altas MongoDB Vector Database: {e}") return str(e) def health_check(self): try: sample = { "_id": "doc1", "datasource":"psql_db", "document": "This referes to the user data which consist of username, password, email and address", "metadata":{ "username": "username" } } sample[self.EMBEDDING_FIELD_NAME] = self.generate_embedding(sample['document']) self.doc_collection.insert_many([sample]) # self.schema_collection.insert_many([sample]) # self.cache_collection.insert_many([sample]) collection_list = self.db.list_collection_names() logger.info(f"collections available:{collection_list}") self.doc_collection.delete_many({ "datasource": "psql_db" }) if len(collection_list) > 0: return None else: return "Collections cannot be created in DB" except Exception as e: logger.error(f"Health check failed: {e}") return f"Failed to connect with Altas MongoDB {e}" def clear_collection(self, config_id): # self.schema_collection.delete_many({}) # Delete all documents in the collection # self.doc_collection.delete_many({}) # self.cache_collection.delete_many({}) self.config_id = config_id self.cache_collection.delete_many({ "metadatas.config_id": config_id }) self.schema_collection.delete_many({ "metadatas.config_id": config_id }) self.doc_collection.delete_many({ "metadatas.config_id": config_id }) def generate_embedding(self, context: str) -> list[float]: array = self.emf([context])[0] return array.tolist() def prepare_data(self, datasource_name, chunked_document, chunked_schema, queries, config_id): if chunked_document: documents = [] document_count = self.doc_collection.count_documents({}) for i, doc in enumerate(chunked_document, start = document_count): sample = { # "_id": "doc" + str(i), "document": doc.page_content, "metadatas": {**doc.metadata,"datasource": datasource_name, "config_id": config_id} } sample[self.EMBEDDING_FIELD_NAME] = self.generate_embedding(sample['document']) documents.append(sample) self.doc_collection.insert_many(documents) if chunked_schema: schemas = [] schema_count = self.schema_collection.count_documents({}) for i, doc in enumerate(chunked_schema, start = schema_count): sample = { # "_id": "doc" + str(i), "document": doc.page_content, "metadatas": {**doc.metadata,"datasource": datasource_name, "config_id": config_id} } sample[self.EMBEDDING_FIELD_NAME] = self.generate_embedding(sample['document']) schemas.append(sample) self.schema_collection.insert_many(schemas) if queries: caches = [] queries_count = self.cache_collection.count_documents({}) for i, doc in enumerate(queries, start = queries_count): sample = { # "_id": "doc" + str(i), "document": doc['description'], "metadatas": {**doc['metadata'], "datasource": datasource_name, "config_id": config_id} } sample[self.EMBEDDING_FIELD_NAME] = self.generate_embedding(sample['document']) caches.append(sample) self.cache_collection.insert_many(caches) self.create_knn_index() def _create_index(self, collection, index_name): index = list(collection.list_search_indexes()) if len(index)==0: collection.create_search_index({ "definition": { "mappings": { "dynamic": True, "fields": { self.EMBEDDING_FIELD_NAME: { "dimensions": 384, "similarity": "cosine", "type": "knnVector" } } } }, "name": index_name # Renamed for consistency }) logger.info(f"Index created:{index_name}") else: logger.info(f"{index_name} Index already exists") def create_knn_index(self): self._create_index(self.doc_collection, self.doc_index_name) self._create_index(self.schema_collection, self.schema_index_name) self._create_index(self.cache_collection, self.cache_index_name) async def _find_similar(self, datasource, collection, query, count, index_name): logger.info(f"datasources:{datasource}") logger.info(f"collection:{collection}") logger.info(f"index_name:{index_name}") res = collection.aggregate([ { '$vectorSearch': { "index": index_name, "path": self.EMBEDDING_FIELD_NAME, "queryVector": self.generate_embedding(query), "numCandidates": 50, "limit": count, } }, { '$match': { 'metadatas.datasource': datasource # Filter for the specified datasource } }, { "$project": { "_id" : 1, "datasource" : 1, "document": 1, "metadatas": 1, "score": {"$meta": "vectorSearchScore"} } } ]) results = list(res) for result in results: result['distances'] = 1 - result['score'] return results async def find_similar_schema(self, datasource, query,count): return await self. _find_similar(datasource, self.schema_collection, query, count, self.schema_index_name) async def find_similar_documentation(self, datasource, query, count): return await self. _find_similar(datasource, self.doc_collection, query, count, self.doc_index_name) async def find_similar_cache(self, datasource, query,count = 3): return await self. _find_similar(datasource, self.cache_collection, query, count, self.cache_index_name) ================================================ FILE: commands/cli.py ================================================ import click from loguru import logger from app.utils.read_config import read_yaml_file import sys @click.group() @click.option('--debug', default=False, envvar='DEBUG_MODE', help='Enable debug mode') @click.option('--config', prompt='please provide config file', help='Path to the configuration file') @click.pass_context def cli(ctx, debug, config): """ CLI for managing application commands. :param ctx: Click context object for passing configurations. :param debug: Flag to enable or disable debug mode. :param config: Path to the configuration file. """ if debug: logger.debug("Debug mode enabled") logger.info("loading configurations") config = read_yaml_file(config) if len(config) > 0: ctx.obj = config else: logger.critical("Configuration data is empty or invalid") sys.exit(1) ================================================ FILE: commands/llm.py ================================================ import click from commands.cli import cli from loguru import logger from app.providers.config import configs from app.main import create_app import uvicorn import sys @cli.command() @click.pass_obj def llm(ctx) -> None: """ Starts the LLM chain server using Uvicorn. :param ctx: Configuration context passed from the CLI command. """ logger.info("Intializing fastapi application server") # try: app = create_app(config=ctx) logger.info("Intialized fastapi application") logger.info("Starting Uvicorn server...") uvicorn.run(app, host="0.0.0.0", port=configs.application_port, reload=False) # except Exception as e: # logger.critical(f"Failed to start the LLM server: {e}") # sys.exit(1) # Registering llm command cli.add_command(llm) ================================================ FILE: config.yaml ================================================ vector_db: name: "chroma" params: path: "./vector_db" embeddings: provider: "chroma_default" ================================================ FILE: docker-compose.yml ================================================ services: nginx: image: nginx:latest container_name: nginx ports: - "80:80" - "82:82" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf # Mount custom nginx.conf to container restart: always depends_on: - zitadel - backend db: image: postgres:16-alpine environment: PGUSER: postgres POSTGRES_PASSWORD: postgres healthcheck: test: ["CMD-SHELL", "pg_isready", "-d", "zitadel", "-U", "postgres", "||", "exit 1"] interval: 10s timeout: 30s retries: 5 start_period: 20s volumes: - ./pgdata:/var/lib/postgresql/data zitadel: user: "${UID:-1000}" restart: always image: 'ghcr.io/zitadel/zitadel:latest' command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled' ports: - '8080:8080' environment: ZITADEL_DATABASE_POSTGRES_HOST: db ZITADEL_DATABASE_POSTGRES_PORT: 5432 ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: zitadel ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: postgres ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: postgres ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable ZITADEL_EXTERNALSECURE: "false" ZITADEL_EXTERNALDOMAIN: "zitadel" ZITADEL_EXTERNALPORT: "82" ZITADEL_FIRSTINSTANCE_MACHINEKEYPATH: /machinekey/zitadel-admin-sa.json ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_USERNAME: zitadel-admin-sa ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_NAME: Admin ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINEKEY_TYPE: 1 volumes: - ./machinekey:/machinekey depends_on: db: condition: service_healthy backend: build: context: . dockerfile: Dockerfile ports: - '8001:8001' volumes: - ./raggenie.db:/app/raggenie.db - ./assets:/app/assets - ./chromadb:/app/chromadb - ./machinekey:/app/machinekey environment: - PYTHONDONTWRITEBYTECODE=1 - PYTHONUNBUFFERED=1 - ZITADEL_TOKEN_URL=http://zitadel:8080/oauth/v2/token - ZITADEL_DOMAIN=http://zitadel:8080 - APP_SERVER=http://localhost:8001 - CLIENT_PRIVATE_KEY_FILE_PATH=machinekey/zitadel-admin-sa.json command: 'python3 main.py --config ./config.yaml llm' depends_on: - zitadel ================================================ FILE: documents/.gitignore ================================================ # Dependencies /node_modules # Production /build # Generated files .docusaurus .cache-loader # Misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: documents/README.md ================================================ # Website This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. ### Installation ``` $ yarn ``` ### Local Development ``` $ yarn start ``` This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. ### Build ``` $ yarn build ``` This command generates static content into the `build` directory and can be served using any static contents hosting service. ### Deployment Using SSH: ``` $ USE_SSH=true yarn deploy ``` Not using SSH: ``` $ GIT_USER= yarn deploy ``` If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. ================================================ FILE: documents/babel.config.js ================================================ module.exports = { presets: [require.resolve('@docusaurus/core/lib/babel/preset')], }; ================================================ FILE: documents/docs/Configuring agents.md ================================================ --- sidebar_position: 7 --- # Configuring agents ================================================ FILE: documents/docs/Connectors/Airtable.md ================================================ --- sidebar_position: 2 --- # Airtable Plugin ### Plugin name The name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction. ### Plugin Description A brief description of data in the plugin. This is used during LLM calls and may affect the quality of LLM response thus make sure that it is descriptive enough for good LLM output while being short enough to reduce LLM cost. ### Airtable token The Airtable Token is an API key used to authenticate and access data from Airtable. Airtable integration allows the plugin to retrieve structured datasets and tables that will be used during query generation. ### Airtable workspace id The Airtable Workspace ID specifies which workspace within your Airtable account the plugin will connect to. A workspace can contain multiple bases, and identifying the correct workspace is important for retrieving the right data. ================================================ FILE: documents/docs/Connectors/Bigquery.md ================================================ --- sidebar_position: 3 --- # Bigquery Plugin ### Plugin name The name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction. ### Plugin Description A brief description of data in the plugin. This is used during LLM calls and may affect the quality of LLM response thus make sure that it is descriptive enough for good LLM output while being short enough to reduce LLM cost. ### Service account JSON The Service Account JSON contains authentication credentials that allow your RAG application to access Google BigQuery securely. This file is essential for granting the necessary permissions to query data stored in BigQuery. ### Project id The Project ID refers to the specific Google Cloud project where your BigQuery datasets reside. Each BigQuery query is associated with a project, and the project ID is used to identify which datasets the plugin should access. ================================================ FILE: documents/docs/Connectors/Connectors.md ================================================ --- sidebar_position: 4 --- # Connectors/pluggins Different components in your LLM app can be inserted using plugins. ## Data Sources Currently these are the datasource plugins that are available in raggenie. ### Structred Datasources * [Postgressql](./Postgressql) * [Airtable](./Airtable) * [Bigquery](./Bigquery) ### Unstrunctured Datasources * [PDFs](./PDFs) * [Websites](./Websites) ================================================ FILE: documents/docs/Connectors/PDFs.md ================================================ --- sidebar_position: 4 --- # PDFs Plugin ### Plugin name The name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction. ### Plugin Description A brief description of data in the plugin. This is used during LLM calls and may affect the quality of LLM response thus make sure that it is descriptive enough for good LLM output while being short enough to reduce LLM cost. ### File upload The File Upload section allows users to upload PDF files into the plugin. These files are then used as a data source for LLM interactions, enabling the system to retrieve and extract relevant information when necessary. ================================================ FILE: documents/docs/Connectors/Postgressql.md ================================================ --- sidebar_position: 1 --- # Postgressql Plugin You can connect to an instance of postgress using the postgressql plugin. ### Plugin name The name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction. ### Plugin Description A brief description of data in the plugin. This is used during LLM calls and may affect the quality of LLM response thus make sure that it is descriptive enough for good LLM output while being short enough to reduce LLM cost. ### Database sslmode SSL Mode determines whether SSL encryption should be used when connecting to the PostgreSQL database. This feature ensures that data transmitted between your raggenie and the database is secure. * sslmode=disable: No SSL is used when connecting to the database. This option can be used if the database server does not require encrypted connections or if encryption is not a priority. However, this may expose sensitive data to potential interception. * sslmode=require: Enforces the use of SSL for database connections. This is recommended for environments where sensitive data is transmitted or where security is a concern. ### Database name The Database Name is the name of the PostgreSQL database that the raggenie will connect to. Each database instance can host multiple databases, and specifying the correct database name is crucial to ensure that your raggenie accesses the intended data. ### Database host The Database Host refers to the URL or IP address where the PostgreSQL server is running. This could be a local server, a remote machine, or a cloud-hosted instance. Ensure that the specified host is reachable from your application's environment. ### Database port The Database Port is the TCP/IP port on which the PostgreSQL server is listening. The default port for PostgreSQL is `5432`, but this can be configured to a different port based on your setup. ### Password The password of the user trying to access the postgressql database. ### User name The Username is the identity that the application uses to connect to the PostgreSQL database. Each user in PostgreSQL can have different permissions, and it is important to use a user with the necessary roles for the application's functionality. ================================================ FILE: documents/docs/Connectors/Websites.md ================================================ --- sidebar_position: 5 --- # Websites Plugin ### Plugin name The name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction. ### Plugin Description A brief description of data in the plugin. This is used during LLM calls and may affect the quality of LLM response thus make sure that it is descriptive enough for good LLM output while being short enough to reduce LLM cost. ### Website URL The Website URL is the address of the website from which the plugin will fetch documents and data. The plugin will query this URL to retrieve the required content for use during LLM interactions. ================================================ FILE: documents/docs/Examples.md ================================================ --- sidebar_position: 4 --- # Examples ================================================ FILE: documents/docs/How to configure raggenie/Configuration.md ================================================ --- sidebar_position: 2 --- # Configuration ## Configuration details You should provide a bot name, a short discription about the bot and a long discription about the bots usecase. Note:- Long dicription will be used when making LLM calls and thus will affect the performance of the chatbot. It is recomended to give detailed description that can help the LLM to understand its usecases. ## Inference endpoint To add an LLM endpoint choose your LLM inference provider and specify a unique name to reference the particular model. ![LLM inference plugin image](../../static/img/inferance_end_point.png?raw=true) Specify the model name, inference provider endpoint, and the API key. ## Capabilities Capabilities can be defined to make your chatbot do custom actions such as fill a form or book a meeting. Currently actions can be defined to interact with your datasources or to webhooks. ### Add Capability Name and Description Capability Name and discription is used by the intent extraction module to determine which capability is to be exicuted. So it is important to give a detailed discription of the capability. ![Capability initialisation image](../../static/img/Capbilities.png?raw=true) ### Add Capability Parameters You can specify the parameters nesessary to exicute an action. Raggenie uses LLM calls to see if all the specified parameters could be retreaved from the user input. In case if LLM could not detect all the nesessary parameters raggenie would ask the user to specify the missing parameters ![Capability parameters image](../../static/img/Create_parameter.png?raw=true) these parameters can be used to trigger an action. ================================================ FILE: documents/docs/How to configure raggenie/Deploy.md ================================================ --- sidebar_position: 4 --- # Deploy `Restart Chatbot` to apply all the changes that have been made to the chat bot. This restarts the backend and connections with the updated configurations. You can get the live preview URL from here to be shared with your end users. ================================================ FILE: documents/docs/How to configure raggenie/Plugins.md ================================================ --- sidebar_position: 1 --- # Plugins ## Configuration Plugin configuration is used to specify the metadata of different datasources such as datasource name, description and login details. You need to specify informations such as: * Plugin Name: Plugin name is used to differentiate between different connected plugins. * Database Description: Description is should contain a breafe description about the use case of the database. The description is used during LLM calls, thus more detailed descriptions may help to improve the relevance of LLM output. The decription should be between 100 and 200 characters to make sure that it is detailed enough while also keeping the token count low. * Database login details: These are specific for different plugins. Refer [Plugins](../Connectors) for more details after entering all the details use `connection test` button perform a health check. If the health check passes use `save & continue` to save the plugin. ## Database schema Raggenie automatically fetches your schema from the database on saving the configuration. Edit and add descriptions for different tables and their related columns. These decriptions are used during LLM calls and is nessesary for usable LLM responses. After adding descriptions `save & continue`. ## Documentation You can add documentation of the plugins. This can be used a add important details regarding the plugins, which helps to fully understand how a plugin functions and how to use it effectively. This can be used to include important conditions and criterias. This data would be split into chunks and retreaved along with the schema during RAG exicution, thus can help to get improved responses from the LLMs. Then `save & continue` to fully save the plugin. ================================================ FILE: documents/docs/How to configure raggenie/Preview.md ================================================ --- sidebar_position: 5 --- # Preview You can see the live preview of your chatbot to interact with and run tests. It comes with basic frondend features such as the chatbot, conversation tracking and chat history. ================================================ FILE: documents/docs/How to configure raggenie/Samples.md ================================================ --- sidebar_position: 3 --- # Samples You can give example questions and their responses to improve the models accuracy. These are used for few shot prompting purposes. You can find all the example questions for your chatbot here. To give sample data for raggenie, fill in the following parameters. * Question: This is the user query that the model is supposed to generate a response for. * Connector: This is the plugin that contains the data, which is needed to get the correct LLM response. * Query: This is the query that should be generated by the LLM to get the correct data. * Metadata: This can be used to give additional data about the example. This is optional. `Save` your changes for updating the sample respose. ================================================ FILE: documents/docs/How to configure raggenie/_category_.json ================================================ { "label": "How to configure raggenie", "position": 3, "link": { "type": "generated-index", "description": "Steps to configure Raggenie" } } ================================================ FILE: documents/docs/How to run raggenie/To run raggenie backend Server.md ================================================ --- sidebar_position: 1 --- # To run raggenie backend Server ### Clone the project The first step is to clone the RAGGenie project from its GitHub repository. The `git clone` command copies the repository from GitHub to your local system. ```bash git clone https://github.com/sirocco-ventures/raggenie ``` Move into the project using ```bash cd raggenie ``` ### Install Requirements Once the project is cloned, the next step is to install the necessary Python packages that the raggenie backend server depends on. Instead of using `pip`, we will use `Poetry`, a tool for dependency management and packaging in Python projects. ```bash poetry install ``` You can find more info for setting up poetry [here](../Prerequesites.md) ### To run server After installing the dependencies, you can run the raggenie backend server. The server uses a configuration file (config.yaml) to set up the environment and specify parameters for LLM usage. The command below will start the server and ensure it operates based on the provided configuration. ```bash python main.py --config ./config/config.yaml llm ``` Below is a sample configuration for the vector database setup in `config.yaml`: ```yaml vector_db: name: "chroma" params: path: "./vector_db" embeddings: provider: "chroma_default" ``` ================================================ FILE: documents/docs/How to run raggenie/To run raggenie ui server.md ================================================ --- sidebar_position: 2 --- # To run raggenie ui server ### Go to the project ui directory The raggenie UI is located in a subdirectory of the project. You must navigate to this directory to install the necessary dependencies and run the UI server. ```bash cd raggenie/ui ``` ### Install dependencies Once in the UI directory, the next step is to install the dependencies needed to run the UI. The dependencies include packages required by the frontend application to function correctly, including UI components, routing, and state management. ```bash npm install ``` Raggenie uses Node.js for frontend, for more details visit [Prerequesites](../Prerequesites.md) ### Start the server After installing the dependencies, you can start the development server, which will launch the raggenie UI in your browser. ```bash npm run dev ``` ================================================ FILE: documents/docs/How to run raggenie/Using Docker.md ================================================ --- sidebar_position: 3 --- # Using Docker The raggenie project includes both a Dockerfile and a Docker Compose file, located in the root folder of the repository. These files allow you to build and orchestrate the application using containers. If you have Docker installed on your machine, you can use the docker-compose.yml file to start the RAGGenie application and its associated services. This command will pull the necessary images, build the application, and start the containers. ```bash docker compose up ``` ================================================ FILE: documents/docs/How to run raggenie/_category_.json ================================================ { "label": "How to run raggenie", "position": 2, "link": { "type": "generated-index", "description": "Steps to run raggenie" } } ================================================ FILE: documents/docs/LLM Inferences.md ================================================ --- sidebar_position: 6 --- # LLM Inferences We currently support these LLM Inference endpoints. * [OpenAI](https://openai.com/index/openai-api/) * [Together.ai](https://www.together.ai/) ================================================ FILE: documents/docs/Prerequesites.md ================================================ --- sidebar_position: 1 --- # Prerequesites ## Backend ### Python Raggenie uses python to run its backend server. Currently supported versions are 3.10, 3.11 and 3.12. To install python, [download](https://www.python.org/downloads/) the version compatible. #### Poetry Poetry is required to install and run the dependancies for raggenie backend, you can install poetry, * using pip ```bash pip install poetry ``` * using curl ```bash curl -sSL https://install.python-poetry.org | python3 - ``` For more detailed explanation you can follow official [documentation](https://python-poetry.org/docs/#installation). To install rest of dependancies run ```bash poetry install ``` ## Frontend ### Node.js The ui requires Node.js for frontend, Currently only versions 20 and above is supported. To install Node [download](https://nodejs.org/en/download/package-manager) the version compatible. ### Npm You needs to use npm to install the requirements for ui, it is usually installed with Node.js To install ui dependancies * go to ui folder ```bash cd ui ``` * install dependancies ```bash npm install ``` ## Docker Raggenie provides docker compose file and docker files which can be used to run raggenie on containers. If you prefer to run raggenie on docker you can find how to install docker [here](https://docs.docker.com/get-started/). And to run raggenie using docker you can find instructions [here](./How%20to%20run%20raggenie/Using%20Docker.md) ================================================ FILE: documents/docusaurus.config.js ================================================ // @ts-check // `@type` JSDoc annotations allow editor autocompletion and type checking // (when paired with `@ts-check`). // There are various equivalent ways to declare your Docusaurus config. // See: https://docusaurus.io/docs/api/docusaurus-config import {themes as prismThemes} from 'prism-react-renderer'; /** @type {import('@docusaurus/types').Config} */ const config = { title: 'Raggenie', // tagline: 'Dinosaurs are cool' // Set the production url of your site here url: 'https://sirocco-ventures.github.io', // Set the // pathname under which your site is served // For GitHub pages deployment, it is often '//' baseUrl: '/raggenie/', // GitHub pages deployment config. // If you aren't using GitHub pages, you don't need these. organizationName: 'sirocco ventures', // Usually your GitHub org/user name. projectName: 'raggenie', // Usually your repo name. onBrokenLinks: 'throw', onBrokenMarkdownLinks: 'warn', // Even if you don't use internationalization, you can use this field to set // useful metadata like html lang. For example, if your site is Chinese, you // may want to replace "en" with "zh-Hans". i18n: { defaultLocale: 'en', locales: ['en'], }, presets: [ [ 'classic', /** @type {import('@docusaurus/preset-classic').Options} */ ({ docs: { sidebarPath: './sidebars.js', // Please change this to your repo. // Remove this to remove the "edit this page" links. editUrl: 'https://sirocco-ventures.github.io/raggenie/tree/main/documents', }, blog: false, theme: { customCss: './src/css/custom.css', }, }), ], ], themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ // Replace with your project's social card image: 'img/docusaurus-social-card.jpg', navbar: { title: 'RAGGENIE', logo: { alt: 'raggenie Logo', src: 'https://cdn.prod.website-files.com/664e485574efd184749b7301/6658314c55210573e334ac1b_Group%2042.png', }, items: [ { type: 'docSidebar', sidebarId: 'documentSidebar', position: 'left', label: 'Documents', }, { href: 'https://github.com/sirocco-ventures/raggenie', label: 'GitHub', position: 'right', }, ], }, footer: { style: 'dark', links: [ { title: 'Documents', items: [ { label: 'Docs', to: '/docs/Prerequesites', }, ], }, { title: 'Community', items: [ { label: 'Slack', href: 'https://join.slack.com/t/theailounge/shared_invite/zt-2ogkrruyf-FPOHuPr5hdqXl34bDWjHjw', }, ], }, { title: 'More', items: [ { label: 'GitHub', href: 'https://github.com/sirocco-ventures/raggenie', }, ], }, ], copyright: `Copyright © ${new Date().getFullYear()} RAGGENIE DOCS. Built with Docusaurus.`, }, prism: { theme: prismThemes.github, darkTheme: prismThemes.dracula, }, }), }; export default config; ================================================ FILE: documents/package.json ================================================ { "name": "documents", "version": "0.0.0", "private": true, "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", "build": "docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", "clear": "docusaurus clear", "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { "@docusaurus/core": "3.5.2", "@docusaurus/preset-classic": "3.5.2", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", "prism-react-renderer": "^2.3.0", "react": "^18.0.0", "react-dom": "^18.0.0" }, "devDependencies": { "@docusaurus/module-type-aliases": "3.5.2", "@docusaurus/types": "3.5.2" }, "browserslist": { "production": [ ">0.5%", "not dead", "not op_mini all" ], "development": [ "last 3 chrome version", "last 3 firefox version", "last 5 safari version" ] }, "engines": { "node": ">=18.0" } } ================================================ FILE: documents/sidebars.js ================================================ /** * Creating a sidebar enables you to: - create an ordered group of docs - render a sidebar for each doc of that group - provide next/previous navigation The sidebars can be generated from the filesystem, or explicitly defined here. Create as many sidebars as you want. */ // @ts-check /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ const sidebars = { // By default, Docusaurus generates a sidebar from the docs folder structure documentSidebar: [{type: 'autogenerated', dirName: '.'}], // But you can create a sidebar manually /* tutorialSidebar: [ 'intro', 'hello', { type: 'category', label: 'Tutorial', items: ['tutorial-basics/create-a-document'], }, ], */ }; export default sidebars; ================================================ FILE: documents/src/css/custom.css ================================================ /** * Any CSS included here will be global. The classic template * bundles Infima by default. Infima is a CSS framework designed to * work well for content-centric websites. */ /* You can override the default Infima variables here. */ :root { --ifm-color-primary: #3893ff; --ifm-color-primary-dark: #29784c; --ifm-color-primary-darker: #277148; --ifm-color-primary-darkest: #205d3b; --ifm-color-primary-light: #33925d; --ifm-color-primary-lighter: #359962; --ifm-color-primary-lightest: #3cad6e; --ifm-code-font-size: 95%; --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); } /* For readability concerns, you should choose a lighter palette in dark mode. */ [data-theme='dark'] { --ifm-color-primary: #3893ff; --ifm-color-primary-dark: #21af90; --ifm-color-primary-darker: #1fa588; --ifm-color-primary-darkest: #1a8870; --ifm-color-primary-light: #29d5b0; --ifm-color-primary-lighter: #32d8b4; --ifm-color-primary-lightest: #4fddbf; --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); } ================================================ FILE: documents/src/pages/index.md ================================================

RAGGENIE Logo

RAGGENIE

## Quick start ### Clone the project ```bash git clone https://github.com/sirocco-ventures/raggenie ``` ### Raggenie Backend * Installing dependencies * **Using `requirements.txt`** To install the required dependencies with `pip`, run: ```bash pip install -r requirements.txt ``` * **Using Poetry** First, install Poetry: ```bash curl -sSL https://install.python-poetry.org | python3 - ``` Then, to install the dependencies, run: ```bash poetry install ``` * Running RAGGENIE backend To run **RAGGENIE** in API mode, specify the config file to use by running the following command: ```bash python main.py --config ./config.yaml llm ``` Below is a sample configuration for the vector database setup in `config.yaml`: ```yaml vector_db: name: "chroma" params: path: "./vector_db" embeddings: provider: "chroma_default" ``` This configuration ensures that the RAGGENIE system connects to the `chroma` vector database and uses the default embeddings provided by Chroma. ### Raggenie Frontend * **Move into the ui folder.** ``` cd ./ui ``` * Install dependencies ```bash npm install ``` * Running RAGGENIE Frontend * To run **RAGGENIE** frontend, create a .env file and add the URL to backend as env variables ```env VITE_BACKEND_URL=${BACKEND_URL} ``` * To start the server, run ```bash npm run dev ``` ### Using Docker Both docker file and the docker compose files are present in the root folder. To run the model you can run ```bash docker compose up ``` ## Connectors/pluggins Different components in your LLM app can be inserted using plugins. ### Data Sources Currently these are the datasource plugins that are available in raggenie. #### Structred Datasources * [Postgressql](./docs/Connectors/Postgressql) * [Airtable](./docs/Connectors/Airtable) * [Bigquery](./docs/Connectors/Bigquery) #### Unstrunctured Datasources * [PDFs](./docs/Connectors/PDFs) * [Websites](./docs/Connectors/Websites) ## LLM Inferences We currently support these LLM Inference endpoints. * [OpenAI](https://openai.com/index/openai-api/) * [Together.ai](https://www.together.ai/) ================================================ FILE: documents/src/pages/index.module.css ================================================ /** * CSS files with the .module.css suffix will be treated as CSS modules * and scoped locally. */ .heroBanner { padding: 4rem 0; text-align: center; position: relative; overflow: hidden; } @media screen and (max-width: 996px) { .heroBanner { padding: 2rem; } } .buttons { display: flex; align-items: center; justify-content: center; } ================================================ FILE: documents/static/.nojekyll ================================================ ================================================ FILE: embeddings/onnx/model.onnx ================================================ [File too large to display: 86.2 MB] ================================================ FILE: embeddings/onnx/tokenizer.json ================================================ { "version": "1.0", "truncation": { "direction": "Right", "max_length": 128, "strategy": "LongestFirst", "stride": 0 }, "padding": { "strategy": { "Fixed": 128 }, "direction": "Right", "pad_to_multiple_of": null, "pad_id": 0, "pad_type_id": 0, "pad_token": "[PAD]" }, "added_tokens": [ { "id": 0, "content": "[PAD]", "single_word": false, "lstrip": false, "rstrip": false, "normalized": false, "special": true }, { "id": 100, "content": "[UNK]", "single_word": false, "lstrip": false, "rstrip": false, "normalized": false, "special": true }, { "id": 101, "content": "[CLS]", "single_word": false, "lstrip": false, "rstrip": false, "normalized": false, "special": true }, { "id": 102, "content": "[SEP]", "single_word": false, "lstrip": false, "rstrip": false, "normalized": false, "special": true }, { "id": 103, "content": "[MASK]", "single_word": false, "lstrip": false, "rstrip": false, "normalized": false, "special": true } ], "normalizer": { "type": "BertNormalizer", "clean_text": true, "handle_chinese_chars": true, "strip_accents": null, "lowercase": true }, "pre_tokenizer": { "type": "BertPreTokenizer" }, "post_processor": { "type": "TemplateProcessing", "single": [ { "SpecialToken": { "id": "[CLS]", "type_id": 0 } }, { "Sequence": { "id": "A", "type_id": 0 } }, { "SpecialToken": { "id": "[SEP]", "type_id": 0 } } ], "pair": [ { "SpecialToken": { "id": "[CLS]", "type_id": 0 } }, { "Sequence": { "id": "A", "type_id": 0 } }, { "SpecialToken": { "id": "[SEP]", "type_id": 0 } }, { "Sequence": { "id": "B", "type_id": 1 } }, { "SpecialToken": { "id": "[SEP]", "type_id": 1 } } ], "special_tokens": { "[CLS]": { "id": "[CLS]", "ids": [ 101 ], "tokens": [ "[CLS]" ] }, "[SEP]": { "id": "[SEP]", "ids": [ 102 ], "tokens": [ "[SEP]" ] } } }, "decoder": { "type": "WordPiece", "prefix": "##", "cleanup": true }, "model": { "type": "WordPiece", "unk_token": "[UNK]", "continuing_subword_prefix": "##", "max_input_chars_per_word": 100, "vocab": { "[PAD]": 0, "[unused0]": 1, "[unused1]": 2, "[unused2]": 3, "[unused3]": 4, "[unused4]": 5, "[unused5]": 6, "[unused6]": 7, "[unused7]": 8, "[unused8]": 9, "[unused9]": 10, "[unused10]": 11, "[unused11]": 12, "[unused12]": 13, "[unused13]": 14, "[unused14]": 15, "[unused15]": 16, "[unused16]": 17, "[unused17]": 18, "[unused18]": 19, "[unused19]": 20, "[unused20]": 21, "[unused21]": 22, "[unused22]": 23, "[unused23]": 24, "[unused24]": 25, "[unused25]": 26, "[unused26]": 27, "[unused27]": 28, "[unused28]": 29, "[unused29]": 30, "[unused30]": 31, "[unused31]": 32, "[unused32]": 33, "[unused33]": 34, "[unused34]": 35, "[unused35]": 36, "[unused36]": 37, "[unused37]": 38, "[unused38]": 39, "[unused39]": 40, "[unused40]": 41, "[unused41]": 42, "[unused42]": 43, "[unused43]": 44, "[unused44]": 45, "[unused45]": 46, "[unused46]": 47, "[unused47]": 48, "[unused48]": 49, "[unused49]": 50, "[unused50]": 51, "[unused51]": 52, "[unused52]": 53, "[unused53]": 54, "[unused54]": 55, "[unused55]": 56, "[unused56]": 57, "[unused57]": 58, "[unused58]": 59, "[unused59]": 60, "[unused60]": 61, "[unused61]": 62, "[unused62]": 63, "[unused63]": 64, "[unused64]": 65, "[unused65]": 66, "[unused66]": 67, "[unused67]": 68, "[unused68]": 69, "[unused69]": 70, "[unused70]": 71, "[unused71]": 72, "[unused72]": 73, "[unused73]": 74, "[unused74]": 75, "[unused75]": 76, "[unused76]": 77, "[unused77]": 78, "[unused78]": 79, "[unused79]": 80, "[unused80]": 81, "[unused81]": 82, "[unused82]": 83, "[unused83]": 84, "[unused84]": 85, "[unused85]": 86, "[unused86]": 87, "[unused87]": 88, "[unused88]": 89, "[unused89]": 90, "[unused90]": 91, "[unused91]": 92, "[unused92]": 93, "[unused93]": 94, "[unused94]": 95, "[unused95]": 96, "[unused96]": 97, "[unused97]": 98, "[unused98]": 99, "[UNK]": 100, "[CLS]": 101, "[SEP]": 102, "[MASK]": 103, "[unused99]": 104, "[unused100]": 105, "[unused101]": 106, "[unused102]": 107, "[unused103]": 108, "[unused104]": 109, "[unused105]": 110, "[unused106]": 111, "[unused107]": 112, "[unused108]": 113, "[unused109]": 114, "[unused110]": 115, "[unused111]": 116, "[unused112]": 117, "[unused113]": 118, "[unused114]": 119, "[unused115]": 120, "[unused116]": 121, "[unused117]": 122, "[unused118]": 123, "[unused119]": 124, "[unused120]": 125, "[unused121]": 126, "[unused122]": 127, "[unused123]": 128, "[unused124]": 129, "[unused125]": 130, "[unused126]": 131, "[unused127]": 132, "[unused128]": 133, "[unused129]": 134, "[unused130]": 135, "[unused131]": 136, "[unused132]": 137, "[unused133]": 138, "[unused134]": 139, "[unused135]": 140, "[unused136]": 141, "[unused137]": 142, "[unused138]": 143, "[unused139]": 144, "[unused140]": 145, "[unused141]": 146, "[unused142]": 147, "[unused143]": 148, "[unused144]": 149, "[unused145]": 150, "[unused146]": 151, "[unused147]": 152, "[unused148]": 153, "[unused149]": 154, "[unused150]": 155, "[unused151]": 156, "[unused152]": 157, "[unused153]": 158, "[unused154]": 159, "[unused155]": 160, "[unused156]": 161, "[unused157]": 162, "[unused158]": 163, "[unused159]": 164, "[unused160]": 165, "[unused161]": 166, "[unused162]": 167, "[unused163]": 168, "[unused164]": 169, "[unused165]": 170, "[unused166]": 171, "[unused167]": 172, "[unused168]": 173, "[unused169]": 174, "[unused170]": 175, "[unused171]": 176, "[unused172]": 177, "[unused173]": 178, "[unused174]": 179, "[unused175]": 180, "[unused176]": 181, "[unused177]": 182, "[unused178]": 183, "[unused179]": 184, "[unused180]": 185, "[unused181]": 186, "[unused182]": 187, "[unused183]": 188, "[unused184]": 189, "[unused185]": 190, "[unused186]": 191, "[unused187]": 192, "[unused188]": 193, "[unused189]": 194, "[unused190]": 195, "[unused191]": 196, "[unused192]": 197, "[unused193]": 198, "[unused194]": 199, "[unused195]": 200, "[unused196]": 201, "[unused197]": 202, "[unused198]": 203, "[unused199]": 204, "[unused200]": 205, "[unused201]": 206, "[unused202]": 207, "[unused203]": 208, "[unused204]": 209, "[unused205]": 210, "[unused206]": 211, "[unused207]": 212, "[unused208]": 213, "[unused209]": 214, "[unused210]": 215, "[unused211]": 216, "[unused212]": 217, "[unused213]": 218, "[unused214]": 219, "[unused215]": 220, "[unused216]": 221, "[unused217]": 222, "[unused218]": 223, "[unused219]": 224, "[unused220]": 225, "[unused221]": 226, "[unused222]": 227, "[unused223]": 228, "[unused224]": 229, "[unused225]": 230, "[unused226]": 231, "[unused227]": 232, "[unused228]": 233, "[unused229]": 234, "[unused230]": 235, "[unused231]": 236, "[unused232]": 237, "[unused233]": 238, "[unused234]": 239, "[unused235]": 240, "[unused236]": 241, "[unused237]": 242, "[unused238]": 243, "[unused239]": 244, "[unused240]": 245, "[unused241]": 246, "[unused242]": 247, "[unused243]": 248, "[unused244]": 249, "[unused245]": 250, "[unused246]": 251, "[unused247]": 252, "[unused248]": 253, "[unused249]": 254, "[unused250]": 255, "[unused251]": 256, "[unused252]": 257, "[unused253]": 258, "[unused254]": 259, "[unused255]": 260, "[unused256]": 261, "[unused257]": 262, "[unused258]": 263, "[unused259]": 264, "[unused260]": 265, "[unused261]": 266, "[unused262]": 267, "[unused263]": 268, "[unused264]": 269, "[unused265]": 270, "[unused266]": 271, "[unused267]": 272, "[unused268]": 273, "[unused269]": 274, "[unused270]": 275, "[unused271]": 276, "[unused272]": 277, "[unused273]": 278, "[unused274]": 279, "[unused275]": 280, "[unused276]": 281, "[unused277]": 282, "[unused278]": 283, "[unused279]": 284, "[unused280]": 285, "[unused281]": 286, "[unused282]": 287, "[unused283]": 288, "[unused284]": 289, "[unused285]": 290, "[unused286]": 291, "[unused287]": 292, "[unused288]": 293, "[unused289]": 294, "[unused290]": 295, "[unused291]": 296, "[unused292]": 297, "[unused293]": 298, "[unused294]": 299, "[unused295]": 300, "[unused296]": 301, "[unused297]": 302, "[unused298]": 303, "[unused299]": 304, "[unused300]": 305, "[unused301]": 306, "[unused302]": 307, "[unused303]": 308, "[unused304]": 309, "[unused305]": 310, "[unused306]": 311, "[unused307]": 312, "[unused308]": 313, "[unused309]": 314, "[unused310]": 315, "[unused311]": 316, "[unused312]": 317, "[unused313]": 318, "[unused314]": 319, "[unused315]": 320, "[unused316]": 321, "[unused317]": 322, "[unused318]": 323, "[unused319]": 324, "[unused320]": 325, "[unused321]": 326, "[unused322]": 327, "[unused323]": 328, "[unused324]": 329, "[unused325]": 330, "[unused326]": 331, "[unused327]": 332, "[unused328]": 333, "[unused329]": 334, "[unused330]": 335, "[unused331]": 336, "[unused332]": 337, "[unused333]": 338, "[unused334]": 339, "[unused335]": 340, "[unused336]": 341, "[unused337]": 342, "[unused338]": 343, "[unused339]": 344, "[unused340]": 345, "[unused341]": 346, "[unused342]": 347, "[unused343]": 348, "[unused344]": 349, "[unused345]": 350, "[unused346]": 351, "[unused347]": 352, "[unused348]": 353, "[unused349]": 354, "[unused350]": 355, "[unused351]": 356, "[unused352]": 357, "[unused353]": 358, "[unused354]": 359, "[unused355]": 360, "[unused356]": 361, "[unused357]": 362, "[unused358]": 363, "[unused359]": 364, "[unused360]": 365, "[unused361]": 366, "[unused362]": 367, "[unused363]": 368, "[unused364]": 369, "[unused365]": 370, "[unused366]": 371, "[unused367]": 372, "[unused368]": 373, "[unused369]": 374, "[unused370]": 375, "[unused371]": 376, "[unused372]": 377, "[unused373]": 378, "[unused374]": 379, "[unused375]": 380, "[unused376]": 381, "[unused377]": 382, "[unused378]": 383, "[unused379]": 384, "[unused380]": 385, "[unused381]": 386, "[unused382]": 387, "[unused383]": 388, "[unused384]": 389, "[unused385]": 390, "[unused386]": 391, "[unused387]": 392, "[unused388]": 393, "[unused389]": 394, "[unused390]": 395, "[unused391]": 396, "[unused392]": 397, "[unused393]": 398, "[unused394]": 399, "[unused395]": 400, "[unused396]": 401, "[unused397]": 402, "[unused398]": 403, "[unused399]": 404, "[unused400]": 405, "[unused401]": 406, "[unused402]": 407, "[unused403]": 408, "[unused404]": 409, "[unused405]": 410, "[unused406]": 411, "[unused407]": 412, "[unused408]": 413, "[unused409]": 414, "[unused410]": 415, "[unused411]": 416, "[unused412]": 417, "[unused413]": 418, "[unused414]": 419, "[unused415]": 420, "[unused416]": 421, "[unused417]": 422, "[unused418]": 423, "[unused419]": 424, "[unused420]": 425, "[unused421]": 426, "[unused422]": 427, "[unused423]": 428, "[unused424]": 429, "[unused425]": 430, "[unused426]": 431, "[unused427]": 432, "[unused428]": 433, "[unused429]": 434, "[unused430]": 435, "[unused431]": 436, "[unused432]": 437, "[unused433]": 438, "[unused434]": 439, "[unused435]": 440, "[unused436]": 441, "[unused437]": 442, "[unused438]": 443, "[unused439]": 444, "[unused440]": 445, "[unused441]": 446, "[unused442]": 447, "[unused443]": 448, "[unused444]": 449, "[unused445]": 450, "[unused446]": 451, "[unused447]": 452, "[unused448]": 453, "[unused449]": 454, "[unused450]": 455, "[unused451]": 456, "[unused452]": 457, "[unused453]": 458, "[unused454]": 459, "[unused455]": 460, "[unused456]": 461, "[unused457]": 462, "[unused458]": 463, "[unused459]": 464, "[unused460]": 465, "[unused461]": 466, "[unused462]": 467, "[unused463]": 468, "[unused464]": 469, "[unused465]": 470, "[unused466]": 471, "[unused467]": 472, "[unused468]": 473, "[unused469]": 474, "[unused470]": 475, "[unused471]": 476, "[unused472]": 477, "[unused473]": 478, "[unused474]": 479, "[unused475]": 480, "[unused476]": 481, "[unused477]": 482, "[unused478]": 483, "[unused479]": 484, "[unused480]": 485, "[unused481]": 486, "[unused482]": 487, "[unused483]": 488, "[unused484]": 489, "[unused485]": 490, "[unused486]": 491, "[unused487]": 492, "[unused488]": 493, "[unused489]": 494, "[unused490]": 495, "[unused491]": 496, "[unused492]": 497, "[unused493]": 498, "[unused494]": 499, "[unused495]": 500, "[unused496]": 501, "[unused497]": 502, "[unused498]": 503, "[unused499]": 504, "[unused500]": 505, "[unused501]": 506, "[unused502]": 507, "[unused503]": 508, "[unused504]": 509, "[unused505]": 510, "[unused506]": 511, "[unused507]": 512, "[unused508]": 513, "[unused509]": 514, "[unused510]": 515, "[unused511]": 516, "[unused512]": 517, "[unused513]": 518, "[unused514]": 519, "[unused515]": 520, "[unused516]": 521, "[unused517]": 522, "[unused518]": 523, "[unused519]": 524, "[unused520]": 525, "[unused521]": 526, "[unused522]": 527, "[unused523]": 528, "[unused524]": 529, "[unused525]": 530, "[unused526]": 531, "[unused527]": 532, "[unused528]": 533, "[unused529]": 534, "[unused530]": 535, "[unused531]": 536, "[unused532]": 537, "[unused533]": 538, "[unused534]": 539, "[unused535]": 540, "[unused536]": 541, "[unused537]": 542, "[unused538]": 543, "[unused539]": 544, "[unused540]": 545, "[unused541]": 546, "[unused542]": 547, "[unused543]": 548, "[unused544]": 549, "[unused545]": 550, "[unused546]": 551, "[unused547]": 552, "[unused548]": 553, "[unused549]": 554, "[unused550]": 555, "[unused551]": 556, "[unused552]": 557, "[unused553]": 558, "[unused554]": 559, "[unused555]": 560, "[unused556]": 561, "[unused557]": 562, "[unused558]": 563, "[unused559]": 564, "[unused560]": 565, "[unused561]": 566, "[unused562]": 567, "[unused563]": 568, "[unused564]": 569, "[unused565]": 570, "[unused566]": 571, "[unused567]": 572, "[unused568]": 573, "[unused569]": 574, "[unused570]": 575, "[unused571]": 576, "[unused572]": 577, "[unused573]": 578, "[unused574]": 579, "[unused575]": 580, "[unused576]": 581, "[unused577]": 582, "[unused578]": 583, "[unused579]": 584, "[unused580]": 585, "[unused581]": 586, "[unused582]": 587, "[unused583]": 588, "[unused584]": 589, "[unused585]": 590, "[unused586]": 591, "[unused587]": 592, "[unused588]": 593, "[unused589]": 594, "[unused590]": 595, "[unused591]": 596, "[unused592]": 597, "[unused593]": 598, "[unused594]": 599, "[unused595]": 600, "[unused596]": 601, "[unused597]": 602, "[unused598]": 603, "[unused599]": 604, "[unused600]": 605, "[unused601]": 606, "[unused602]": 607, "[unused603]": 608, "[unused604]": 609, "[unused605]": 610, "[unused606]": 611, "[unused607]": 612, "[unused608]": 613, "[unused609]": 614, "[unused610]": 615, "[unused611]": 616, "[unused612]": 617, "[unused613]": 618, "[unused614]": 619, "[unused615]": 620, "[unused616]": 621, "[unused617]": 622, "[unused618]": 623, "[unused619]": 624, "[unused620]": 625, "[unused621]": 626, "[unused622]": 627, "[unused623]": 628, "[unused624]": 629, "[unused625]": 630, "[unused626]": 631, "[unused627]": 632, "[unused628]": 633, "[unused629]": 634, "[unused630]": 635, "[unused631]": 636, "[unused632]": 637, "[unused633]": 638, "[unused634]": 639, "[unused635]": 640, "[unused636]": 641, "[unused637]": 642, "[unused638]": 643, "[unused639]": 644, "[unused640]": 645, "[unused641]": 646, "[unused642]": 647, "[unused643]": 648, "[unused644]": 649, "[unused645]": 650, "[unused646]": 651, "[unused647]": 652, "[unused648]": 653, "[unused649]": 654, "[unused650]": 655, "[unused651]": 656, "[unused652]": 657, "[unused653]": 658, "[unused654]": 659, "[unused655]": 660, "[unused656]": 661, "[unused657]": 662, "[unused658]": 663, "[unused659]": 664, "[unused660]": 665, "[unused661]": 666, "[unused662]": 667, "[unused663]": 668, "[unused664]": 669, "[unused665]": 670, "[unused666]": 671, "[unused667]": 672, "[unused668]": 673, "[unused669]": 674, "[unused670]": 675, "[unused671]": 676, "[unused672]": 677, "[unused673]": 678, "[unused674]": 679, "[unused675]": 680, "[unused676]": 681, "[unused677]": 682, "[unused678]": 683, "[unused679]": 684, "[unused680]": 685, "[unused681]": 686, "[unused682]": 687, "[unused683]": 688, "[unused684]": 689, "[unused685]": 690, "[unused686]": 691, "[unused687]": 692, "[unused688]": 693, "[unused689]": 694, "[unused690]": 695, "[unused691]": 696, "[unused692]": 697, "[unused693]": 698, "[unused694]": 699, "[unused695]": 700, "[unused696]": 701, "[unused697]": 702, "[unused698]": 703, "[unused699]": 704, "[unused700]": 705, "[unused701]": 706, "[unused702]": 707, "[unused703]": 708, "[unused704]": 709, "[unused705]": 710, "[unused706]": 711, "[unused707]": 712, "[unused708]": 713, "[unused709]": 714, "[unused710]": 715, "[unused711]": 716, "[unused712]": 717, "[unused713]": 718, "[unused714]": 719, "[unused715]": 720, "[unused716]": 721, "[unused717]": 722, "[unused718]": 723, "[unused719]": 724, "[unused720]": 725, "[unused721]": 726, "[unused722]": 727, "[unused723]": 728, "[unused724]": 729, "[unused725]": 730, "[unused726]": 731, "[unused727]": 732, "[unused728]": 733, "[unused729]": 734, "[unused730]": 735, "[unused731]": 736, "[unused732]": 737, "[unused733]": 738, "[unused734]": 739, "[unused735]": 740, "[unused736]": 741, "[unused737]": 742, "[unused738]": 743, "[unused739]": 744, "[unused740]": 745, "[unused741]": 746, "[unused742]": 747, "[unused743]": 748, "[unused744]": 749, "[unused745]": 750, "[unused746]": 751, "[unused747]": 752, "[unused748]": 753, "[unused749]": 754, "[unused750]": 755, "[unused751]": 756, "[unused752]": 757, "[unused753]": 758, "[unused754]": 759, "[unused755]": 760, "[unused756]": 761, "[unused757]": 762, "[unused758]": 763, "[unused759]": 764, "[unused760]": 765, "[unused761]": 766, "[unused762]": 767, "[unused763]": 768, "[unused764]": 769, "[unused765]": 770, "[unused766]": 771, "[unused767]": 772, "[unused768]": 773, "[unused769]": 774, "[unused770]": 775, "[unused771]": 776, "[unused772]": 777, "[unused773]": 778, "[unused774]": 779, "[unused775]": 780, "[unused776]": 781, "[unused777]": 782, "[unused778]": 783, "[unused779]": 784, "[unused780]": 785, "[unused781]": 786, "[unused782]": 787, "[unused783]": 788, "[unused784]": 789, "[unused785]": 790, "[unused786]": 791, "[unused787]": 792, "[unused788]": 793, "[unused789]": 794, "[unused790]": 795, "[unused791]": 796, "[unused792]": 797, "[unused793]": 798, "[unused794]": 799, "[unused795]": 800, "[unused796]": 801, "[unused797]": 802, "[unused798]": 803, "[unused799]": 804, "[unused800]": 805, "[unused801]": 806, "[unused802]": 807, "[unused803]": 808, "[unused804]": 809, "[unused805]": 810, "[unused806]": 811, "[unused807]": 812, "[unused808]": 813, "[unused809]": 814, "[unused810]": 815, "[unused811]": 816, "[unused812]": 817, "[unused813]": 818, "[unused814]": 819, "[unused815]": 820, "[unused816]": 821, "[unused817]": 822, "[unused818]": 823, "[unused819]": 824, "[unused820]": 825, "[unused821]": 826, "[unused822]": 827, "[unused823]": 828, "[unused824]": 829, "[unused825]": 830, "[unused826]": 831, "[unused827]": 832, "[unused828]": 833, "[unused829]": 834, "[unused830]": 835, "[unused831]": 836, "[unused832]": 837, "[unused833]": 838, "[unused834]": 839, "[unused835]": 840, "[unused836]": 841, "[unused837]": 842, "[unused838]": 843, "[unused839]": 844, "[unused840]": 845, "[unused841]": 846, "[unused842]": 847, "[unused843]": 848, "[unused844]": 849, "[unused845]": 850, "[unused846]": 851, "[unused847]": 852, "[unused848]": 853, "[unused849]": 854, "[unused850]": 855, "[unused851]": 856, "[unused852]": 857, "[unused853]": 858, "[unused854]": 859, "[unused855]": 860, "[unused856]": 861, "[unused857]": 862, "[unused858]": 863, "[unused859]": 864, "[unused860]": 865, "[unused861]": 866, "[unused862]": 867, "[unused863]": 868, "[unused864]": 869, "[unused865]": 870, "[unused866]": 871, "[unused867]": 872, "[unused868]": 873, "[unused869]": 874, "[unused870]": 875, "[unused871]": 876, "[unused872]": 877, "[unused873]": 878, "[unused874]": 879, "[unused875]": 880, "[unused876]": 881, "[unused877]": 882, "[unused878]": 883, "[unused879]": 884, "[unused880]": 885, "[unused881]": 886, "[unused882]": 887, "[unused883]": 888, "[unused884]": 889, "[unused885]": 890, "[unused886]": 891, "[unused887]": 892, "[unused888]": 893, "[unused889]": 894, "[unused890]": 895, "[unused891]": 896, "[unused892]": 897, "[unused893]": 898, "[unused894]": 899, "[unused895]": 900, "[unused896]": 901, "[unused897]": 902, "[unused898]": 903, "[unused899]": 904, "[unused900]": 905, "[unused901]": 906, "[unused902]": 907, "[unused903]": 908, "[unused904]": 909, "[unused905]": 910, "[unused906]": 911, "[unused907]": 912, "[unused908]": 913, "[unused909]": 914, "[unused910]": 915, "[unused911]": 916, "[unused912]": 917, "[unused913]": 918, "[unused914]": 919, "[unused915]": 920, "[unused916]": 921, "[unused917]": 922, "[unused918]": 923, "[unused919]": 924, "[unused920]": 925, "[unused921]": 926, "[unused922]": 927, "[unused923]": 928, "[unused924]": 929, "[unused925]": 930, "[unused926]": 931, "[unused927]": 932, "[unused928]": 933, "[unused929]": 934, "[unused930]": 935, "[unused931]": 936, "[unused932]": 937, "[unused933]": 938, "[unused934]": 939, "[unused935]": 940, "[unused936]": 941, "[unused937]": 942, "[unused938]": 943, "[unused939]": 944, "[unused940]": 945, "[unused941]": 946, "[unused942]": 947, "[unused943]": 948, "[unused944]": 949, "[unused945]": 950, "[unused946]": 951, "[unused947]": 952, "[unused948]": 953, "[unused949]": 954, "[unused950]": 955, "[unused951]": 956, "[unused952]": 957, "[unused953]": 958, "[unused954]": 959, "[unused955]": 960, "[unused956]": 961, "[unused957]": 962, "[unused958]": 963, "[unused959]": 964, "[unused960]": 965, "[unused961]": 966, "[unused962]": 967, "[unused963]": 968, "[unused964]": 969, "[unused965]": 970, "[unused966]": 971, "[unused967]": 972, "[unused968]": 973, "[unused969]": 974, "[unused970]": 975, "[unused971]": 976, "[unused972]": 977, "[unused973]": 978, "[unused974]": 979, "[unused975]": 980, "[unused976]": 981, "[unused977]": 982, "[unused978]": 983, "[unused979]": 984, "[unused980]": 985, "[unused981]": 986, "[unused982]": 987, "[unused983]": 988, "[unused984]": 989, "[unused985]": 990, "[unused986]": 991, "[unused987]": 992, "[unused988]": 993, "[unused989]": 994, "[unused990]": 995, "[unused991]": 996, "[unused992]": 997, "[unused993]": 998, "!": 999, "\"": 1000, "#": 1001, "$": 1002, "%": 1003, "&": 1004, "'": 1005, "(": 1006, ")": 1007, "*": 1008, "+": 1009, ",": 1010, "-": 1011, ".": 1012, "/": 1013, "0": 1014, "1": 1015, "2": 1016, "3": 1017, "4": 1018, "5": 1019, "6": 1020, "7": 1021, "8": 1022, "9": 1023, ":": 1024, ";": 1025, "<": 1026, "=": 1027, ">": 1028, "?": 1029, "@": 1030, "[": 1031, "\\": 1032, "]": 1033, "^": 1034, "_": 1035, "`": 1036, "a": 1037, "b": 1038, "c": 1039, "d": 1040, "e": 1041, "f": 1042, "g": 1043, "h": 1044, "i": 1045, "j": 1046, "k": 1047, "l": 1048, "m": 1049, "n": 1050, "o": 1051, "p": 1052, "q": 1053, "r": 1054, "s": 1055, "t": 1056, "u": 1057, "v": 1058, "w": 1059, "x": 1060, "y": 1061, "z": 1062, "{": 1063, "|": 1064, "}": 1065, "~": 1066, "¡": 1067, "¢": 1068, "£": 1069, "¤": 1070, "¥": 1071, "¦": 1072, "§": 1073, "¨": 1074, "©": 1075, "ª": 1076, "«": 1077, "¬": 1078, "®": 1079, "°": 1080, "±": 1081, "²": 1082, "³": 1083, "´": 1084, "µ": 1085, "¶": 1086, "·": 1087, "¹": 1088, "º": 1089, "»": 1090, "¼": 1091, "½": 1092, "¾": 1093, "¿": 1094, "×": 1095, "ß": 1096, "æ": 1097, "ð": 1098, "÷": 1099, "ø": 1100, "þ": 1101, "đ": 1102, "ħ": 1103, "ı": 1104, "ł": 1105, "ŋ": 1106, "œ": 1107, "ƒ": 1108, "ɐ": 1109, "ɑ": 1110, "ɒ": 1111, "ɔ": 1112, "ɕ": 1113, "ə": 1114, "ɛ": 1115, "ɡ": 1116, "ɣ": 1117, "ɨ": 1118, "ɪ": 1119, "ɫ": 1120, "ɬ": 1121, "ɯ": 1122, "ɲ": 1123, "ɴ": 1124, "ɹ": 1125, "ɾ": 1126, "ʀ": 1127, "ʁ": 1128, "ʂ": 1129, "ʃ": 1130, "ʉ": 1131, "ʊ": 1132, "ʋ": 1133, "ʌ": 1134, "ʎ": 1135, "ʐ": 1136, "ʑ": 1137, "ʒ": 1138, "ʔ": 1139, "ʰ": 1140, "ʲ": 1141, "ʳ": 1142, "ʷ": 1143, "ʸ": 1144, "ʻ": 1145, "ʼ": 1146, "ʾ": 1147, "ʿ": 1148, "ˈ": 1149, "ː": 1150, "ˡ": 1151, "ˢ": 1152, "ˣ": 1153, "ˤ": 1154, "α": 1155, "β": 1156, "γ": 1157, "δ": 1158, "ε": 1159, "ζ": 1160, "η": 1161, "θ": 1162, "ι": 1163, "κ": 1164, "λ": 1165, "μ": 1166, "ν": 1167, "ξ": 1168, "ο": 1169, "π": 1170, "ρ": 1171, "ς": 1172, "σ": 1173, "τ": 1174, "υ": 1175, "φ": 1176, "χ": 1177, "ψ": 1178, "ω": 1179, "а": 1180, "б": 1181, "в": 1182, "г": 1183, "д": 1184, "е": 1185, "ж": 1186, "з": 1187, "и": 1188, "к": 1189, "л": 1190, "м": 1191, "н": 1192, "о": 1193, "п": 1194, "р": 1195, "с": 1196, "т": 1197, "у": 1198, "ф": 1199, "х": 1200, "ц": 1201, "ч": 1202, "ш": 1203, "щ": 1204, "ъ": 1205, "ы": 1206, "ь": 1207, "э": 1208, "ю": 1209, "я": 1210, "ђ": 1211, "є": 1212, "і": 1213, "ј": 1214, "љ": 1215, "њ": 1216, "ћ": 1217, "ӏ": 1218, "ա": 1219, "բ": 1220, "գ": 1221, "դ": 1222, "ե": 1223, "թ": 1224, "ի": 1225, "լ": 1226, "կ": 1227, "հ": 1228, "մ": 1229, "յ": 1230, "ն": 1231, "ո": 1232, "պ": 1233, "ս": 1234, "վ": 1235, "տ": 1236, "ր": 1237, "ւ": 1238, "ք": 1239, "־": 1240, "א": 1241, "ב": 1242, "ג": 1243, "ד": 1244, "ה": 1245, "ו": 1246, "ז": 1247, "ח": 1248, "ט": 1249, "י": 1250, "ך": 1251, "כ": 1252, "ל": 1253, "ם": 1254, "מ": 1255, "ן": 1256, "נ": 1257, "ס": 1258, "ע": 1259, "ף": 1260, "פ": 1261, "ץ": 1262, "צ": 1263, "ק": 1264, "ר": 1265, "ש": 1266, "ת": 1267, "،": 1268, "ء": 1269, "ا": 1270, "ب": 1271, "ة": 1272, "ت": 1273, "ث": 1274, "ج": 1275, "ح": 1276, "خ": 1277, "د": 1278, "ذ": 1279, "ر": 1280, "ز": 1281, "س": 1282, "ش": 1283, "ص": 1284, "ض": 1285, "ط": 1286, "ظ": 1287, "ع": 1288, "غ": 1289, "ـ": 1290, "ف": 1291, "ق": 1292, "ك": 1293, "ل": 1294, "م": 1295, "ن": 1296, "ه": 1297, "و": 1298, "ى": 1299, "ي": 1300, "ٹ": 1301, "پ": 1302, "چ": 1303, "ک": 1304, "گ": 1305, "ں": 1306, "ھ": 1307, "ہ": 1308, "ی": 1309, "ے": 1310, "अ": 1311, "आ": 1312, "उ": 1313, "ए": 1314, "क": 1315, "ख": 1316, "ग": 1317, "च": 1318, "ज": 1319, "ट": 1320, "ड": 1321, "ण": 1322, "त": 1323, "थ": 1324, "द": 1325, "ध": 1326, "न": 1327, "प": 1328, "ब": 1329, "भ": 1330, "म": 1331, "य": 1332, "र": 1333, "ल": 1334, "व": 1335, "श": 1336, "ष": 1337, "स": 1338, "ह": 1339, "ा": 1340, "ि": 1341, "ी": 1342, "ो": 1343, "।": 1344, "॥": 1345, "ং": 1346, "অ": 1347, "আ": 1348, "ই": 1349, "উ": 1350, "এ": 1351, "ও": 1352, "ক": 1353, "খ": 1354, "গ": 1355, "চ": 1356, "ছ": 1357, "জ": 1358, "ট": 1359, "ড": 1360, "ণ": 1361, "ত": 1362, "থ": 1363, "দ": 1364, "ধ": 1365, "ন": 1366, "প": 1367, "ব": 1368, "ভ": 1369, "ম": 1370, "য": 1371, "র": 1372, "ল": 1373, "শ": 1374, "ষ": 1375, "স": 1376, "হ": 1377, "া": 1378, "ি": 1379, "ী": 1380, "ে": 1381, "க": 1382, "ச": 1383, "ட": 1384, "த": 1385, "ந": 1386, "ன": 1387, "ப": 1388, "ம": 1389, "ய": 1390, "ர": 1391, "ல": 1392, "ள": 1393, "வ": 1394, "ா": 1395, "ி": 1396, "ு": 1397, "ே": 1398, "ை": 1399, "ನ": 1400, "ರ": 1401, "ಾ": 1402, "ක": 1403, "ය": 1404, "ර": 1405, "ල": 1406, "ව": 1407, "ා": 1408, "ก": 1409, "ง": 1410, "ต": 1411, "ท": 1412, "น": 1413, "พ": 1414, "ม": 1415, "ย": 1416, "ร": 1417, "ล": 1418, "ว": 1419, "ส": 1420, "อ": 1421, "า": 1422, "เ": 1423, "་": 1424, "།": 1425, "ག": 1426, "ང": 1427, "ད": 1428, "ན": 1429, "པ": 1430, "བ": 1431, "མ": 1432, "འ": 1433, "ར": 1434, "ལ": 1435, "ས": 1436, "မ": 1437, "ა": 1438, "ბ": 1439, "გ": 1440, "დ": 1441, "ე": 1442, "ვ": 1443, "თ": 1444, "ი": 1445, "კ": 1446, "ლ": 1447, "მ": 1448, "ნ": 1449, "ო": 1450, "რ": 1451, "ს": 1452, "ტ": 1453, "უ": 1454, "ᄀ": 1455, "ᄂ": 1456, "ᄃ": 1457, "ᄅ": 1458, "ᄆ": 1459, "ᄇ": 1460, "ᄉ": 1461, "ᄊ": 1462, "ᄋ": 1463, "ᄌ": 1464, "ᄎ": 1465, "ᄏ": 1466, "ᄐ": 1467, "ᄑ": 1468, "ᄒ": 1469, "ᅡ": 1470, "ᅢ": 1471, "ᅥ": 1472, "ᅦ": 1473, "ᅧ": 1474, "ᅩ": 1475, "ᅪ": 1476, "ᅭ": 1477, "ᅮ": 1478, "ᅯ": 1479, "ᅲ": 1480, "ᅳ": 1481, "ᅴ": 1482, "ᅵ": 1483, "ᆨ": 1484, "ᆫ": 1485, "ᆯ": 1486, "ᆷ": 1487, "ᆸ": 1488, "ᆼ": 1489, "ᴬ": 1490, "ᴮ": 1491, "ᴰ": 1492, "ᴵ": 1493, "ᴺ": 1494, "ᵀ": 1495, "ᵃ": 1496, "ᵇ": 1497, "ᵈ": 1498, "ᵉ": 1499, "ᵍ": 1500, "ᵏ": 1501, "ᵐ": 1502, "ᵒ": 1503, "ᵖ": 1504, "ᵗ": 1505, "ᵘ": 1506, "ᵢ": 1507, "ᵣ": 1508, "ᵤ": 1509, "ᵥ": 1510, "ᶜ": 1511, "ᶠ": 1512, "‐": 1513, "‑": 1514, "‒": 1515, "–": 1516, "—": 1517, "―": 1518, "‖": 1519, "‘": 1520, "’": 1521, "‚": 1522, "“": 1523, "”": 1524, "„": 1525, "†": 1526, "‡": 1527, "•": 1528, "…": 1529, "‰": 1530, "′": 1531, "″": 1532, "›": 1533, "‿": 1534, "⁄": 1535, "⁰": 1536, "ⁱ": 1537, "⁴": 1538, "⁵": 1539, "⁶": 1540, "⁷": 1541, "⁸": 1542, "⁹": 1543, "⁺": 1544, "⁻": 1545, "ⁿ": 1546, "₀": 1547, "₁": 1548, "₂": 1549, "₃": 1550, "₄": 1551, "₅": 1552, "₆": 1553, "₇": 1554, "₈": 1555, "₉": 1556, "₊": 1557, "₍": 1558, "₎": 1559, "ₐ": 1560, "ₑ": 1561, "ₒ": 1562, "ₓ": 1563, "ₕ": 1564, "ₖ": 1565, "ₗ": 1566, "ₘ": 1567, "ₙ": 1568, "ₚ": 1569, "ₛ": 1570, "ₜ": 1571, "₤": 1572, "₩": 1573, "€": 1574, "₱": 1575, "₹": 1576, "ℓ": 1577, "№": 1578, "ℝ": 1579, "™": 1580, "⅓": 1581, "⅔": 1582, "←": 1583, "↑": 1584, "→": 1585, "↓": 1586, "↔": 1587, "↦": 1588, "⇄": 1589, "⇌": 1590, "⇒": 1591, "∂": 1592, "∅": 1593, "∆": 1594, "∇": 1595, "∈": 1596, "−": 1597, "∗": 1598, "∘": 1599, "√": 1600, "∞": 1601, "∧": 1602, "∨": 1603, "∩": 1604, "∪": 1605, "≈": 1606, "≡": 1607, "≤": 1608, "≥": 1609, "⊂": 1610, "⊆": 1611, "⊕": 1612, "⊗": 1613, "⋅": 1614, "─": 1615, "│": 1616, "■": 1617, "▪": 1618, "●": 1619, "★": 1620, "☆": 1621, "☉": 1622, "♠": 1623, "♣": 1624, "♥": 1625, "♦": 1626, "♭": 1627, "♯": 1628, "⟨": 1629, "⟩": 1630, "ⱼ": 1631, "⺩": 1632, "⺼": 1633, "⽥": 1634, "、": 1635, "。": 1636, "〈": 1637, "〉": 1638, "《": 1639, "》": 1640, "「": 1641, "」": 1642, "『": 1643, "』": 1644, "〜": 1645, "あ": 1646, "い": 1647, "う": 1648, "え": 1649, "お": 1650, "か": 1651, "き": 1652, "く": 1653, "け": 1654, "こ": 1655, "さ": 1656, "し": 1657, "す": 1658, "せ": 1659, "そ": 1660, "た": 1661, "ち": 1662, "っ": 1663, "つ": 1664, "て": 1665, "と": 1666, "な": 1667, "に": 1668, "ぬ": 1669, "ね": 1670, "の": 1671, "は": 1672, "ひ": 1673, "ふ": 1674, "へ": 1675, "ほ": 1676, "ま": 1677, "み": 1678, "む": 1679, "め": 1680, "も": 1681, "や": 1682, "ゆ": 1683, "よ": 1684, "ら": 1685, "り": 1686, "る": 1687, "れ": 1688, "ろ": 1689, "を": 1690, "ん": 1691, "ァ": 1692, "ア": 1693, "ィ": 1694, "イ": 1695, "ウ": 1696, "ェ": 1697, "エ": 1698, "オ": 1699, "カ": 1700, "キ": 1701, "ク": 1702, "ケ": 1703, "コ": 1704, "サ": 1705, "シ": 1706, "ス": 1707, "セ": 1708, "タ": 1709, "チ": 1710, "ッ": 1711, "ツ": 1712, "テ": 1713, "ト": 1714, "ナ": 1715, "ニ": 1716, "ノ": 1717, "ハ": 1718, "ヒ": 1719, "フ": 1720, "ヘ": 1721, "ホ": 1722, "マ": 1723, "ミ": 1724, "ム": 1725, "メ": 1726, "モ": 1727, "ャ": 1728, "ュ": 1729, "ョ": 1730, "ラ": 1731, "リ": 1732, "ル": 1733, "レ": 1734, "ロ": 1735, "ワ": 1736, "ン": 1737, "・": 1738, "ー": 1739, "一": 1740, "三": 1741, "上": 1742, "下": 1743, "不": 1744, "世": 1745, "中": 1746, "主": 1747, "久": 1748, "之": 1749, "也": 1750, "事": 1751, "二": 1752, "五": 1753, "井": 1754, "京": 1755, "人": 1756, "亻": 1757, "仁": 1758, "介": 1759, "代": 1760, "仮": 1761, "伊": 1762, "会": 1763, "佐": 1764, "侍": 1765, "保": 1766, "信": 1767, "健": 1768, "元": 1769, "光": 1770, "八": 1771, "公": 1772, "内": 1773, "出": 1774, "分": 1775, "前": 1776, "劉": 1777, "力": 1778, "加": 1779, "勝": 1780, "北": 1781, "区": 1782, "十": 1783, "千": 1784, "南": 1785, "博": 1786, "原": 1787, "口": 1788, "古": 1789, "史": 1790, "司": 1791, "合": 1792, "吉": 1793, "同": 1794, "名": 1795, "和": 1796, "囗": 1797, "四": 1798, "国": 1799, "國": 1800, "土": 1801, "地": 1802, "坂": 1803, "城": 1804, "堂": 1805, "場": 1806, "士": 1807, "夏": 1808, "外": 1809, "大": 1810, "天": 1811, "太": 1812, "夫": 1813, "奈": 1814, "女": 1815, "子": 1816, "学": 1817, "宀": 1818, "宇": 1819, "安": 1820, "宗": 1821, "定": 1822, "宣": 1823, "宮": 1824, "家": 1825, "宿": 1826, "寺": 1827, "將": 1828, "小": 1829, "尚": 1830, "山": 1831, "岡": 1832, "島": 1833, "崎": 1834, "川": 1835, "州": 1836, "巿": 1837, "帝": 1838, "平": 1839, "年": 1840, "幸": 1841, "广": 1842, "弘": 1843, "張": 1844, "彳": 1845, "後": 1846, "御": 1847, "德": 1848, "心": 1849, "忄": 1850, "志": 1851, "忠": 1852, "愛": 1853, "成": 1854, "我": 1855, "戦": 1856, "戸": 1857, "手": 1858, "扌": 1859, "政": 1860, "文": 1861, "新": 1862, "方": 1863, "日": 1864, "明": 1865, "星": 1866, "春": 1867, "昭": 1868, "智": 1869, "曲": 1870, "書": 1871, "月": 1872, "有": 1873, "朝": 1874, "木": 1875, "本": 1876, "李": 1877, "村": 1878, "東": 1879, "松": 1880, "林": 1881, "森": 1882, "楊": 1883, "樹": 1884, "橋": 1885, "歌": 1886, "止": 1887, "正": 1888, "武": 1889, "比": 1890, "氏": 1891, "民": 1892, "水": 1893, "氵": 1894, "氷": 1895, "永": 1896, "江": 1897, "沢": 1898, "河": 1899, "治": 1900, "法": 1901, "海": 1902, "清": 1903, "漢": 1904, "瀬": 1905, "火": 1906, "版": 1907, "犬": 1908, "王": 1909, "生": 1910, "田": 1911, "男": 1912, "疒": 1913, "発": 1914, "白": 1915, "的": 1916, "皇": 1917, "目": 1918, "相": 1919, "省": 1920, "真": 1921, "石": 1922, "示": 1923, "社": 1924, "神": 1925, "福": 1926, "禾": 1927, "秀": 1928, "秋": 1929, "空": 1930, "立": 1931, "章": 1932, "竹": 1933, "糹": 1934, "美": 1935, "義": 1936, "耳": 1937, "良": 1938, "艹": 1939, "花": 1940, "英": 1941, "華": 1942, "葉": 1943, "藤": 1944, "行": 1945, "街": 1946, "西": 1947, "見": 1948, "訁": 1949, "語": 1950, "谷": 1951, "貝": 1952, "貴": 1953, "車": 1954, "軍": 1955, "辶": 1956, "道": 1957, "郎": 1958, "郡": 1959, "部": 1960, "都": 1961, "里": 1962, "野": 1963, "金": 1964, "鈴": 1965, "镇": 1966, "長": 1967, "門": 1968, "間": 1969, "阝": 1970, "阿": 1971, "陳": 1972, "陽": 1973, "雄": 1974, "青": 1975, "面": 1976, "風": 1977, "食": 1978, "香": 1979, "馬": 1980, "高": 1981, "龍": 1982, "龸": 1983, "fi": 1984, "fl": 1985, "!": 1986, "(": 1987, ")": 1988, ",": 1989, "-": 1990, ".": 1991, "/": 1992, ":": 1993, "?": 1994, "~": 1995, "the": 1996, "of": 1997, "and": 1998, "in": 1999, "to": 2000, "was": 2001, "he": 2002, "is": 2003, "as": 2004, "for": 2005, "on": 2006, "with": 2007, "that": 2008, "it": 2009, "his": 2010, "by": 2011, "at": 2012, "from": 2013, "her": 2014, "##s": 2015, "she": 2016, "you": 2017, "had": 2018, "an": 2019, "were": 2020, "but": 2021, "be": 2022, "this": 2023, "are": 2024, "not": 2025, "my": 2026, "they": 2027, "one": 2028, "which": 2029, "or": 2030, "have": 2031, "him": 2032, "me": 2033, "first": 2034, "all": 2035, "also": 2036, "their": 2037, "has": 2038, "up": 2039, "who": 2040, "out": 2041, "been": 2042, "when": 2043, "after": 2044, "there": 2045, "into": 2046, "new": 2047, "two": 2048, "its": 2049, "##a": 2050, "time": 2051, "would": 2052, "no": 2053, "what": 2054, "about": 2055, "said": 2056, "we": 2057, "over": 2058, "then": 2059, "other": 2060, "so": 2061, "more": 2062, "##e": 2063, "can": 2064, "if": 2065, "like": 2066, "back": 2067, "them": 2068, "only": 2069, "some": 2070, "could": 2071, "##i": 2072, "where": 2073, "just": 2074, "##ing": 2075, "during": 2076, "before": 2077, "##n": 2078, "do": 2079, "##o": 2080, "made": 2081, "school": 2082, "through": 2083, "than": 2084, "now": 2085, "years": 2086, "most": 2087, "world": 2088, "may": 2089, "between": 2090, "down": 2091, "well": 2092, "three": 2093, "##d": 2094, "year": 2095, "while": 2096, "will": 2097, "##ed": 2098, "##r": 2099, "##y": 2100, "later": 2101, "##t": 2102, "city": 2103, "under": 2104, "around": 2105, "did": 2106, "such": 2107, "being": 2108, "used": 2109, "state": 2110, "people": 2111, "part": 2112, "know": 2113, "against": 2114, "your": 2115, "many": 2116, "second": 2117, "university": 2118, "both": 2119, "national": 2120, "##er": 2121, "these": 2122, "don": 2123, "known": 2124, "off": 2125, "way": 2126, "until": 2127, "re": 2128, "how": 2129, "even": 2130, "get": 2131, "head": 2132, "...": 2133, "didn": 2134, "##ly": 2135, "team": 2136, "american": 2137, "because": 2138, "de": 2139, "##l": 2140, "born": 2141, "united": 2142, "film": 2143, "since": 2144, "still": 2145, "long": 2146, "work": 2147, "south": 2148, "us": 2149, "became": 2150, "any": 2151, "high": 2152, "again": 2153, "day": 2154, "family": 2155, "see": 2156, "right": 2157, "man": 2158, "eyes": 2159, "house": 2160, "season": 2161, "war": 2162, "states": 2163, "including": 2164, "took": 2165, "life": 2166, "north": 2167, "same": 2168, "each": 2169, "called": 2170, "name": 2171, "much": 2172, "place": 2173, "however": 2174, "go": 2175, "four": 2176, "group": 2177, "another": 2178, "found": 2179, "won": 2180, "area": 2181, "here": 2182, "going": 2183, "10": 2184, "away": 2185, "series": 2186, "left": 2187, "home": 2188, "music": 2189, "best": 2190, "make": 2191, "hand": 2192, "number": 2193, "company": 2194, "several": 2195, "never": 2196, "last": 2197, "john": 2198, "000": 2199, "very": 2200, "album": 2201, "take": 2202, "end": 2203, "good": 2204, "too": 2205, "following": 2206, "released": 2207, "game": 2208, "played": 2209, "little": 2210, "began": 2211, "district": 2212, "##m": 2213, "old": 2214, "want": 2215, "those": 2216, "side": 2217, "held": 2218, "own": 2219, "early": 2220, "county": 2221, "ll": 2222, "league": 2223, "use": 2224, "west": 2225, "##u": 2226, "face": 2227, "think": 2228, "##es": 2229, "2010": 2230, "government": 2231, "##h": 2232, "march": 2233, "came": 2234, "small": 2235, "general": 2236, "town": 2237, "june": 2238, "##on": 2239, "line": 2240, "based": 2241, "something": 2242, "##k": 2243, "september": 2244, "thought": 2245, "looked": 2246, "along": 2247, "international": 2248, "2011": 2249, "air": 2250, "july": 2251, "club": 2252, "went": 2253, "january": 2254, "october": 2255, "our": 2256, "august": 2257, "april": 2258, "york": 2259, "12": 2260, "few": 2261, "2012": 2262, "2008": 2263, "east": 2264, "show": 2265, "member": 2266, "college": 2267, "2009": 2268, "father": 2269, "public": 2270, "##us": 2271, "come": 2272, "men": 2273, "five": 2274, "set": 2275, "station": 2276, "church": 2277, "##c": 2278, "next": 2279, "former": 2280, "november": 2281, "room": 2282, "party": 2283, "located": 2284, "december": 2285, "2013": 2286, "age": 2287, "got": 2288, "2007": 2289, "##g": 2290, "system": 2291, "let": 2292, "love": 2293, "2006": 2294, "though": 2295, "every": 2296, "2014": 2297, "look": 2298, "song": 2299, "water": 2300, "century": 2301, "without": 2302, "body": 2303, "black": 2304, "night": 2305, "within": 2306, "great": 2307, "women": 2308, "single": 2309, "ve": 2310, "building": 2311, "large": 2312, "population": 2313, "river": 2314, "named": 2315, "band": 2316, "white": 2317, "started": 2318, "##an": 2319, "once": 2320, "15": 2321, "20": 2322, "should": 2323, "18": 2324, "2015": 2325, "service": 2326, "top": 2327, "built": 2328, "british": 2329, "open": 2330, "death": 2331, "king": 2332, "moved": 2333, "local": 2334, "times": 2335, "children": 2336, "february": 2337, "book": 2338, "why": 2339, "11": 2340, "door": 2341, "need": 2342, "president": 2343, "order": 2344, "final": 2345, "road": 2346, "wasn": 2347, "although": 2348, "due": 2349, "major": 2350, "died": 2351, "village": 2352, "third": 2353, "knew": 2354, "2016": 2355, "asked": 2356, "turned": 2357, "st": 2358, "wanted": 2359, "say": 2360, "##p": 2361, "together": 2362, "received": 2363, "main": 2364, "son": 2365, "served": 2366, "different": 2367, "##en": 2368, "behind": 2369, "himself": 2370, "felt": 2371, "members": 2372, "power": 2373, "football": 2374, "law": 2375, "voice": 2376, "play": 2377, "##in": 2378, "near": 2379, "park": 2380, "history": 2381, "30": 2382, "having": 2383, "2005": 2384, "16": 2385, "##man": 2386, "saw": 2387, "mother": 2388, "##al": 2389, "army": 2390, "point": 2391, "front": 2392, "help": 2393, "english": 2394, "street": 2395, "art": 2396, "late": 2397, "hands": 2398, "games": 2399, "award": 2400, "##ia": 2401, "young": 2402, "14": 2403, "put": 2404, "published": 2405, "country": 2406, "division": 2407, "across": 2408, "told": 2409, "13": 2410, "often": 2411, "ever": 2412, "french": 2413, "london": 2414, "center": 2415, "six": 2416, "red": 2417, "2017": 2418, "led": 2419, "days": 2420, "include": 2421, "light": 2422, "25": 2423, "find": 2424, "tell": 2425, "among": 2426, "species": 2427, "really": 2428, "according": 2429, "central": 2430, "half": 2431, "2004": 2432, "form": 2433, "original": 2434, "gave": 2435, "office": 2436, "making": 2437, "enough": 2438, "lost": 2439, "full": 2440, "opened": 2441, "must": 2442, "included": 2443, "live": 2444, "given": 2445, "german": 2446, "player": 2447, "run": 2448, "business": 2449, "woman": 2450, "community": 2451, "cup": 2452, "might": 2453, "million": 2454, "land": 2455, "2000": 2456, "court": 2457, "development": 2458, "17": 2459, "short": 2460, "round": 2461, "ii": 2462, "km": 2463, "seen": 2464, "class": 2465, "story": 2466, "always": 2467, "become": 2468, "sure": 2469, "research": 2470, "almost": 2471, "director": 2472, "council": 2473, "la": 2474, "##2": 2475, "career": 2476, "things": 2477, "using": 2478, "island": 2479, "##z": 2480, "couldn": 2481, "car": 2482, "##is": 2483, "24": 2484, "close": 2485, "force": 2486, "##1": 2487, "better": 2488, "free": 2489, "support": 2490, "control": 2491, "field": 2492, "students": 2493, "2003": 2494, "education": 2495, "married": 2496, "##b": 2497, "nothing": 2498, "worked": 2499, "others": 2500, "record": 2501, "big": 2502, "inside": 2503, "level": 2504, "anything": 2505, "continued": 2506, "give": 2507, "james": 2508, "##3": 2509, "military": 2510, "established": 2511, "non": 2512, "returned": 2513, "feel": 2514, "does": 2515, "title": 2516, "written": 2517, "thing": 2518, "feet": 2519, "william": 2520, "far": 2521, "co": 2522, "association": 2523, "hard": 2524, "already": 2525, "2002": 2526, "##ra": 2527, "championship": 2528, "human": 2529, "western": 2530, "100": 2531, "##na": 2532, "department": 2533, "hall": 2534, "role": 2535, "various": 2536, "production": 2537, "21": 2538, "19": 2539, "heart": 2540, "2001": 2541, "living": 2542, "fire": 2543, "version": 2544, "##ers": 2545, "##f": 2546, "television": 2547, "royal": 2548, "##4": 2549, "produced": 2550, "working": 2551, "act": 2552, "case": 2553, "society": 2554, "region": 2555, "present": 2556, "radio": 2557, "period": 2558, "looking": 2559, "least": 2560, "total": 2561, "keep": 2562, "england": 2563, "wife": 2564, "program": 2565, "per": 2566, "brother": 2567, "mind": 2568, "special": 2569, "22": 2570, "##le": 2571, "am": 2572, "works": 2573, "soon": 2574, "##6": 2575, "political": 2576, "george": 2577, "services": 2578, "taken": 2579, "created": 2580, "##7": 2581, "further": 2582, "able": 2583, "reached": 2584, "david": 2585, "union": 2586, "joined": 2587, "upon": 2588, "done": 2589, "important": 2590, "social": 2591, "information": 2592, "either": 2593, "##ic": 2594, "##x": 2595, "appeared": 2596, "position": 2597, "ground": 2598, "lead": 2599, "rock": 2600, "dark": 2601, "election": 2602, "23": 2603, "board": 2604, "france": 2605, "hair": 2606, "course": 2607, "arms": 2608, "site": 2609, "police": 2610, "girl": 2611, "instead": 2612, "real": 2613, "sound": 2614, "##v": 2615, "words": 2616, "moment": 2617, "##te": 2618, "someone": 2619, "##8": 2620, "summer": 2621, "project": 2622, "announced": 2623, "san": 2624, "less": 2625, "wrote": 2626, "past": 2627, "followed": 2628, "##5": 2629, "blue": 2630, "founded": 2631, "al": 2632, "finally": 2633, "india": 2634, "taking": 2635, "records": 2636, "america": 2637, "##ne": 2638, "1999": 2639, "design": 2640, "considered": 2641, "northern": 2642, "god": 2643, "stop": 2644, "battle": 2645, "toward": 2646, "european": 2647, "outside": 2648, "described": 2649, "track": 2650, "today": 2651, "playing": 2652, "language": 2653, "28": 2654, "call": 2655, "26": 2656, "heard": 2657, "professional": 2658, "low": 2659, "australia": 2660, "miles": 2661, "california": 2662, "win": 2663, "yet": 2664, "green": 2665, "##ie": 2666, "trying": 2667, "blood": 2668, "##ton": 2669, "southern": 2670, "science": 2671, "maybe": 2672, "everything": 2673, "match": 2674, "square": 2675, "27": 2676, "mouth": 2677, "video": 2678, "race": 2679, "recorded": 2680, "leave": 2681, "above": 2682, "##9": 2683, "daughter": 2684, "points": 2685, "space": 2686, "1998": 2687, "museum": 2688, "change": 2689, "middle": 2690, "common": 2691, "##0": 2692, "move": 2693, "tv": 2694, "post": 2695, "##ta": 2696, "lake": 2697, "seven": 2698, "tried": 2699, "elected": 2700, "closed": 2701, "ten": 2702, "paul": 2703, "minister": 2704, "##th": 2705, "months": 2706, "start": 2707, "chief": 2708, "return": 2709, "canada": 2710, "person": 2711, "sea": 2712, "release": 2713, "similar": 2714, "modern": 2715, "brought": 2716, "rest": 2717, "hit": 2718, "formed": 2719, "mr": 2720, "##la": 2721, "1997": 2722, "floor": 2723, "event": 2724, "doing": 2725, "thomas": 2726, "1996": 2727, "robert": 2728, "care": 2729, "killed": 2730, "training": 2731, "star": 2732, "week": 2733, "needed": 2734, "turn": 2735, "finished": 2736, "railway": 2737, "rather": 2738, "news": 2739, "health": 2740, "sent": 2741, "example": 2742, "ran": 2743, "term": 2744, "michael": 2745, "coming": 2746, "currently": 2747, "yes": 2748, "forces": 2749, "despite": 2750, "gold": 2751, "areas": 2752, "50": 2753, "stage": 2754, "fact": 2755, "29": 2756, "dead": 2757, "says": 2758, "popular": 2759, "2018": 2760, "originally": 2761, "germany": 2762, "probably": 2763, "developed": 2764, "result": 2765, "pulled": 2766, "friend": 2767, "stood": 2768, "money": 2769, "running": 2770, "mi": 2771, "signed": 2772, "word": 2773, "songs": 2774, "child": 2775, "eventually": 2776, "met": 2777, "tour": 2778, "average": 2779, "teams": 2780, "minutes": 2781, "festival": 2782, "current": 2783, "deep": 2784, "kind": 2785, "1995": 2786, "decided": 2787, "usually": 2788, "eastern": 2789, "seemed": 2790, "##ness": 2791, "episode": 2792, "bed": 2793, "added": 2794, "table": 2795, "indian": 2796, "private": 2797, "charles": 2798, "route": 2799, "available": 2800, "idea": 2801, "throughout": 2802, "centre": 2803, "addition": 2804, "appointed": 2805, "style": 2806, "1994": 2807, "books": 2808, "eight": 2809, "construction": 2810, "press": 2811, "mean": 2812, "wall": 2813, "friends": 2814, "remained": 2815, "schools": 2816, "study": 2817, "##ch": 2818, "##um": 2819, "institute": 2820, "oh": 2821, "chinese": 2822, "sometimes": 2823, "events": 2824, "possible": 2825, "1992": 2826, "australian": 2827, "type": 2828, "brown": 2829, "forward": 2830, "talk": 2831, "process": 2832, "food": 2833, "debut": 2834, "seat": 2835, "performance": 2836, "committee": 2837, "features": 2838, "character": 2839, "arts": 2840, "herself": 2841, "else": 2842, "lot": 2843, "strong": 2844, "russian": 2845, "range": 2846, "hours": 2847, "peter": 2848, "arm": 2849, "##da": 2850, "morning": 2851, "dr": 2852, "sold": 2853, "##ry": 2854, "quickly": 2855, "directed": 2856, "1993": 2857, "guitar": 2858, "china": 2859, "##w": 2860, "31": 2861, "list": 2862, "##ma": 2863, "performed": 2864, "media": 2865, "uk": 2866, "players": 2867, "smile": 2868, "##rs": 2869, "myself": 2870, "40": 2871, "placed": 2872, "coach": 2873, "province": 2874, "towards": 2875, "wouldn": 2876, "leading": 2877, "whole": 2878, "boy": 2879, "official": 2880, "designed": 2881, "grand": 2882, "census": 2883, "##el": 2884, "europe": 2885, "attack": 2886, "japanese": 2887, "henry": 2888, "1991": 2889, "##re": 2890, "##os": 2891, "cross": 2892, "getting": 2893, "alone": 2894, "action": 2895, "lower": 2896, "network": 2897, "wide": 2898, "washington": 2899, "japan": 2900, "1990": 2901, "hospital": 2902, "believe": 2903, "changed": 2904, "sister": 2905, "##ar": 2906, "hold": 2907, "gone": 2908, "sir": 2909, "hadn": 2910, "ship": 2911, "##ka": 2912, "studies": 2913, "academy": 2914, "shot": 2915, "rights": 2916, "below": 2917, "base": 2918, "bad": 2919, "involved": 2920, "kept": 2921, "largest": 2922, "##ist": 2923, "bank": 2924, "future": 2925, "especially": 2926, "beginning": 2927, "mark": 2928, "movement": 2929, "section": 2930, "female": 2931, "magazine": 2932, "plan": 2933, "professor": 2934, "lord": 2935, "longer": 2936, "##ian": 2937, "sat": 2938, "walked": 2939, "hill": 2940, "actually": 2941, "civil": 2942, "energy": 2943, "model": 2944, "families": 2945, "size": 2946, "thus": 2947, "aircraft": 2948, "completed": 2949, "includes": 2950, "data": 2951, "captain": 2952, "##or": 2953, "fight": 2954, "vocals": 2955, "featured": 2956, "richard": 2957, "bridge": 2958, "fourth": 2959, "1989": 2960, "officer": 2961, "stone": 2962, "hear": 2963, "##ism": 2964, "means": 2965, "medical": 2966, "groups": 2967, "management": 2968, "self": 2969, "lips": 2970, "competition": 2971, "entire": 2972, "lived": 2973, "technology": 2974, "leaving": 2975, "federal": 2976, "tournament": 2977, "bit": 2978, "passed": 2979, "hot": 2980, "independent": 2981, "awards": 2982, "kingdom": 2983, "mary": 2984, "spent": 2985, "fine": 2986, "doesn": 2987, "reported": 2988, "##ling": 2989, "jack": 2990, "fall": 2991, "raised": 2992, "itself": 2993, "stay": 2994, "true": 2995, "studio": 2996, "1988": 2997, "sports": 2998, "replaced": 2999, "paris": 3000, "systems": 3001, "saint": 3002, "leader": 3003, "theatre": 3004, "whose": 3005, "market": 3006, "capital": 3007, "parents": 3008, "spanish": 3009, "canadian": 3010, "earth": 3011, "##ity": 3012, "cut": 3013, "degree": 3014, "writing": 3015, "bay": 3016, "christian": 3017, "awarded": 3018, "natural": 3019, "higher": 3020, "bill": 3021, "##as": 3022, "coast": 3023, "provided": 3024, "previous": 3025, "senior": 3026, "ft": 3027, "valley": 3028, "organization": 3029, "stopped": 3030, "onto": 3031, "countries": 3032, "parts": 3033, "conference": 3034, "queen": 3035, "security": 3036, "interest": 3037, "saying": 3038, "allowed": 3039, "master": 3040, "earlier": 3041, "phone": 3042, "matter": 3043, "smith": 3044, "winning": 3045, "try": 3046, "happened": 3047, "moving": 3048, "campaign": 3049, "los": 3050, "##ley": 3051, "breath": 3052, "nearly": 3053, "mid": 3054, "1987": 3055, "certain": 3056, "girls": 3057, "date": 3058, "italian": 3059, "african": 3060, "standing": 3061, "fell": 3062, "artist": 3063, "##ted": 3064, "shows": 3065, "deal": 3066, "mine": 3067, "industry": 3068, "1986": 3069, "##ng": 3070, "everyone": 3071, "republic": 3072, "provide": 3073, "collection": 3074, "library": 3075, "student": 3076, "##ville": 3077, "primary": 3078, "owned": 3079, "older": 3080, "via": 3081, "heavy": 3082, "1st": 3083, "makes": 3084, "##able": 3085, "attention": 3086, "anyone": 3087, "africa": 3088, "##ri": 3089, "stated": 3090, "length": 3091, "ended": 3092, "fingers": 3093, "command": 3094, "staff": 3095, "skin": 3096, "foreign": 3097, "opening": 3098, "governor": 3099, "okay": 3100, "medal": 3101, "kill": 3102, "sun": 3103, "cover": 3104, "job": 3105, "1985": 3106, "introduced": 3107, "chest": 3108, "hell": 3109, "feeling": 3110, "##ies": 3111, "success": 3112, "meet": 3113, "reason": 3114, "standard": 3115, "meeting": 3116, "novel": 3117, "1984": 3118, "trade": 3119, "source": 3120, "buildings": 3121, "##land": 3122, "rose": 3123, "guy": 3124, "goal": 3125, "##ur": 3126, "chapter": 3127, "native": 3128, "husband": 3129, "previously": 3130, "unit": 3131, "limited": 3132, "entered": 3133, "weeks": 3134, "producer": 3135, "operations": 3136, "mountain": 3137, "takes": 3138, "covered": 3139, "forced": 3140, "related": 3141, "roman": 3142, "complete": 3143, "successful": 3144, "key": 3145, "texas": 3146, "cold": 3147, "##ya": 3148, "channel": 3149, "1980": 3150, "traditional": 3151, "films": 3152, "dance": 3153, "clear": 3154, "approximately": 3155, "500": 3156, "nine": 3157, "van": 3158, "prince": 3159, "question": 3160, "active": 3161, "tracks": 3162, "ireland": 3163, "regional": 3164, "silver": 3165, "author": 3166, "personal": 3167, "sense": 3168, "operation": 3169, "##ine": 3170, "economic": 3171, "1983": 3172, "holding": 3173, "twenty": 3174, "isbn": 3175, "additional": 3176, "speed": 3177, "hour": 3178, "edition": 3179, "regular": 3180, "historic": 3181, "places": 3182, "whom": 3183, "shook": 3184, "movie": 3185, "km²": 3186, "secretary": 3187, "prior": 3188, "report": 3189, "chicago": 3190, "read": 3191, "foundation": 3192, "view": 3193, "engine": 3194, "scored": 3195, "1982": 3196, "units": 3197, "ask": 3198, "airport": 3199, "property": 3200, "ready": 3201, "immediately": 3202, "lady": 3203, "month": 3204, "listed": 3205, "contract": 3206, "##de": 3207, "manager": 3208, "themselves": 3209, "lines": 3210, "##ki": 3211, "navy": 3212, "writer": 3213, "meant": 3214, "##ts": 3215, "runs": 3216, "##ro": 3217, "practice": 3218, "championships": 3219, "singer": 3220, "glass": 3221, "commission": 3222, "required": 3223, "forest": 3224, "starting": 3225, "culture": 3226, "generally": 3227, "giving": 3228, "access": 3229, "attended": 3230, "test": 3231, "couple": 3232, "stand": 3233, "catholic": 3234, "martin": 3235, "caught": 3236, "executive": 3237, "##less": 3238, "eye": 3239, "##ey": 3240, "thinking": 3241, "chair": 3242, "quite": 3243, "shoulder": 3244, "1979": 3245, "hope": 3246, "decision": 3247, "plays": 3248, "defeated": 3249, "municipality": 3250, "whether": 3251, "structure": 3252, "offered": 3253, "slowly": 3254, "pain": 3255, "ice": 3256, "direction": 3257, "##ion": 3258, "paper": 3259, "mission": 3260, "1981": 3261, "mostly": 3262, "200": 3263, "noted": 3264, "individual": 3265, "managed": 3266, "nature": 3267, "lives": 3268, "plant": 3269, "##ha": 3270, "helped": 3271, "except": 3272, "studied": 3273, "computer": 3274, "figure": 3275, "relationship": 3276, "issue": 3277, "significant": 3278, "loss": 3279, "die": 3280, "smiled": 3281, "gun": 3282, "ago": 3283, "highest": 3284, "1972": 3285, "##am": 3286, "male": 3287, "bring": 3288, "goals": 3289, "mexico": 3290, "problem": 3291, "distance": 3292, "commercial": 3293, "completely": 3294, "location": 3295, "annual": 3296, "famous": 3297, "drive": 3298, "1976": 3299, "neck": 3300, "1978": 3301, "surface": 3302, "caused": 3303, "italy": 3304, "understand": 3305, "greek": 3306, "highway": 3307, "wrong": 3308, "hotel": 3309, "comes": 3310, "appearance": 3311, "joseph": 3312, "double": 3313, "issues": 3314, "musical": 3315, "companies": 3316, "castle": 3317, "income": 3318, "review": 3319, "assembly": 3320, "bass": 3321, "initially": 3322, "parliament": 3323, "artists": 3324, "experience": 3325, "1974": 3326, "particular": 3327, "walk": 3328, "foot": 3329, "engineering": 3330, "talking": 3331, "window": 3332, "dropped": 3333, "##ter": 3334, "miss": 3335, "baby": 3336, "boys": 3337, "break": 3338, "1975": 3339, "stars": 3340, "edge": 3341, "remember": 3342, "policy": 3343, "carried": 3344, "train": 3345, "stadium": 3346, "bar": 3347, "sex": 3348, "angeles": 3349, "evidence": 3350, "##ge": 3351, "becoming": 3352, "assistant": 3353, "soviet": 3354, "1977": 3355, "upper": 3356, "step": 3357, "wing": 3358, "1970": 3359, "youth": 3360, "financial": 3361, "reach": 3362, "##ll": 3363, "actor": 3364, "numerous": 3365, "##se": 3366, "##st": 3367, "nodded": 3368, "arrived": 3369, "##ation": 3370, "minute": 3371, "##nt": 3372, "believed": 3373, "sorry": 3374, "complex": 3375, "beautiful": 3376, "victory": 3377, "associated": 3378, "temple": 3379, "1968": 3380, "1973": 3381, "chance": 3382, "perhaps": 3383, "metal": 3384, "##son": 3385, "1945": 3386, "bishop": 3387, "##et": 3388, "lee": 3389, "launched": 3390, "particularly": 3391, "tree": 3392, "le": 3393, "retired": 3394, "subject": 3395, "prize": 3396, "contains": 3397, "yeah": 3398, "theory": 3399, "empire": 3400, "##ce": 3401, "suddenly": 3402, "waiting": 3403, "trust": 3404, "recording": 3405, "##to": 3406, "happy": 3407, "terms": 3408, "camp": 3409, "champion": 3410, "1971": 3411, "religious": 3412, "pass": 3413, "zealand": 3414, "names": 3415, "2nd": 3416, "port": 3417, "ancient": 3418, "tom": 3419, "corner": 3420, "represented": 3421, "watch": 3422, "legal": 3423, "anti": 3424, "justice": 3425, "cause": 3426, "watched": 3427, "brothers": 3428, "45": 3429, "material": 3430, "changes": 3431, "simply": 3432, "response": 3433, "louis": 3434, "fast": 3435, "##ting": 3436, "answer": 3437, "60": 3438, "historical": 3439, "1969": 3440, "stories": 3441, "straight": 3442, "create": 3443, "feature": 3444, "increased": 3445, "rate": 3446, "administration": 3447, "virginia": 3448, "el": 3449, "activities": 3450, "cultural": 3451, "overall": 3452, "winner": 3453, "programs": 3454, "basketball": 3455, "legs": 3456, "guard": 3457, "beyond": 3458, "cast": 3459, "doctor": 3460, "mm": 3461, "flight": 3462, "results": 3463, "remains": 3464, "cost": 3465, "effect": 3466, "winter": 3467, "##ble": 3468, "larger": 3469, "islands": 3470, "problems": 3471, "chairman": 3472, "grew": 3473, "commander": 3474, "isn": 3475, "1967": 3476, "pay": 3477, "failed": 3478, "selected": 3479, "hurt": 3480, "fort": 3481, "box": 3482, "regiment": 3483, "majority": 3484, "journal": 3485, "35": 3486, "edward": 3487, "plans": 3488, "##ke": 3489, "##ni": 3490, "shown": 3491, "pretty": 3492, "irish": 3493, "characters": 3494, "directly": 3495, "scene": 3496, "likely": 3497, "operated": 3498, "allow": 3499, "spring": 3500, "##j": 3501, "junior": 3502, "matches": 3503, "looks": 3504, "mike": 3505, "houses": 3506, "fellow": 3507, "##tion": 3508, "beach": 3509, "marriage": 3510, "##ham": 3511, "##ive": 3512, "rules": 3513, "oil": 3514, "65": 3515, "florida": 3516, "expected": 3517, "nearby": 3518, "congress": 3519, "sam": 3520, "peace": 3521, "recent": 3522, "iii": 3523, "wait": 3524, "subsequently": 3525, "cell": 3526, "##do": 3527, "variety": 3528, "serving": 3529, "agreed": 3530, "please": 3531, "poor": 3532, "joe": 3533, "pacific": 3534, "attempt": 3535, "wood": 3536, "democratic": 3537, "piece": 3538, "prime": 3539, "##ca": 3540, "rural": 3541, "mile": 3542, "touch": 3543, "appears": 3544, "township": 3545, "1964": 3546, "1966": 3547, "soldiers": 3548, "##men": 3549, "##ized": 3550, "1965": 3551, "pennsylvania": 3552, "closer": 3553, "fighting": 3554, "claimed": 3555, "score": 3556, "jones": 3557, "physical": 3558, "editor": 3559, "##ous": 3560, "filled": 3561, "genus": 3562, "specific": 3563, "sitting": 3564, "super": 3565, "mom": 3566, "##va": 3567, "therefore": 3568, "supported": 3569, "status": 3570, "fear": 3571, "cases": 3572, "store": 3573, "meaning": 3574, "wales": 3575, "minor": 3576, "spain": 3577, "tower": 3578, "focus": 3579, "vice": 3580, "frank": 3581, "follow": 3582, "parish": 3583, "separate": 3584, "golden": 3585, "horse": 3586, "fifth": 3587, "remaining": 3588, "branch": 3589, "32": 3590, "presented": 3591, "stared": 3592, "##id": 3593, "uses": 3594, "secret": 3595, "forms": 3596, "##co": 3597, "baseball": 3598, "exactly": 3599, "##ck": 3600, "choice": 3601, "note": 3602, "discovered": 3603, "travel": 3604, "composed": 3605, "truth": 3606, "russia": 3607, "ball": 3608, "color": 3609, "kiss": 3610, "dad": 3611, "wind": 3612, "continue": 3613, "ring": 3614, "referred": 3615, "numbers": 3616, "digital": 3617, "greater": 3618, "##ns": 3619, "metres": 3620, "slightly": 3621, "direct": 3622, "increase": 3623, "1960": 3624, "responsible": 3625, "crew": 3626, "rule": 3627, "trees": 3628, "troops": 3629, "##no": 3630, "broke": 3631, "goes": 3632, "individuals": 3633, "hundred": 3634, "weight": 3635, "creek": 3636, "sleep": 3637, "memory": 3638, "defense": 3639, "provides": 3640, "ordered": 3641, "code": 3642, "value": 3643, "jewish": 3644, "windows": 3645, "1944": 3646, "safe": 3647, "judge": 3648, "whatever": 3649, "corps": 3650, "realized": 3651, "growing": 3652, "pre": 3653, "##ga": 3654, "cities": 3655, "alexander": 3656, "gaze": 3657, "lies": 3658, "spread": 3659, "scott": 3660, "letter": 3661, "showed": 3662, "situation": 3663, "mayor": 3664, "transport": 3665, "watching": 3666, "workers": 3667, "extended": 3668, "##li": 3669, "expression": 3670, "normal": 3671, "##ment": 3672, "chart": 3673, "multiple": 3674, "border": 3675, "##ba": 3676, "host": 3677, "##ner": 3678, "daily": 3679, "mrs": 3680, "walls": 3681, "piano": 3682, "##ko": 3683, "heat": 3684, "cannot": 3685, "##ate": 3686, "earned": 3687, "products": 3688, "drama": 3689, "era": 3690, "authority": 3691, "seasons": 3692, "join": 3693, "grade": 3694, "##io": 3695, "sign": 3696, "difficult": 3697, "machine": 3698, "1963": 3699, "territory": 3700, "mainly": 3701, "##wood": 3702, "stations": 3703, "squadron": 3704, "1962": 3705, "stepped": 3706, "iron": 3707, "19th": 3708, "##led": 3709, "serve": 3710, "appear": 3711, "sky": 3712, "speak": 3713, "broken": 3714, "charge": 3715, "knowledge": 3716, "kilometres": 3717, "removed": 3718, "ships": 3719, "article": 3720, "campus": 3721, "simple": 3722, "##ty": 3723, "pushed": 3724, "britain": 3725, "##ve": 3726, "leaves": 3727, "recently": 3728, "cd": 3729, "soft": 3730, "boston": 3731, "latter": 3732, "easy": 3733, "acquired": 3734, "poland": 3735, "##sa": 3736, "quality": 3737, "officers": 3738, "presence": 3739, "planned": 3740, "nations": 3741, "mass": 3742, "broadcast": 3743, "jean": 3744, "share": 3745, "image": 3746, "influence": 3747, "wild": 3748, "offer": 3749, "emperor": 3750, "electric": 3751, "reading": 3752, "headed": 3753, "ability": 3754, "promoted": 3755, "yellow": 3756, "ministry": 3757, "1942": 3758, "throat": 3759, "smaller": 3760, "politician": 3761, "##by": 3762, "latin": 3763, "spoke": 3764, "cars": 3765, "williams": 3766, "males": 3767, "lack": 3768, "pop": 3769, "80": 3770, "##ier": 3771, "acting": 3772, "seeing": 3773, "consists": 3774, "##ti": 3775, "estate": 3776, "1961": 3777, "pressure": 3778, "johnson": 3779, "newspaper": 3780, "jr": 3781, "chris": 3782, "olympics": 3783, "online": 3784, "conditions": 3785, "beat": 3786, "elements": 3787, "walking": 3788, "vote": 3789, "##field": 3790, "needs": 3791, "carolina": 3792, "text": 3793, "featuring": 3794, "global": 3795, "block": 3796, "shirt": 3797, "levels": 3798, "francisco": 3799, "purpose": 3800, "females": 3801, "et": 3802, "dutch": 3803, "duke": 3804, "ahead": 3805, "gas": 3806, "twice": 3807, "safety": 3808, "serious": 3809, "turning": 3810, "highly": 3811, "lieutenant": 3812, "firm": 3813, "maria": 3814, "amount": 3815, "mixed": 3816, "daniel": 3817, "proposed": 3818, "perfect": 3819, "agreement": 3820, "affairs": 3821, "3rd": 3822, "seconds": 3823, "contemporary": 3824, "paid": 3825, "1943": 3826, "prison": 3827, "save": 3828, "kitchen": 3829, "label": 3830, "administrative": 3831, "intended": 3832, "constructed": 3833, "academic": 3834, "nice": 3835, "teacher": 3836, "races": 3837, "1956": 3838, "formerly": 3839, "corporation": 3840, "ben": 3841, "nation": 3842, "issued": 3843, "shut": 3844, "1958": 3845, "drums": 3846, "housing": 3847, "victoria": 3848, "seems": 3849, "opera": 3850, "1959": 3851, "graduated": 3852, "function": 3853, "von": 3854, "mentioned": 3855, "picked": 3856, "build": 3857, "recognized": 3858, "shortly": 3859, "protection": 3860, "picture": 3861, "notable": 3862, "exchange": 3863, "elections": 3864, "1980s": 3865, "loved": 3866, "percent": 3867, "racing": 3868, "fish": 3869, "elizabeth": 3870, "garden": 3871, "volume": 3872, "hockey": 3873, "1941": 3874, "beside": 3875, "settled": 3876, "##ford": 3877, "1940": 3878, "competed": 3879, "replied": 3880, "drew": 3881, "1948": 3882, "actress": 3883, "marine": 3884, "scotland": 3885, "steel": 3886, "glanced": 3887, "farm": 3888, "steve": 3889, "1957": 3890, "risk": 3891, "tonight": 3892, "positive": 3893, "magic": 3894, "singles": 3895, "effects": 3896, "gray": 3897, "screen": 3898, "dog": 3899, "##ja": 3900, "residents": 3901, "bus": 3902, "sides": 3903, "none": 3904, "secondary": 3905, "literature": 3906, "polish": 3907, "destroyed": 3908, "flying": 3909, "founder": 3910, "households": 3911, "1939": 3912, "lay": 3913, "reserve": 3914, "usa": 3915, "gallery": 3916, "##ler": 3917, "1946": 3918, "industrial": 3919, "younger": 3920, "approach": 3921, "appearances": 3922, "urban": 3923, "ones": 3924, "1950": 3925, "finish": 3926, "avenue": 3927, "powerful": 3928, "fully": 3929, "growth": 3930, "page": 3931, "honor": 3932, "jersey": 3933, "projects": 3934, "advanced": 3935, "revealed": 3936, "basic": 3937, "90": 3938, "infantry": 3939, "pair": 3940, "equipment": 3941, "visit": 3942, "33": 3943, "evening": 3944, "search": 3945, "grant": 3946, "effort": 3947, "solo": 3948, "treatment": 3949, "buried": 3950, "republican": 3951, "primarily": 3952, "bottom": 3953, "owner": 3954, "1970s": 3955, "israel": 3956, "gives": 3957, "jim": 3958, "dream": 3959, "bob": 3960, "remain": 3961, "spot": 3962, "70": 3963, "notes": 3964, "produce": 3965, "champions": 3966, "contact": 3967, "ed": 3968, "soul": 3969, "accepted": 3970, "ways": 3971, "del": 3972, "##ally": 3973, "losing": 3974, "split": 3975, "price": 3976, "capacity": 3977, "basis": 3978, "trial": 3979, "questions": 3980, "##ina": 3981, "1955": 3982, "20th": 3983, "guess": 3984, "officially": 3985, "memorial": 3986, "naval": 3987, "initial": 3988, "##ization": 3989, "whispered": 3990, "median": 3991, "engineer": 3992, "##ful": 3993, "sydney": 3994, "##go": 3995, "columbia": 3996, "strength": 3997, "300": 3998, "1952": 3999, "tears": 4000, "senate": 4001, "00": 4002, "card": 4003, "asian": 4004, "agent": 4005, "1947": 4006, "software": 4007, "44": 4008, "draw": 4009, "warm": 4010, "supposed": 4011, "com": 4012, "pro": 4013, "##il": 4014, "transferred": 4015, "leaned": 4016, "##at": 4017, "candidate": 4018, "escape": 4019, "mountains": 4020, "asia": 4021, "potential": 4022, "activity": 4023, "entertainment": 4024, "seem": 4025, "traffic": 4026, "jackson": 4027, "murder": 4028, "36": 4029, "slow": 4030, "product": 4031, "orchestra": 4032, "haven": 4033, "agency": 4034, "bbc": 4035, "taught": 4036, "website": 4037, "comedy": 4038, "unable": 4039, "storm": 4040, "planning": 4041, "albums": 4042, "rugby": 4043, "environment": 4044, "scientific": 4045, "grabbed": 4046, "protect": 4047, "##hi": 4048, "boat": 4049, "typically": 4050, "1954": 4051, "1953": 4052, "damage": 4053, "principal": 4054, "divided": 4055, "dedicated": 4056, "mount": 4057, "ohio": 4058, "##berg": 4059, "pick": 4060, "fought": 4061, "driver": 4062, "##der": 4063, "empty": 4064, "shoulders": 4065, "sort": 4066, "thank": 4067, "berlin": 4068, "prominent": 4069, "account": 4070, "freedom": 4071, "necessary": 4072, "efforts": 4073, "alex": 4074, "headquarters": 4075, "follows": 4076, "alongside": 4077, "des": 4078, "simon": 4079, "andrew": 4080, "suggested": 4081, "operating": 4082, "learning": 4083, "steps": 4084, "1949": 4085, "sweet": 4086, "technical": 4087, "begin": 4088, "easily": 4089, "34": 4090, "teeth": 4091, "speaking": 4092, "settlement": 4093, "scale": 4094, "##sh": 4095, "renamed": 4096, "ray": 4097, "max": 4098, "enemy": 4099, "semi": 4100, "joint": 4101, "compared": 4102, "##rd": 4103, "scottish": 4104, "leadership": 4105, "analysis": 4106, "offers": 4107, "georgia": 4108, "pieces": 4109, "captured": 4110, "animal": 4111, "deputy": 4112, "guest": 4113, "organized": 4114, "##lin": 4115, "tony": 4116, "combined": 4117, "method": 4118, "challenge": 4119, "1960s": 4120, "huge": 4121, "wants": 4122, "battalion": 4123, "sons": 4124, "rise": 4125, "crime": 4126, "types": 4127, "facilities": 4128, "telling": 4129, "path": 4130, "1951": 4131, "platform": 4132, "sit": 4133, "1990s": 4134, "##lo": 4135, "tells": 4136, "assigned": 4137, "rich": 4138, "pull": 4139, "##ot": 4140, "commonly": 4141, "alive": 4142, "##za": 4143, "letters": 4144, "concept": 4145, "conducted": 4146, "wearing": 4147, "happen": 4148, "bought": 4149, "becomes": 4150, "holy": 4151, "gets": 4152, "ocean": 4153, "defeat": 4154, "languages": 4155, "purchased": 4156, "coffee": 4157, "occurred": 4158, "titled": 4159, "##q": 4160, "declared": 4161, "applied": 4162, "sciences": 4163, "concert": 4164, "sounds": 4165, "jazz": 4166, "brain": 4167, "##me": 4168, "painting": 4169, "fleet": 4170, "tax": 4171, "nick": 4172, "##ius": 4173, "michigan": 4174, "count": 4175, "animals": 4176, "leaders": 4177, "episodes": 4178, "##line": 4179, "content": 4180, "##den": 4181, "birth": 4182, "##it": 4183, "clubs": 4184, "64": 4185, "palace": 4186, "critical": 4187, "refused": 4188, "fair": 4189, "leg": 4190, "laughed": 4191, "returning": 4192, "surrounding": 4193, "participated": 4194, "formation": 4195, "lifted": 4196, "pointed": 4197, "connected": 4198, "rome": 4199, "medicine": 4200, "laid": 4201, "taylor": 4202, "santa": 4203, "powers": 4204, "adam": 4205, "tall": 4206, "shared": 4207, "focused": 4208, "knowing": 4209, "yards": 4210, "entrance": 4211, "falls": 4212, "##wa": 4213, "calling": 4214, "##ad": 4215, "sources": 4216, "chosen": 4217, "beneath": 4218, "resources": 4219, "yard": 4220, "##ite": 4221, "nominated": 4222, "silence": 4223, "zone": 4224, "defined": 4225, "##que": 4226, "gained": 4227, "thirty": 4228, "38": 4229, "bodies": 4230, "moon": 4231, "##ard": 4232, "adopted": 4233, "christmas": 4234, "widely": 4235, "register": 4236, "apart": 4237, "iran": 4238, "premier": 4239, "serves": 4240, "du": 4241, "unknown": 4242, "parties": 4243, "##les": 4244, "generation": 4245, "##ff": 4246, "continues": 4247, "quick": 4248, "fields": 4249, "brigade": 4250, "quiet": 4251, "teaching": 4252, "clothes": 4253, "impact": 4254, "weapons": 4255, "partner": 4256, "flat": 4257, "theater": 4258, "supreme": 4259, "1938": 4260, "37": 4261, "relations": 4262, "##tor": 4263, "plants": 4264, "suffered": 4265, "1936": 4266, "wilson": 4267, "kids": 4268, "begins": 4269, "##age": 4270, "1918": 4271, "seats": 4272, "armed": 4273, "internet": 4274, "models": 4275, "worth": 4276, "laws": 4277, "400": 4278, "communities": 4279, "classes": 4280, "background": 4281, "knows": 4282, "thanks": 4283, "quarter": 4284, "reaching": 4285, "humans": 4286, "carry": 4287, "killing": 4288, "format": 4289, "kong": 4290, "hong": 4291, "setting": 4292, "75": 4293, "architecture": 4294, "disease": 4295, "railroad": 4296, "inc": 4297, "possibly": 4298, "wish": 4299, "arthur": 4300, "thoughts": 4301, "harry": 4302, "doors": 4303, "density": 4304, "##di": 4305, "crowd": 4306, "illinois": 4307, "stomach": 4308, "tone": 4309, "unique": 4310, "reports": 4311, "anyway": 4312, "##ir": 4313, "liberal": 4314, "der": 4315, "vehicle": 4316, "thick": 4317, "dry": 4318, "drug": 4319, "faced": 4320, "largely": 4321, "facility": 4322, "theme": 4323, "holds": 4324, "creation": 4325, "strange": 4326, "colonel": 4327, "##mi": 4328, "revolution": 4329, "bell": 4330, "politics": 4331, "turns": 4332, "silent": 4333, "rail": 4334, "relief": 4335, "independence": 4336, "combat": 4337, "shape": 4338, "write": 4339, "determined": 4340, "sales": 4341, "learned": 4342, "4th": 4343, "finger": 4344, "oxford": 4345, "providing": 4346, "1937": 4347, "heritage": 4348, "fiction": 4349, "situated": 4350, "designated": 4351, "allowing": 4352, "distribution": 4353, "hosted": 4354, "##est": 4355, "sight": 4356, "interview": 4357, "estimated": 4358, "reduced": 4359, "##ria": 4360, "toronto": 4361, "footballer": 4362, "keeping": 4363, "guys": 4364, "damn": 4365, "claim": 4366, "motion": 4367, "sport": 4368, "sixth": 4369, "stayed": 4370, "##ze": 4371, "en": 4372, "rear": 4373, "receive": 4374, "handed": 4375, "twelve": 4376, "dress": 4377, "audience": 4378, "granted": 4379, "brazil": 4380, "##well": 4381, "spirit": 4382, "##ated": 4383, "noticed": 4384, "etc": 4385, "olympic": 4386, "representative": 4387, "eric": 4388, "tight": 4389, "trouble": 4390, "reviews": 4391, "drink": 4392, "vampire": 4393, "missing": 4394, "roles": 4395, "ranked": 4396, "newly": 4397, "household": 4398, "finals": 4399, "wave": 4400, "critics": 4401, "##ee": 4402, "phase": 4403, "massachusetts": 4404, "pilot": 4405, "unlike": 4406, "philadelphia": 4407, "bright": 4408, "guns": 4409, "crown": 4410, "organizations": 4411, "roof": 4412, "42": 4413, "respectively": 4414, "clearly": 4415, "tongue": 4416, "marked": 4417, "circle": 4418, "fox": 4419, "korea": 4420, "bronze": 4421, "brian": 4422, "expanded": 4423, "sexual": 4424, "supply": 4425, "yourself": 4426, "inspired": 4427, "labour": 4428, "fc": 4429, "##ah": 4430, "reference": 4431, "vision": 4432, "draft": 4433, "connection": 4434, "brand": 4435, "reasons": 4436, "1935": 4437, "classic": 4438, "driving": 4439, "trip": 4440, "jesus": 4441, "cells": 4442, "entry": 4443, "1920": 4444, "neither": 4445, "trail": 4446, "claims": 4447, "atlantic": 4448, "orders": 4449, "labor": 4450, "nose": 4451, "afraid": 4452, "identified": 4453, "intelligence": 4454, "calls": 4455, "cancer": 4456, "attacked": 4457, "passing": 4458, "stephen": 4459, "positions": 4460, "imperial": 4461, "grey": 4462, "jason": 4463, "39": 4464, "sunday": 4465, "48": 4466, "swedish": 4467, "avoid": 4468, "extra": 4469, "uncle": 4470, "message": 4471, "covers": 4472, "allows": 4473, "surprise": 4474, "materials": 4475, "fame": 4476, "hunter": 4477, "##ji": 4478, "1930": 4479, "citizens": 4480, "figures": 4481, "davis": 4482, "environmental": 4483, "confirmed": 4484, "shit": 4485, "titles": 4486, "di": 4487, "performing": 4488, "difference": 4489, "acts": 4490, "attacks": 4491, "##ov": 4492, "existing": 4493, "votes": 4494, "opportunity": 4495, "nor": 4496, "shop": 4497, "entirely": 4498, "trains": 4499, "opposite": 4500, "pakistan": 4501, "##pa": 4502, "develop": 4503, "resulted": 4504, "representatives": 4505, "actions": 4506, "reality": 4507, "pressed": 4508, "##ish": 4509, "barely": 4510, "wine": 4511, "conversation": 4512, "faculty": 4513, "northwest": 4514, "ends": 4515, "documentary": 4516, "nuclear": 4517, "stock": 4518, "grace": 4519, "sets": 4520, "eat": 4521, "alternative": 4522, "##ps": 4523, "bag": 4524, "resulting": 4525, "creating": 4526, "surprised": 4527, "cemetery": 4528, "1919": 4529, "drop": 4530, "finding": 4531, "sarah": 4532, "cricket": 4533, "streets": 4534, "tradition": 4535, "ride": 4536, "1933": 4537, "exhibition": 4538, "target": 4539, "ear": 4540, "explained": 4541, "rain": 4542, "composer": 4543, "injury": 4544, "apartment": 4545, "municipal": 4546, "educational": 4547, "occupied": 4548, "netherlands": 4549, "clean": 4550, "billion": 4551, "constitution": 4552, "learn": 4553, "1914": 4554, "maximum": 4555, "classical": 4556, "francis": 4557, "lose": 4558, "opposition": 4559, "jose": 4560, "ontario": 4561, "bear": 4562, "core": 4563, "hills": 4564, "rolled": 4565, "ending": 4566, "drawn": 4567, "permanent": 4568, "fun": 4569, "##tes": 4570, "##lla": 4571, "lewis": 4572, "sites": 4573, "chamber": 4574, "ryan": 4575, "##way": 4576, "scoring": 4577, "height": 4578, "1934": 4579, "##house": 4580, "lyrics": 4581, "staring": 4582, "55": 4583, "officials": 4584, "1917": 4585, "snow": 4586, "oldest": 4587, "##tic": 4588, "orange": 4589, "##ger": 4590, "qualified": 4591, "interior": 4592, "apparently": 4593, "succeeded": 4594, "thousand": 4595, "dinner": 4596, "lights": 4597, "existence": 4598, "fans": 4599, "heavily": 4600, "41": 4601, "greatest": 4602, "conservative": 4603, "send": 4604, "bowl": 4605, "plus": 4606, "enter": 4607, "catch": 4608, "##un": 4609, "economy": 4610, "duty": 4611, "1929": 4612, "speech": 4613, "authorities": 4614, "princess": 4615, "performances": 4616, "versions": 4617, "shall": 4618, "graduate": 4619, "pictures": 4620, "effective": 4621, "remembered": 4622, "poetry": 4623, "desk": 4624, "crossed": 4625, "starring": 4626, "starts": 4627, "passenger": 4628, "sharp": 4629, "##ant": 4630, "acres": 4631, "ass": 4632, "weather": 4633, "falling": 4634, "rank": 4635, "fund": 4636, "supporting": 4637, "check": 4638, "adult": 4639, "publishing": 4640, "heads": 4641, "cm": 4642, "southeast": 4643, "lane": 4644, "##burg": 4645, "application": 4646, "bc": 4647, "##ura": 4648, "les": 4649, "condition": 4650, "transfer": 4651, "prevent": 4652, "display": 4653, "ex": 4654, "regions": 4655, "earl": 4656, "federation": 4657, "cool": 4658, "relatively": 4659, "answered": 4660, "besides": 4661, "1928": 4662, "obtained": 4663, "portion": 4664, "##town": 4665, "mix": 4666, "##ding": 4667, "reaction": 4668, "liked": 4669, "dean": 4670, "express": 4671, "peak": 4672, "1932": 4673, "##tte": 4674, "counter": 4675, "religion": 4676, "chain": 4677, "rare": 4678, "miller": 4679, "convention": 4680, "aid": 4681, "lie": 4682, "vehicles": 4683, "mobile": 4684, "perform": 4685, "squad": 4686, "wonder": 4687, "lying": 4688, "crazy": 4689, "sword": 4690, "##ping": 4691, "attempted": 4692, "centuries": 4693, "weren": 4694, "philosophy": 4695, "category": 4696, "##ize": 4697, "anna": 4698, "interested": 4699, "47": 4700, "sweden": 4701, "wolf": 4702, "frequently": 4703, "abandoned": 4704, "kg": 4705, "literary": 4706, "alliance": 4707, "task": 4708, "entitled": 4709, "##ay": 4710, "threw": 4711, "promotion": 4712, "factory": 4713, "tiny": 4714, "soccer": 4715, "visited": 4716, "matt": 4717, "fm": 4718, "achieved": 4719, "52": 4720, "defence": 4721, "internal": 4722, "persian": 4723, "43": 4724, "methods": 4725, "##ging": 4726, "arrested": 4727, "otherwise": 4728, "cambridge": 4729, "programming": 4730, "villages": 4731, "elementary": 4732, "districts": 4733, "rooms": 4734, "criminal": 4735, "conflict": 4736, "worry": 4737, "trained": 4738, "1931": 4739, "attempts": 4740, "waited": 4741, "signal": 4742, "bird": 4743, "truck": 4744, "subsequent": 4745, "programme": 4746, "##ol": 4747, "ad": 4748, "49": 4749, "communist": 4750, "details": 4751, "faith": 4752, "sector": 4753, "patrick": 4754, "carrying": 4755, "laugh": 4756, "##ss": 4757, "controlled": 4758, "korean": 4759, "showing": 4760, "origin": 4761, "fuel": 4762, "evil": 4763, "1927": 4764, "##ent": 4765, "brief": 4766, "identity": 4767, "darkness": 4768, "address": 4769, "pool": 4770, "missed": 4771, "publication": 4772, "web": 4773, "planet": 4774, "ian": 4775, "anne": 4776, "wings": 4777, "invited": 4778, "##tt": 4779, "briefly": 4780, "standards": 4781, "kissed": 4782, "##be": 4783, "ideas": 4784, "climate": 4785, "causing": 4786, "walter": 4787, "worse": 4788, "albert": 4789, "articles": 4790, "winners": 4791, "desire": 4792, "aged": 4793, "northeast": 4794, "dangerous": 4795, "gate": 4796, "doubt": 4797, "1922": 4798, "wooden": 4799, "multi": 4800, "##ky": 4801, "poet": 4802, "rising": 4803, "funding": 4804, "46": 4805, "communications": 4806, "communication": 4807, "violence": 4808, "copies": 4809, "prepared": 4810, "ford": 4811, "investigation": 4812, "skills": 4813, "1924": 4814, "pulling": 4815, "electronic": 4816, "##ak": 4817, "##ial": 4818, "##han": 4819, "containing": 4820, "ultimately": 4821, "offices": 4822, "singing": 4823, "understanding": 4824, "restaurant": 4825, "tomorrow": 4826, "fashion": 4827, "christ": 4828, "ward": 4829, "da": 4830, "pope": 4831, "stands": 4832, "5th": 4833, "flow": 4834, "studios": 4835, "aired": 4836, "commissioned": 4837, "contained": 4838, "exist": 4839, "fresh": 4840, "americans": 4841, "##per": 4842, "wrestling": 4843, "approved": 4844, "kid": 4845, "employed": 4846, "respect": 4847, "suit": 4848, "1925": 4849, "angel": 4850, "asking": 4851, "increasing": 4852, "frame": 4853, "angry": 4854, "selling": 4855, "1950s": 4856, "thin": 4857, "finds": 4858, "##nd": 4859, "temperature": 4860, "statement": 4861, "ali": 4862, "explain": 4863, "inhabitants": 4864, "towns": 4865, "extensive": 4866, "narrow": 4867, "51": 4868, "jane": 4869, "flowers": 4870, "images": 4871, "promise": 4872, "somewhere": 4873, "object": 4874, "fly": 4875, "closely": 4876, "##ls": 4877, "1912": 4878, "bureau": 4879, "cape": 4880, "1926": 4881, "weekly": 4882, "presidential": 4883, "legislative": 4884, "1921": 4885, "##ai": 4886, "##au": 4887, "launch": 4888, "founding": 4889, "##ny": 4890, "978": 4891, "##ring": 4892, "artillery": 4893, "strike": 4894, "un": 4895, "institutions": 4896, "roll": 4897, "writers": 4898, "landing": 4899, "chose": 4900, "kevin": 4901, "anymore": 4902, "pp": 4903, "##ut": 4904, "attorney": 4905, "fit": 4906, "dan": 4907, "billboard": 4908, "receiving": 4909, "agricultural": 4910, "breaking": 4911, "sought": 4912, "dave": 4913, "admitted": 4914, "lands": 4915, "mexican": 4916, "##bury": 4917, "charlie": 4918, "specifically": 4919, "hole": 4920, "iv": 4921, "howard": 4922, "credit": 4923, "moscow": 4924, "roads": 4925, "accident": 4926, "1923": 4927, "proved": 4928, "wear": 4929, "struck": 4930, "hey": 4931, "guards": 4932, "stuff": 4933, "slid": 4934, "expansion": 4935, "1915": 4936, "cat": 4937, "anthony": 4938, "##kin": 4939, "melbourne": 4940, "opposed": 4941, "sub": 4942, "southwest": 4943, "architect": 4944, "failure": 4945, "plane": 4946, "1916": 4947, "##ron": 4948, "map": 4949, "camera": 4950, "tank": 4951, "listen": 4952, "regarding": 4953, "wet": 4954, "introduction": 4955, "metropolitan": 4956, "link": 4957, "ep": 4958, "fighter": 4959, "inch": 4960, "grown": 4961, "gene": 4962, "anger": 4963, "fixed": 4964, "buy": 4965, "dvd": 4966, "khan": 4967, "domestic": 4968, "worldwide": 4969, "chapel": 4970, "mill": 4971, "functions": 4972, "examples": 4973, "##head": 4974, "developing": 4975, "1910": 4976, "turkey": 4977, "hits": 4978, "pocket": 4979, "antonio": 4980, "papers": 4981, "grow": 4982, "unless": 4983, "circuit": 4984, "18th": 4985, "concerned": 4986, "attached": 4987, "journalist": 4988, "selection": 4989, "journey": 4990, "converted": 4991, "provincial": 4992, "painted": 4993, "hearing": 4994, "aren": 4995, "bands": 4996, "negative": 4997, "aside": 4998, "wondered": 4999, "knight": 5000, "lap": 5001, "survey": 5002, "ma": 5003, "##ow": 5004, "noise": 5005, "billy": 5006, "##ium": 5007, "shooting": 5008, "guide": 5009, "bedroom": 5010, "priest": 5011, "resistance": 5012, "motor": 5013, "homes": 5014, "sounded": 5015, "giant": 5016, "##mer": 5017, "150": 5018, "scenes": 5019, "equal": 5020, "comic": 5021, "patients": 5022, "hidden": 5023, "solid": 5024, "actual": 5025, "bringing": 5026, "afternoon": 5027, "touched": 5028, "funds": 5029, "wedding": 5030, "consisted": 5031, "marie": 5032, "canal": 5033, "sr": 5034, "kim": 5035, "treaty": 5036, "turkish": 5037, "recognition": 5038, "residence": 5039, "cathedral": 5040, "broad": 5041, "knees": 5042, "incident": 5043, "shaped": 5044, "fired": 5045, "norwegian": 5046, "handle": 5047, "cheek": 5048, "contest": 5049, "represent": 5050, "##pe": 5051, "representing": 5052, "beauty": 5053, "##sen": 5054, "birds": 5055, "advantage": 5056, "emergency": 5057, "wrapped": 5058, "drawing": 5059, "notice": 5060, "pink": 5061, "broadcasting": 5062, "##ong": 5063, "somehow": 5064, "bachelor": 5065, "seventh": 5066, "collected": 5067, "registered": 5068, "establishment": 5069, "alan": 5070, "assumed": 5071, "chemical": 5072, "personnel": 5073, "roger": 5074, "retirement": 5075, "jeff": 5076, "portuguese": 5077, "wore": 5078, "tied": 5079, "device": 5080, "threat": 5081, "progress": 5082, "advance": 5083, "##ised": 5084, "banks": 5085, "hired": 5086, "manchester": 5087, "nfl": 5088, "teachers": 5089, "structures": 5090, "forever": 5091, "##bo": 5092, "tennis": 5093, "helping": 5094, "saturday": 5095, "sale": 5096, "applications": 5097, "junction": 5098, "hip": 5099, "incorporated": 5100, "neighborhood": 5101, "dressed": 5102, "ceremony": 5103, "##ds": 5104, "influenced": 5105, "hers": 5106, "visual": 5107, "stairs": 5108, "decades": 5109, "inner": 5110, "kansas": 5111, "hung": 5112, "hoped": 5113, "gain": 5114, "scheduled": 5115, "downtown": 5116, "engaged": 5117, "austria": 5118, "clock": 5119, "norway": 5120, "certainly": 5121, "pale": 5122, "protected": 5123, "1913": 5124, "victor": 5125, "employees": 5126, "plate": 5127, "putting": 5128, "surrounded": 5129, "##ists": 5130, "finishing": 5131, "blues": 5132, "tropical": 5133, "##ries": 5134, "minnesota": 5135, "consider": 5136, "philippines": 5137, "accept": 5138, "54": 5139, "retrieved": 5140, "1900": 5141, "concern": 5142, "anderson": 5143, "properties": 5144, "institution": 5145, "gordon": 5146, "successfully": 5147, "vietnam": 5148, "##dy": 5149, "backing": 5150, "outstanding": 5151, "muslim": 5152, "crossing": 5153, "folk": 5154, "producing": 5155, "usual": 5156, "demand": 5157, "occurs": 5158, "observed": 5159, "lawyer": 5160, "educated": 5161, "##ana": 5162, "kelly": 5163, "string": 5164, "pleasure": 5165, "budget": 5166, "items": 5167, "quietly": 5168, "colorado": 5169, "philip": 5170, "typical": 5171, "##worth": 5172, "derived": 5173, "600": 5174, "survived": 5175, "asks": 5176, "mental": 5177, "##ide": 5178, "56": 5179, "jake": 5180, "jews": 5181, "distinguished": 5182, "ltd": 5183, "1911": 5184, "sri": 5185, "extremely": 5186, "53": 5187, "athletic": 5188, "loud": 5189, "thousands": 5190, "worried": 5191, "shadow": 5192, "transportation": 5193, "horses": 5194, "weapon": 5195, "arena": 5196, "importance": 5197, "users": 5198, "tim": 5199, "objects": 5200, "contributed": 5201, "dragon": 5202, "douglas": 5203, "aware": 5204, "senator": 5205, "johnny": 5206, "jordan": 5207, "sisters": 5208, "engines": 5209, "flag": 5210, "investment": 5211, "samuel": 5212, "shock": 5213, "capable": 5214, "clark": 5215, "row": 5216, "wheel": 5217, "refers": 5218, "session": 5219, "familiar": 5220, "biggest": 5221, "wins": 5222, "hate": 5223, "maintained": 5224, "drove": 5225, "hamilton": 5226, "request": 5227, "expressed": 5228, "injured": 5229, "underground": 5230, "churches": 5231, "walker": 5232, "wars": 5233, "tunnel": 5234, "passes": 5235, "stupid": 5236, "agriculture": 5237, "softly": 5238, "cabinet": 5239, "regarded": 5240, "joining": 5241, "indiana": 5242, "##ea": 5243, "##ms": 5244, "push": 5245, "dates": 5246, "spend": 5247, "behavior": 5248, "woods": 5249, "protein": 5250, "gently": 5251, "chase": 5252, "morgan": 5253, "mention": 5254, "burning": 5255, "wake": 5256, "combination": 5257, "occur": 5258, "mirror": 5259, "leads": 5260, "jimmy": 5261, "indeed": 5262, "impossible": 5263, "singapore": 5264, "paintings": 5265, "covering": 5266, "##nes": 5267, "soldier": 5268, "locations": 5269, "attendance": 5270, "sell": 5271, "historian": 5272, "wisconsin": 5273, "invasion": 5274, "argued": 5275, "painter": 5276, "diego": 5277, "changing": 5278, "egypt": 5279, "##don": 5280, "experienced": 5281, "inches": 5282, "##ku": 5283, "missouri": 5284, "vol": 5285, "grounds": 5286, "spoken": 5287, "switzerland": 5288, "##gan": 5289, "reform": 5290, "rolling": 5291, "ha": 5292, "forget": 5293, "massive": 5294, "resigned": 5295, "burned": 5296, "allen": 5297, "tennessee": 5298, "locked": 5299, "values": 5300, "improved": 5301, "##mo": 5302, "wounded": 5303, "universe": 5304, "sick": 5305, "dating": 5306, "facing": 5307, "pack": 5308, "purchase": 5309, "user": 5310, "##pur": 5311, "moments": 5312, "##ul": 5313, "merged": 5314, "anniversary": 5315, "1908": 5316, "coal": 5317, "brick": 5318, "understood": 5319, "causes": 5320, "dynasty": 5321, "queensland": 5322, "establish": 5323, "stores": 5324, "crisis": 5325, "promote": 5326, "hoping": 5327, "views": 5328, "cards": 5329, "referee": 5330, "extension": 5331, "##si": 5332, "raise": 5333, "arizona": 5334, "improve": 5335, "colonial": 5336, "formal": 5337, "charged": 5338, "##rt": 5339, "palm": 5340, "lucky": 5341, "hide": 5342, "rescue": 5343, "faces": 5344, "95": 5345, "feelings": 5346, "candidates": 5347, "juan": 5348, "##ell": 5349, "goods": 5350, "6th": 5351, "courses": 5352, "weekend": 5353, "59": 5354, "luke": 5355, "cash": 5356, "fallen": 5357, "##om": 5358, "delivered": 5359, "affected": 5360, "installed": 5361, "carefully": 5362, "tries": 5363, "swiss": 5364, "hollywood": 5365, "costs": 5366, "lincoln": 5367, "responsibility": 5368, "##he": 5369, "shore": 5370, "file": 5371, "proper": 5372, "normally": 5373, "maryland": 5374, "assistance": 5375, "jump": 5376, "constant": 5377, "offering": 5378, "friendly": 5379, "waters": 5380, "persons": 5381, "realize": 5382, "contain": 5383, "trophy": 5384, "800": 5385, "partnership": 5386, "factor": 5387, "58": 5388, "musicians": 5389, "cry": 5390, "bound": 5391, "oregon": 5392, "indicated": 5393, "hero": 5394, "houston": 5395, "medium": 5396, "##ure": 5397, "consisting": 5398, "somewhat": 5399, "##ara": 5400, "57": 5401, "cycle": 5402, "##che": 5403, "beer": 5404, "moore": 5405, "frederick": 5406, "gotten": 5407, "eleven": 5408, "worst": 5409, "weak": 5410, "approached": 5411, "arranged": 5412, "chin": 5413, "loan": 5414, "universal": 5415, "bond": 5416, "fifteen": 5417, "pattern": 5418, "disappeared": 5419, "##ney": 5420, "translated": 5421, "##zed": 5422, "lip": 5423, "arab": 5424, "capture": 5425, "interests": 5426, "insurance": 5427, "##chi": 5428, "shifted": 5429, "cave": 5430, "prix": 5431, "warning": 5432, "sections": 5433, "courts": 5434, "coat": 5435, "plot": 5436, "smell": 5437, "feed": 5438, "golf": 5439, "favorite": 5440, "maintain": 5441, "knife": 5442, "vs": 5443, "voted": 5444, "degrees": 5445, "finance": 5446, "quebec": 5447, "opinion": 5448, "translation": 5449, "manner": 5450, "ruled": 5451, "operate": 5452, "productions": 5453, "choose": 5454, "musician": 5455, "discovery": 5456, "confused": 5457, "tired": 5458, "separated": 5459, "stream": 5460, "techniques": 5461, "committed": 5462, "attend": 5463, "ranking": 5464, "kings": 5465, "throw": 5466, "passengers": 5467, "measure": 5468, "horror": 5469, "fan": 5470, "mining": 5471, "sand": 5472, "danger": 5473, "salt": 5474, "calm": 5475, "decade": 5476, "dam": 5477, "require": 5478, "runner": 5479, "##ik": 5480, "rush": 5481, "associate": 5482, "greece": 5483, "##ker": 5484, "rivers": 5485, "consecutive": 5486, "matthew": 5487, "##ski": 5488, "sighed": 5489, "sq": 5490, "documents": 5491, "steam": 5492, "edited": 5493, "closing": 5494, "tie": 5495, "accused": 5496, "1905": 5497, "##ini": 5498, "islamic": 5499, "distributed": 5500, "directors": 5501, "organisation": 5502, "bruce": 5503, "7th": 5504, "breathing": 5505, "mad": 5506, "lit": 5507, "arrival": 5508, "concrete": 5509, "taste": 5510, "08": 5511, "composition": 5512, "shaking": 5513, "faster": 5514, "amateur": 5515, "adjacent": 5516, "stating": 5517, "1906": 5518, "twin": 5519, "flew": 5520, "##ran": 5521, "tokyo": 5522, "publications": 5523, "##tone": 5524, "obviously": 5525, "ridge": 5526, "storage": 5527, "1907": 5528, "carl": 5529, "pages": 5530, "concluded": 5531, "desert": 5532, "driven": 5533, "universities": 5534, "ages": 5535, "terminal": 5536, "sequence": 5537, "borough": 5538, "250": 5539, "constituency": 5540, "creative": 5541, "cousin": 5542, "economics": 5543, "dreams": 5544, "margaret": 5545, "notably": 5546, "reduce": 5547, "montreal": 5548, "mode": 5549, "17th": 5550, "ears": 5551, "saved": 5552, "jan": 5553, "vocal": 5554, "##ica": 5555, "1909": 5556, "andy": 5557, "##jo": 5558, "riding": 5559, "roughly": 5560, "threatened": 5561, "##ise": 5562, "meters": 5563, "meanwhile": 5564, "landed": 5565, "compete": 5566, "repeated": 5567, "grass": 5568, "czech": 5569, "regularly": 5570, "charges": 5571, "tea": 5572, "sudden": 5573, "appeal": 5574, "##ung": 5575, "solution": 5576, "describes": 5577, "pierre": 5578, "classification": 5579, "glad": 5580, "parking": 5581, "##ning": 5582, "belt": 5583, "physics": 5584, "99": 5585, "rachel": 5586, "add": 5587, "hungarian": 5588, "participate": 5589, "expedition": 5590, "damaged": 5591, "gift": 5592, "childhood": 5593, "85": 5594, "fifty": 5595, "##red": 5596, "mathematics": 5597, "jumped": 5598, "letting": 5599, "defensive": 5600, "mph": 5601, "##ux": 5602, "##gh": 5603, "testing": 5604, "##hip": 5605, "hundreds": 5606, "shoot": 5607, "owners": 5608, "matters": 5609, "smoke": 5610, "israeli": 5611, "kentucky": 5612, "dancing": 5613, "mounted": 5614, "grandfather": 5615, "emma": 5616, "designs": 5617, "profit": 5618, "argentina": 5619, "##gs": 5620, "truly": 5621, "li": 5622, "lawrence": 5623, "cole": 5624, "begun": 5625, "detroit": 5626, "willing": 5627, "branches": 5628, "smiling": 5629, "decide": 5630, "miami": 5631, "enjoyed": 5632, "recordings": 5633, "##dale": 5634, "poverty": 5635, "ethnic": 5636, "gay": 5637, "##bi": 5638, "gary": 5639, "arabic": 5640, "09": 5641, "accompanied": 5642, "##one": 5643, "##ons": 5644, "fishing": 5645, "determine": 5646, "residential": 5647, "acid": 5648, "##ary": 5649, "alice": 5650, "returns": 5651, "starred": 5652, "mail": 5653, "##ang": 5654, "jonathan": 5655, "strategy": 5656, "##ue": 5657, "net": 5658, "forty": 5659, "cook": 5660, "businesses": 5661, "equivalent": 5662, "commonwealth": 5663, "distinct": 5664, "ill": 5665, "##cy": 5666, "seriously": 5667, "##ors": 5668, "##ped": 5669, "shift": 5670, "harris": 5671, "replace": 5672, "rio": 5673, "imagine": 5674, "formula": 5675, "ensure": 5676, "##ber": 5677, "additionally": 5678, "scheme": 5679, "conservation": 5680, "occasionally": 5681, "purposes": 5682, "feels": 5683, "favor": 5684, "##and": 5685, "##ore": 5686, "1930s": 5687, "contrast": 5688, "hanging": 5689, "hunt": 5690, "movies": 5691, "1904": 5692, "instruments": 5693, "victims": 5694, "danish": 5695, "christopher": 5696, "busy": 5697, "demon": 5698, "sugar": 5699, "earliest": 5700, "colony": 5701, "studying": 5702, "balance": 5703, "duties": 5704, "##ks": 5705, "belgium": 5706, "slipped": 5707, "carter": 5708, "05": 5709, "visible": 5710, "stages": 5711, "iraq": 5712, "fifa": 5713, "##im": 5714, "commune": 5715, "forming": 5716, "zero": 5717, "07": 5718, "continuing": 5719, "talked": 5720, "counties": 5721, "legend": 5722, "bathroom": 5723, "option": 5724, "tail": 5725, "clay": 5726, "daughters": 5727, "afterwards": 5728, "severe": 5729, "jaw": 5730, "visitors": 5731, "##ded": 5732, "devices": 5733, "aviation": 5734, "russell": 5735, "kate": 5736, "##vi": 5737, "entering": 5738, "subjects": 5739, "##ino": 5740, "temporary": 5741, "swimming": 5742, "forth": 5743, "smooth": 5744, "ghost": 5745, "audio": 5746, "bush": 5747, "operates": 5748, "rocks": 5749, "movements": 5750, "signs": 5751, "eddie": 5752, "##tz": 5753, "ann": 5754, "voices": 5755, "honorary": 5756, "06": 5757, "memories": 5758, "dallas": 5759, "pure": 5760, "measures": 5761, "racial": 5762, "promised": 5763, "66": 5764, "harvard": 5765, "ceo": 5766, "16th": 5767, "parliamentary": 5768, "indicate": 5769, "benefit": 5770, "flesh": 5771, "dublin": 5772, "louisiana": 5773, "1902": 5774, "1901": 5775, "patient": 5776, "sleeping": 5777, "1903": 5778, "membership": 5779, "coastal": 5780, "medieval": 5781, "wanting": 5782, "element": 5783, "scholars": 5784, "rice": 5785, "62": 5786, "limit": 5787, "survive": 5788, "makeup": 5789, "rating": 5790, "definitely": 5791, "collaboration": 5792, "obvious": 5793, "##tan": 5794, "boss": 5795, "ms": 5796, "baron": 5797, "birthday": 5798, "linked": 5799, "soil": 5800, "diocese": 5801, "##lan": 5802, "ncaa": 5803, "##mann": 5804, "offensive": 5805, "shell": 5806, "shouldn": 5807, "waist": 5808, "##tus": 5809, "plain": 5810, "ross": 5811, "organ": 5812, "resolution": 5813, "manufacturing": 5814, "adding": 5815, "relative": 5816, "kennedy": 5817, "98": 5818, "whilst": 5819, "moth": 5820, "marketing": 5821, "gardens": 5822, "crash": 5823, "72": 5824, "heading": 5825, "partners": 5826, "credited": 5827, "carlos": 5828, "moves": 5829, "cable": 5830, "##zi": 5831, "marshall": 5832, "##out": 5833, "depending": 5834, "bottle": 5835, "represents": 5836, "rejected": 5837, "responded": 5838, "existed": 5839, "04": 5840, "jobs": 5841, "denmark": 5842, "lock": 5843, "##ating": 5844, "treated": 5845, "graham": 5846, "routes": 5847, "talent": 5848, "commissioner": 5849, "drugs": 5850, "secure": 5851, "tests": 5852, "reign": 5853, "restored": 5854, "photography": 5855, "##gi": 5856, "contributions": 5857, "oklahoma": 5858, "designer": 5859, "disc": 5860, "grin": 5861, "seattle": 5862, "robin": 5863, "paused": 5864, "atlanta": 5865, "unusual": 5866, "##gate": 5867, "praised": 5868, "las": 5869, "laughing": 5870, "satellite": 5871, "hungary": 5872, "visiting": 5873, "##sky": 5874, "interesting": 5875, "factors": 5876, "deck": 5877, "poems": 5878, "norman": 5879, "##water": 5880, "stuck": 5881, "speaker": 5882, "rifle": 5883, "domain": 5884, "premiered": 5885, "##her": 5886, "dc": 5887, "comics": 5888, "actors": 5889, "01": 5890, "reputation": 5891, "eliminated": 5892, "8th": 5893, "ceiling": 5894, "prisoners": 5895, "script": 5896, "##nce": 5897, "leather": 5898, "austin": 5899, "mississippi": 5900, "rapidly": 5901, "admiral": 5902, "parallel": 5903, "charlotte": 5904, "guilty": 5905, "tools": 5906, "gender": 5907, "divisions": 5908, "fruit": 5909, "##bs": 5910, "laboratory": 5911, "nelson": 5912, "fantasy": 5913, "marry": 5914, "rapid": 5915, "aunt": 5916, "tribe": 5917, "requirements": 5918, "aspects": 5919, "suicide": 5920, "amongst": 5921, "adams": 5922, "bone": 5923, "ukraine": 5924, "abc": 5925, "kick": 5926, "sees": 5927, "edinburgh": 5928, "clothing": 5929, "column": 5930, "rough": 5931, "gods": 5932, "hunting": 5933, "broadway": 5934, "gathered": 5935, "concerns": 5936, "##ek": 5937, "spending": 5938, "ty": 5939, "12th": 5940, "snapped": 5941, "requires": 5942, "solar": 5943, "bones": 5944, "cavalry": 5945, "##tta": 5946, "iowa": 5947, "drinking": 5948, "waste": 5949, "index": 5950, "franklin": 5951, "charity": 5952, "thompson": 5953, "stewart": 5954, "tip": 5955, "flash": 5956, "landscape": 5957, "friday": 5958, "enjoy": 5959, "singh": 5960, "poem": 5961, "listening": 5962, "##back": 5963, "eighth": 5964, "fred": 5965, "differences": 5966, "adapted": 5967, "bomb": 5968, "ukrainian": 5969, "surgery": 5970, "corporate": 5971, "masters": 5972, "anywhere": 5973, "##more": 5974, "waves": 5975, "odd": 5976, "sean": 5977, "portugal": 5978, "orleans": 5979, "dick": 5980, "debate": 5981, "kent": 5982, "eating": 5983, "puerto": 5984, "cleared": 5985, "96": 5986, "expect": 5987, "cinema": 5988, "97": 5989, "guitarist": 5990, "blocks": 5991, "electrical": 5992, "agree": 5993, "involving": 5994, "depth": 5995, "dying": 5996, "panel": 5997, "struggle": 5998, "##ged": 5999, "peninsula": 6000, "adults": 6001, "novels": 6002, "emerged": 6003, "vienna": 6004, "metro": 6005, "debuted": 6006, "shoes": 6007, "tamil": 6008, "songwriter": 6009, "meets": 6010, "prove": 6011, "beating": 6012, "instance": 6013, "heaven": 6014, "scared": 6015, "sending": 6016, "marks": 6017, "artistic": 6018, "passage": 6019, "superior": 6020, "03": 6021, "significantly": 6022, "shopping": 6023, "##tive": 6024, "retained": 6025, "##izing": 6026, "malaysia": 6027, "technique": 6028, "cheeks": 6029, "##ola": 6030, "warren": 6031, "maintenance": 6032, "destroy": 6033, "extreme": 6034, "allied": 6035, "120": 6036, "appearing": 6037, "##yn": 6038, "fill": 6039, "advice": 6040, "alabama": 6041, "qualifying": 6042, "policies": 6043, "cleveland": 6044, "hat": 6045, "battery": 6046, "smart": 6047, "authors": 6048, "10th": 6049, "soundtrack": 6050, "acted": 6051, "dated": 6052, "lb": 6053, "glance": 6054, "equipped": 6055, "coalition": 6056, "funny": 6057, "outer": 6058, "ambassador": 6059, "roy": 6060, "possibility": 6061, "couples": 6062, "campbell": 6063, "dna": 6064, "loose": 6065, "ethan": 6066, "supplies": 6067, "1898": 6068, "gonna": 6069, "88": 6070, "monster": 6071, "##res": 6072, "shake": 6073, "agents": 6074, "frequency": 6075, "springs": 6076, "dogs": 6077, "practices": 6078, "61": 6079, "gang": 6080, "plastic": 6081, "easier": 6082, "suggests": 6083, "gulf": 6084, "blade": 6085, "exposed": 6086, "colors": 6087, "industries": 6088, "markets": 6089, "pan": 6090, "nervous": 6091, "electoral": 6092, "charts": 6093, "legislation": 6094, "ownership": 6095, "##idae": 6096, "mac": 6097, "appointment": 6098, "shield": 6099, "copy": 6100, "assault": 6101, "socialist": 6102, "abbey": 6103, "monument": 6104, "license": 6105, "throne": 6106, "employment": 6107, "jay": 6108, "93": 6109, "replacement": 6110, "charter": 6111, "cloud": 6112, "powered": 6113, "suffering": 6114, "accounts": 6115, "oak": 6116, "connecticut": 6117, "strongly": 6118, "wright": 6119, "colour": 6120, "crystal": 6121, "13th": 6122, "context": 6123, "welsh": 6124, "networks": 6125, "voiced": 6126, "gabriel": 6127, "jerry": 6128, "##cing": 6129, "forehead": 6130, "mp": 6131, "##ens": 6132, "manage": 6133, "schedule": 6134, "totally": 6135, "remix": 6136, "##ii": 6137, "forests": 6138, "occupation": 6139, "print": 6140, "nicholas": 6141, "brazilian": 6142, "strategic": 6143, "vampires": 6144, "engineers": 6145, "76": 6146, "roots": 6147, "seek": 6148, "correct": 6149, "instrumental": 6150, "und": 6151, "alfred": 6152, "backed": 6153, "hop": 6154, "##des": 6155, "stanley": 6156, "robinson": 6157, "traveled": 6158, "wayne": 6159, "welcome": 6160, "austrian": 6161, "achieve": 6162, "67": 6163, "exit": 6164, "rates": 6165, "1899": 6166, "strip": 6167, "whereas": 6168, "##cs": 6169, "sing": 6170, "deeply": 6171, "adventure": 6172, "bobby": 6173, "rick": 6174, "jamie": 6175, "careful": 6176, "components": 6177, "cap": 6178, "useful": 6179, "personality": 6180, "knee": 6181, "##shi": 6182, "pushing": 6183, "hosts": 6184, "02": 6185, "protest": 6186, "ca": 6187, "ottoman": 6188, "symphony": 6189, "##sis": 6190, "63": 6191, "boundary": 6192, "1890": 6193, "processes": 6194, "considering": 6195, "considerable": 6196, "tons": 6197, "##work": 6198, "##ft": 6199, "##nia": 6200, "cooper": 6201, "trading": 6202, "dear": 6203, "conduct": 6204, "91": 6205, "illegal": 6206, "apple": 6207, "revolutionary": 6208, "holiday": 6209, "definition": 6210, "harder": 6211, "##van": 6212, "jacob": 6213, "circumstances": 6214, "destruction": 6215, "##lle": 6216, "popularity": 6217, "grip": 6218, "classified": 6219, "liverpool": 6220, "donald": 6221, "baltimore": 6222, "flows": 6223, "seeking": 6224, "honour": 6225, "approval": 6226, "92": 6227, "mechanical": 6228, "till": 6229, "happening": 6230, "statue": 6231, "critic": 6232, "increasingly": 6233, "immediate": 6234, "describe": 6235, "commerce": 6236, "stare": 6237, "##ster": 6238, "indonesia": 6239, "meat": 6240, "rounds": 6241, "boats": 6242, "baker": 6243, "orthodox": 6244, "depression": 6245, "formally": 6246, "worn": 6247, "naked": 6248, "claire": 6249, "muttered": 6250, "sentence": 6251, "11th": 6252, "emily": 6253, "document": 6254, "77": 6255, "criticism": 6256, "wished": 6257, "vessel": 6258, "spiritual": 6259, "bent": 6260, "virgin": 6261, "parker": 6262, "minimum": 6263, "murray": 6264, "lunch": 6265, "danny": 6266, "printed": 6267, "compilation": 6268, "keyboards": 6269, "false": 6270, "blow": 6271, "belonged": 6272, "68": 6273, "raising": 6274, "78": 6275, "cutting": 6276, "##board": 6277, "pittsburgh": 6278, "##up": 6279, "9th": 6280, "shadows": 6281, "81": 6282, "hated": 6283, "indigenous": 6284, "jon": 6285, "15th": 6286, "barry": 6287, "scholar": 6288, "ah": 6289, "##zer": 6290, "oliver": 6291, "##gy": 6292, "stick": 6293, "susan": 6294, "meetings": 6295, "attracted": 6296, "spell": 6297, "romantic": 6298, "##ver": 6299, "ye": 6300, "1895": 6301, "photo": 6302, "demanded": 6303, "customers": 6304, "##ac": 6305, "1896": 6306, "logan": 6307, "revival": 6308, "keys": 6309, "modified": 6310, "commanded": 6311, "jeans": 6312, "##ious": 6313, "upset": 6314, "raw": 6315, "phil": 6316, "detective": 6317, "hiding": 6318, "resident": 6319, "vincent": 6320, "##bly": 6321, "experiences": 6322, "diamond": 6323, "defeating": 6324, "coverage": 6325, "lucas": 6326, "external": 6327, "parks": 6328, "franchise": 6329, "helen": 6330, "bible": 6331, "successor": 6332, "percussion": 6333, "celebrated": 6334, "il": 6335, "lift": 6336, "profile": 6337, "clan": 6338, "romania": 6339, "##ied": 6340, "mills": 6341, "##su": 6342, "nobody": 6343, "achievement": 6344, "shrugged": 6345, "fault": 6346, "1897": 6347, "rhythm": 6348, "initiative": 6349, "breakfast": 6350, "carbon": 6351, "700": 6352, "69": 6353, "lasted": 6354, "violent": 6355, "74": 6356, "wound": 6357, "ken": 6358, "killer": 6359, "gradually": 6360, "filmed": 6361, "°c": 6362, "dollars": 6363, "processing": 6364, "94": 6365, "remove": 6366, "criticized": 6367, "guests": 6368, "sang": 6369, "chemistry": 6370, "##vin": 6371, "legislature": 6372, "disney": 6373, "##bridge": 6374, "uniform": 6375, "escaped": 6376, "integrated": 6377, "proposal": 6378, "purple": 6379, "denied": 6380, "liquid": 6381, "karl": 6382, "influential": 6383, "morris": 6384, "nights": 6385, "stones": 6386, "intense": 6387, "experimental": 6388, "twisted": 6389, "71": 6390, "84": 6391, "##ld": 6392, "pace": 6393, "nazi": 6394, "mitchell": 6395, "ny": 6396, "blind": 6397, "reporter": 6398, "newspapers": 6399, "14th": 6400, "centers": 6401, "burn": 6402, "basin": 6403, "forgotten": 6404, "surviving": 6405, "filed": 6406, "collections": 6407, "monastery": 6408, "losses": 6409, "manual": 6410, "couch": 6411, "description": 6412, "appropriate": 6413, "merely": 6414, "tag": 6415, "missions": 6416, "sebastian": 6417, "restoration": 6418, "replacing": 6419, "triple": 6420, "73": 6421, "elder": 6422, "julia": 6423, "warriors": 6424, "benjamin": 6425, "julian": 6426, "convinced": 6427, "stronger": 6428, "amazing": 6429, "declined": 6430, "versus": 6431, "merchant": 6432, "happens": 6433, "output": 6434, "finland": 6435, "bare": 6436, "barbara": 6437, "absence": 6438, "ignored": 6439, "dawn": 6440, "injuries": 6441, "##port": 6442, "producers": 6443, "##ram": 6444, "82": 6445, "luis": 6446, "##ities": 6447, "kw": 6448, "admit": 6449, "expensive": 6450, "electricity": 6451, "nba": 6452, "exception": 6453, "symbol": 6454, "##ving": 6455, "ladies": 6456, "shower": 6457, "sheriff": 6458, "characteristics": 6459, "##je": 6460, "aimed": 6461, "button": 6462, "ratio": 6463, "effectively": 6464, "summit": 6465, "angle": 6466, "jury": 6467, "bears": 6468, "foster": 6469, "vessels": 6470, "pants": 6471, "executed": 6472, "evans": 6473, "dozen": 6474, "advertising": 6475, "kicked": 6476, "patrol": 6477, "1889": 6478, "competitions": 6479, "lifetime": 6480, "principles": 6481, "athletics": 6482, "##logy": 6483, "birmingham": 6484, "sponsored": 6485, "89": 6486, "rob": 6487, "nomination": 6488, "1893": 6489, "acoustic": 6490, "##sm": 6491, "creature": 6492, "longest": 6493, "##tra": 6494, "credits": 6495, "harbor": 6496, "dust": 6497, "josh": 6498, "##so": 6499, "territories": 6500, "milk": 6501, "infrastructure": 6502, "completion": 6503, "thailand": 6504, "indians": 6505, "leon": 6506, "archbishop": 6507, "##sy": 6508, "assist": 6509, "pitch": 6510, "blake": 6511, "arrangement": 6512, "girlfriend": 6513, "serbian": 6514, "operational": 6515, "hence": 6516, "sad": 6517, "scent": 6518, "fur": 6519, "dj": 6520, "sessions": 6521, "hp": 6522, "refer": 6523, "rarely": 6524, "##ora": 6525, "exists": 6526, "1892": 6527, "##ten": 6528, "scientists": 6529, "dirty": 6530, "penalty": 6531, "burst": 6532, "portrait": 6533, "seed": 6534, "79": 6535, "pole": 6536, "limits": 6537, "rival": 6538, "1894": 6539, "stable": 6540, "alpha": 6541, "grave": 6542, "constitutional": 6543, "alcohol": 6544, "arrest": 6545, "flower": 6546, "mystery": 6547, "devil": 6548, "architectural": 6549, "relationships": 6550, "greatly": 6551, "habitat": 6552, "##istic": 6553, "larry": 6554, "progressive": 6555, "remote": 6556, "cotton": 6557, "##ics": 6558, "##ok": 6559, "preserved": 6560, "reaches": 6561, "##ming": 6562, "cited": 6563, "86": 6564, "vast": 6565, "scholarship": 6566, "decisions": 6567, "cbs": 6568, "joy": 6569, "teach": 6570, "1885": 6571, "editions": 6572, "knocked": 6573, "eve": 6574, "searching": 6575, "partly": 6576, "participation": 6577, "gap": 6578, "animated": 6579, "fate": 6580, "excellent": 6581, "##ett": 6582, "na": 6583, "87": 6584, "alternate": 6585, "saints": 6586, "youngest": 6587, "##ily": 6588, "climbed": 6589, "##ita": 6590, "##tors": 6591, "suggest": 6592, "##ct": 6593, "discussion": 6594, "staying": 6595, "choir": 6596, "lakes": 6597, "jacket": 6598, "revenue": 6599, "nevertheless": 6600, "peaked": 6601, "instrument": 6602, "wondering": 6603, "annually": 6604, "managing": 6605, "neil": 6606, "1891": 6607, "signing": 6608, "terry": 6609, "##ice": 6610, "apply": 6611, "clinical": 6612, "brooklyn": 6613, "aim": 6614, "catherine": 6615, "fuck": 6616, "farmers": 6617, "figured": 6618, "ninth": 6619, "pride": 6620, "hugh": 6621, "evolution": 6622, "ordinary": 6623, "involvement": 6624, "comfortable": 6625, "shouted": 6626, "tech": 6627, "encouraged": 6628, "taiwan": 6629, "representation": 6630, "sharing": 6631, "##lia": 6632, "##em": 6633, "panic": 6634, "exact": 6635, "cargo": 6636, "competing": 6637, "fat": 6638, "cried": 6639, "83": 6640, "1920s": 6641, "occasions": 6642, "pa": 6643, "cabin": 6644, "borders": 6645, "utah": 6646, "marcus": 6647, "##isation": 6648, "badly": 6649, "muscles": 6650, "##ance": 6651, "victorian": 6652, "transition": 6653, "warner": 6654, "bet": 6655, "permission": 6656, "##rin": 6657, "slave": 6658, "terrible": 6659, "similarly": 6660, "shares": 6661, "seth": 6662, "uefa": 6663, "possession": 6664, "medals": 6665, "benefits": 6666, "colleges": 6667, "lowered": 6668, "perfectly": 6669, "mall": 6670, "transit": 6671, "##ye": 6672, "##kar": 6673, "publisher": 6674, "##ened": 6675, "harrison": 6676, "deaths": 6677, "elevation": 6678, "##ae": 6679, "asleep": 6680, "machines": 6681, "sigh": 6682, "ash": 6683, "hardly": 6684, "argument": 6685, "occasion": 6686, "parent": 6687, "leo": 6688, "decline": 6689, "1888": 6690, "contribution": 6691, "##ua": 6692, "concentration": 6693, "1000": 6694, "opportunities": 6695, "hispanic": 6696, "guardian": 6697, "extent": 6698, "emotions": 6699, "hips": 6700, "mason": 6701, "volumes": 6702, "bloody": 6703, "controversy": 6704, "diameter": 6705, "steady": 6706, "mistake": 6707, "phoenix": 6708, "identify": 6709, "violin": 6710, "##sk": 6711, "departure": 6712, "richmond": 6713, "spin": 6714, "funeral": 6715, "enemies": 6716, "1864": 6717, "gear": 6718, "literally": 6719, "connor": 6720, "random": 6721, "sergeant": 6722, "grab": 6723, "confusion": 6724, "1865": 6725, "transmission": 6726, "informed": 6727, "op": 6728, "leaning": 6729, "sacred": 6730, "suspended": 6731, "thinks": 6732, "gates": 6733, "portland": 6734, "luck": 6735, "agencies": 6736, "yours": 6737, "hull": 6738, "expert": 6739, "muscle": 6740, "layer": 6741, "practical": 6742, "sculpture": 6743, "jerusalem": 6744, "latest": 6745, "lloyd": 6746, "statistics": 6747, "deeper": 6748, "recommended": 6749, "warrior": 6750, "arkansas": 6751, "mess": 6752, "supports": 6753, "greg": 6754, "eagle": 6755, "1880": 6756, "recovered": 6757, "rated": 6758, "concerts": 6759, "rushed": 6760, "##ano": 6761, "stops": 6762, "eggs": 6763, "files": 6764, "premiere": 6765, "keith": 6766, "##vo": 6767, "delhi": 6768, "turner": 6769, "pit": 6770, "affair": 6771, "belief": 6772, "paint": 6773, "##zing": 6774, "mate": 6775, "##ach": 6776, "##ev": 6777, "victim": 6778, "##ology": 6779, "withdrew": 6780, "bonus": 6781, "styles": 6782, "fled": 6783, "##ud": 6784, "glasgow": 6785, "technologies": 6786, "funded": 6787, "nbc": 6788, "adaptation": 6789, "##ata": 6790, "portrayed": 6791, "cooperation": 6792, "supporters": 6793, "judges": 6794, "bernard": 6795, "justin": 6796, "hallway": 6797, "ralph": 6798, "##ick": 6799, "graduating": 6800, "controversial": 6801, "distant": 6802, "continental": 6803, "spider": 6804, "bite": 6805, "##ho": 6806, "recognize": 6807, "intention": 6808, "mixing": 6809, "##ese": 6810, "egyptian": 6811, "bow": 6812, "tourism": 6813, "suppose": 6814, "claiming": 6815, "tiger": 6816, "dominated": 6817, "participants": 6818, "vi": 6819, "##ru": 6820, "nurse": 6821, "partially": 6822, "tape": 6823, "##rum": 6824, "psychology": 6825, "##rn": 6826, "essential": 6827, "touring": 6828, "duo": 6829, "voting": 6830, "civilian": 6831, "emotional": 6832, "channels": 6833, "##king": 6834, "apparent": 6835, "hebrew": 6836, "1887": 6837, "tommy": 6838, "carrier": 6839, "intersection": 6840, "beast": 6841, "hudson": 6842, "##gar": 6843, "##zo": 6844, "lab": 6845, "nova": 6846, "bench": 6847, "discuss": 6848, "costa": 6849, "##ered": 6850, "detailed": 6851, "behalf": 6852, "drivers": 6853, "unfortunately": 6854, "obtain": 6855, "##lis": 6856, "rocky": 6857, "##dae": 6858, "siege": 6859, "friendship": 6860, "honey": 6861, "##rian": 6862, "1861": 6863, "amy": 6864, "hang": 6865, "posted": 6866, "governments": 6867, "collins": 6868, "respond": 6869, "wildlife": 6870, "preferred": 6871, "operator": 6872, "##po": 6873, "laura": 6874, "pregnant": 6875, "videos": 6876, "dennis": 6877, "suspected": 6878, "boots": 6879, "instantly": 6880, "weird": 6881, "automatic": 6882, "businessman": 6883, "alleged": 6884, "placing": 6885, "throwing": 6886, "ph": 6887, "mood": 6888, "1862": 6889, "perry": 6890, "venue": 6891, "jet": 6892, "remainder": 6893, "##lli": 6894, "##ci": 6895, "passion": 6896, "biological": 6897, "boyfriend": 6898, "1863": 6899, "dirt": 6900, "buffalo": 6901, "ron": 6902, "segment": 6903, "fa": 6904, "abuse": 6905, "##era": 6906, "genre": 6907, "thrown": 6908, "stroke": 6909, "colored": 6910, "stress": 6911, "exercise": 6912, "displayed": 6913, "##gen": 6914, "struggled": 6915, "##tti": 6916, "abroad": 6917, "dramatic": 6918, "wonderful": 6919, "thereafter": 6920, "madrid": 6921, "component": 6922, "widespread": 6923, "##sed": 6924, "tale": 6925, "citizen": 6926, "todd": 6927, "monday": 6928, "1886": 6929, "vancouver": 6930, "overseas": 6931, "forcing": 6932, "crying": 6933, "descent": 6934, "##ris": 6935, "discussed": 6936, "substantial": 6937, "ranks": 6938, "regime": 6939, "1870": 6940, "provinces": 6941, "switch": 6942, "drum": 6943, "zane": 6944, "ted": 6945, "tribes": 6946, "proof": 6947, "lp": 6948, "cream": 6949, "researchers": 6950, "volunteer": 6951, "manor": 6952, "silk": 6953, "milan": 6954, "donated": 6955, "allies": 6956, "venture": 6957, "principle": 6958, "delivery": 6959, "enterprise": 6960, "##ves": 6961, "##ans": 6962, "bars": 6963, "traditionally": 6964, "witch": 6965, "reminded": 6966, "copper": 6967, "##uk": 6968, "pete": 6969, "inter": 6970, "links": 6971, "colin": 6972, "grinned": 6973, "elsewhere": 6974, "competitive": 6975, "frequent": 6976, "##oy": 6977, "scream": 6978, "##hu": 6979, "tension": 6980, "texts": 6981, "submarine": 6982, "finnish": 6983, "defending": 6984, "defend": 6985, "pat": 6986, "detail": 6987, "1884": 6988, "affiliated": 6989, "stuart": 6990, "themes": 6991, "villa": 6992, "periods": 6993, "tool": 6994, "belgian": 6995, "ruling": 6996, "crimes": 6997, "answers": 6998, "folded": 6999, "licensed": 7000, "resort": 7001, "demolished": 7002, "hans": 7003, "lucy": 7004, "1881": 7005, "lion": 7006, "traded": 7007, "photographs": 7008, "writes": 7009, "craig": 7010, "##fa": 7011, "trials": 7012, "generated": 7013, "beth": 7014, "noble": 7015, "debt": 7016, "percentage": 7017, "yorkshire": 7018, "erected": 7019, "ss": 7020, "viewed": 7021, "grades": 7022, "confidence": 7023, "ceased": 7024, "islam": 7025, "telephone": 7026, "retail": 7027, "##ible": 7028, "chile": 7029, "m²": 7030, "roberts": 7031, "sixteen": 7032, "##ich": 7033, "commented": 7034, "hampshire": 7035, "innocent": 7036, "dual": 7037, "pounds": 7038, "checked": 7039, "regulations": 7040, "afghanistan": 7041, "sung": 7042, "rico": 7043, "liberty": 7044, "assets": 7045, "bigger": 7046, "options": 7047, "angels": 7048, "relegated": 7049, "tribute": 7050, "wells": 7051, "attending": 7052, "leaf": 7053, "##yan": 7054, "butler": 7055, "romanian": 7056, "forum": 7057, "monthly": 7058, "lisa": 7059, "patterns": 7060, "gmina": 7061, "##tory": 7062, "madison": 7063, "hurricane": 7064, "rev": 7065, "##ians": 7066, "bristol": 7067, "##ula": 7068, "elite": 7069, "valuable": 7070, "disaster": 7071, "democracy": 7072, "awareness": 7073, "germans": 7074, "freyja": 7075, "##ins": 7076, "loop": 7077, "absolutely": 7078, "paying": 7079, "populations": 7080, "maine": 7081, "sole": 7082, "prayer": 7083, "spencer": 7084, "releases": 7085, "doorway": 7086, "bull": 7087, "##ani": 7088, "lover": 7089, "midnight": 7090, "conclusion": 7091, "##sson": 7092, "thirteen": 7093, "lily": 7094, "mediterranean": 7095, "##lt": 7096, "nhl": 7097, "proud": 7098, "sample": 7099, "##hill": 7100, "drummer": 7101, "guinea": 7102, "##ova": 7103, "murphy": 7104, "climb": 7105, "##ston": 7106, "instant": 7107, "attributed": 7108, "horn": 7109, "ain": 7110, "railways": 7111, "steven": 7112, "##ao": 7113, "autumn": 7114, "ferry": 7115, "opponent": 7116, "root": 7117, "traveling": 7118, "secured": 7119, "corridor": 7120, "stretched": 7121, "tales": 7122, "sheet": 7123, "trinity": 7124, "cattle": 7125, "helps": 7126, "indicates": 7127, "manhattan": 7128, "murdered": 7129, "fitted": 7130, "1882": 7131, "gentle": 7132, "grandmother": 7133, "mines": 7134, "shocked": 7135, "vegas": 7136, "produces": 7137, "##light": 7138, "caribbean": 7139, "##ou": 7140, "belong": 7141, "continuous": 7142, "desperate": 7143, "drunk": 7144, "historically": 7145, "trio": 7146, "waved": 7147, "raf": 7148, "dealing": 7149, "nathan": 7150, "bat": 7151, "murmured": 7152, "interrupted": 7153, "residing": 7154, "scientist": 7155, "pioneer": 7156, "harold": 7157, "aaron": 7158, "##net": 7159, "delta": 7160, "attempting": 7161, "minority": 7162, "mini": 7163, "believes": 7164, "chorus": 7165, "tend": 7166, "lots": 7167, "eyed": 7168, "indoor": 7169, "load": 7170, "shots": 7171, "updated": 7172, "jail": 7173, "##llo": 7174, "concerning": 7175, "connecting": 7176, "wealth": 7177, "##ved": 7178, "slaves": 7179, "arrive": 7180, "rangers": 7181, "sufficient": 7182, "rebuilt": 7183, "##wick": 7184, "cardinal": 7185, "flood": 7186, "muhammad": 7187, "whenever": 7188, "relation": 7189, "runners": 7190, "moral": 7191, "repair": 7192, "viewers": 7193, "arriving": 7194, "revenge": 7195, "punk": 7196, "assisted": 7197, "bath": 7198, "fairly": 7199, "breathe": 7200, "lists": 7201, "innings": 7202, "illustrated": 7203, "whisper": 7204, "nearest": 7205, "voters": 7206, "clinton": 7207, "ties": 7208, "ultimate": 7209, "screamed": 7210, "beijing": 7211, "lions": 7212, "andre": 7213, "fictional": 7214, "gathering": 7215, "comfort": 7216, "radar": 7217, "suitable": 7218, "dismissed": 7219, "hms": 7220, "ban": 7221, "pine": 7222, "wrist": 7223, "atmosphere": 7224, "voivodeship": 7225, "bid": 7226, "timber": 7227, "##ned": 7228, "##nan": 7229, "giants": 7230, "##ane": 7231, "cameron": 7232, "recovery": 7233, "uss": 7234, "identical": 7235, "categories": 7236, "switched": 7237, "serbia": 7238, "laughter": 7239, "noah": 7240, "ensemble": 7241, "therapy": 7242, "peoples": 7243, "touching": 7244, "##off": 7245, "locally": 7246, "pearl": 7247, "platforms": 7248, "everywhere": 7249, "ballet": 7250, "tables": 7251, "lanka": 7252, "herbert": 7253, "outdoor": 7254, "toured": 7255, "derek": 7256, "1883": 7257, "spaces": 7258, "contested": 7259, "swept": 7260, "1878": 7261, "exclusive": 7262, "slight": 7263, "connections": 7264, "##dra": 7265, "winds": 7266, "prisoner": 7267, "collective": 7268, "bangladesh": 7269, "tube": 7270, "publicly": 7271, "wealthy": 7272, "thai": 7273, "##ys": 7274, "isolated": 7275, "select": 7276, "##ric": 7277, "insisted": 7278, "pen": 7279, "fortune": 7280, "ticket": 7281, "spotted": 7282, "reportedly": 7283, "animation": 7284, "enforcement": 7285, "tanks": 7286, "110": 7287, "decides": 7288, "wider": 7289, "lowest": 7290, "owen": 7291, "##time": 7292, "nod": 7293, "hitting": 7294, "##hn": 7295, "gregory": 7296, "furthermore": 7297, "magazines": 7298, "fighters": 7299, "solutions": 7300, "##ery": 7301, "pointing": 7302, "requested": 7303, "peru": 7304, "reed": 7305, "chancellor": 7306, "knights": 7307, "mask": 7308, "worker": 7309, "eldest": 7310, "flames": 7311, "reduction": 7312, "1860": 7313, "volunteers": 7314, "##tis": 7315, "reporting": 7316, "##hl": 7317, "wire": 7318, "advisory": 7319, "endemic": 7320, "origins": 7321, "settlers": 7322, "pursue": 7323, "knock": 7324, "consumer": 7325, "1876": 7326, "eu": 7327, "compound": 7328, "creatures": 7329, "mansion": 7330, "sentenced": 7331, "ivan": 7332, "deployed": 7333, "guitars": 7334, "frowned": 7335, "involves": 7336, "mechanism": 7337, "kilometers": 7338, "perspective": 7339, "shops": 7340, "maps": 7341, "terminus": 7342, "duncan": 7343, "alien": 7344, "fist": 7345, "bridges": 7346, "##pers": 7347, "heroes": 7348, "fed": 7349, "derby": 7350, "swallowed": 7351, "##ros": 7352, "patent": 7353, "sara": 7354, "illness": 7355, "characterized": 7356, "adventures": 7357, "slide": 7358, "hawaii": 7359, "jurisdiction": 7360, "##op": 7361, "organised": 7362, "##side": 7363, "adelaide": 7364, "walks": 7365, "biology": 7366, "se": 7367, "##ties": 7368, "rogers": 7369, "swing": 7370, "tightly": 7371, "boundaries": 7372, "##rie": 7373, "prepare": 7374, "implementation": 7375, "stolen": 7376, "##sha": 7377, "certified": 7378, "colombia": 7379, "edwards": 7380, "garage": 7381, "##mm": 7382, "recalled": 7383, "##ball": 7384, "rage": 7385, "harm": 7386, "nigeria": 7387, "breast": 7388, "##ren": 7389, "furniture": 7390, "pupils": 7391, "settle": 7392, "##lus": 7393, "cuba": 7394, "balls": 7395, "client": 7396, "alaska": 7397, "21st": 7398, "linear": 7399, "thrust": 7400, "celebration": 7401, "latino": 7402, "genetic": 7403, "terror": 7404, "##cia": 7405, "##ening": 7406, "lightning": 7407, "fee": 7408, "witness": 7409, "lodge": 7410, "establishing": 7411, "skull": 7412, "##ique": 7413, "earning": 7414, "hood": 7415, "##ei": 7416, "rebellion": 7417, "wang": 7418, "sporting": 7419, "warned": 7420, "missile": 7421, "devoted": 7422, "activist": 7423, "porch": 7424, "worship": 7425, "fourteen": 7426, "package": 7427, "1871": 7428, "decorated": 7429, "##shire": 7430, "housed": 7431, "##ock": 7432, "chess": 7433, "sailed": 7434, "doctors": 7435, "oscar": 7436, "joan": 7437, "treat": 7438, "garcia": 7439, "harbour": 7440, "jeremy": 7441, "##ire": 7442, "traditions": 7443, "dominant": 7444, "jacques": 7445, "##gon": 7446, "##wan": 7447, "relocated": 7448, "1879": 7449, "amendment": 7450, "sized": 7451, "companion": 7452, "simultaneously": 7453, "volleyball": 7454, "spun": 7455, "acre": 7456, "increases": 7457, "stopping": 7458, "loves": 7459, "belongs": 7460, "affect": 7461, "drafted": 7462, "tossed": 7463, "scout": 7464, "battles": 7465, "1875": 7466, "filming": 7467, "shoved": 7468, "munich": 7469, "tenure": 7470, "vertical": 7471, "romance": 7472, "pc": 7473, "##cher": 7474, "argue": 7475, "##ical": 7476, "craft": 7477, "ranging": 7478, "www": 7479, "opens": 7480, "honest": 7481, "tyler": 7482, "yesterday": 7483, "virtual": 7484, "##let": 7485, "muslims": 7486, "reveal": 7487, "snake": 7488, "immigrants": 7489, "radical": 7490, "screaming": 7491, "speakers": 7492, "firing": 7493, "saving": 7494, "belonging": 7495, "ease": 7496, "lighting": 7497, "prefecture": 7498, "blame": 7499, "farmer": 7500, "hungry": 7501, "grows": 7502, "rubbed": 7503, "beam": 7504, "sur": 7505, "subsidiary": 7506, "##cha": 7507, "armenian": 7508, "sao": 7509, "dropping": 7510, "conventional": 7511, "##fer": 7512, "microsoft": 7513, "reply": 7514, "qualify": 7515, "spots": 7516, "1867": 7517, "sweat": 7518, "festivals": 7519, "##ken": 7520, "immigration": 7521, "physician": 7522, "discover": 7523, "exposure": 7524, "sandy": 7525, "explanation": 7526, "isaac": 7527, "implemented": 7528, "##fish": 7529, "hart": 7530, "initiated": 7531, "connect": 7532, "stakes": 7533, "presents": 7534, "heights": 7535, "householder": 7536, "pleased": 7537, "tourist": 7538, "regardless": 7539, "slip": 7540, "closest": 7541, "##ction": 7542, "surely": 7543, "sultan": 7544, "brings": 7545, "riley": 7546, "preparation": 7547, "aboard": 7548, "slammed": 7549, "baptist": 7550, "experiment": 7551, "ongoing": 7552, "interstate": 7553, "organic": 7554, "playoffs": 7555, "##ika": 7556, "1877": 7557, "130": 7558, "##tar": 7559, "hindu": 7560, "error": 7561, "tours": 7562, "tier": 7563, "plenty": 7564, "arrangements": 7565, "talks": 7566, "trapped": 7567, "excited": 7568, "sank": 7569, "ho": 7570, "athens": 7571, "1872": 7572, "denver": 7573, "welfare": 7574, "suburb": 7575, "athletes": 7576, "trick": 7577, "diverse": 7578, "belly": 7579, "exclusively": 7580, "yelled": 7581, "1868": 7582, "##med": 7583, "conversion": 7584, "##ette": 7585, "1874": 7586, "internationally": 7587, "computers": 7588, "conductor": 7589, "abilities": 7590, "sensitive": 7591, "hello": 7592, "dispute": 7593, "measured": 7594, "globe": 7595, "rocket": 7596, "prices": 7597, "amsterdam": 7598, "flights": 7599, "tigers": 7600, "inn": 7601, "municipalities": 7602, "emotion": 7603, "references": 7604, "3d": 7605, "##mus": 7606, "explains": 7607, "airlines": 7608, "manufactured": 7609, "pm": 7610, "archaeological": 7611, "1873": 7612, "interpretation": 7613, "devon": 7614, "comment": 7615, "##ites": 7616, "settlements": 7617, "kissing": 7618, "absolute": 7619, "improvement": 7620, "suite": 7621, "impressed": 7622, "barcelona": 7623, "sullivan": 7624, "jefferson": 7625, "towers": 7626, "jesse": 7627, "julie": 7628, "##tin": 7629, "##lu": 7630, "grandson": 7631, "hi": 7632, "gauge": 7633, "regard": 7634, "rings": 7635, "interviews": 7636, "trace": 7637, "raymond": 7638, "thumb": 7639, "departments": 7640, "burns": 7641, "serial": 7642, "bulgarian": 7643, "scores": 7644, "demonstrated": 7645, "##ix": 7646, "1866": 7647, "kyle": 7648, "alberta": 7649, "underneath": 7650, "romanized": 7651, "##ward": 7652, "relieved": 7653, "acquisition": 7654, "phrase": 7655, "cliff": 7656, "reveals": 7657, "han": 7658, "cuts": 7659, "merger": 7660, "custom": 7661, "##dar": 7662, "nee": 7663, "gilbert": 7664, "graduation": 7665, "##nts": 7666, "assessment": 7667, "cafe": 7668, "difficulty": 7669, "demands": 7670, "swung": 7671, "democrat": 7672, "jennifer": 7673, "commons": 7674, "1940s": 7675, "grove": 7676, "##yo": 7677, "completing": 7678, "focuses": 7679, "sum": 7680, "substitute": 7681, "bearing": 7682, "stretch": 7683, "reception": 7684, "##py": 7685, "reflected": 7686, "essentially": 7687, "destination": 7688, "pairs": 7689, "##ched": 7690, "survival": 7691, "resource": 7692, "##bach": 7693, "promoting": 7694, "doubles": 7695, "messages": 7696, "tear": 7697, "##down": 7698, "##fully": 7699, "parade": 7700, "florence": 7701, "harvey": 7702, "incumbent": 7703, "partial": 7704, "framework": 7705, "900": 7706, "pedro": 7707, "frozen": 7708, "procedure": 7709, "olivia": 7710, "controls": 7711, "##mic": 7712, "shelter": 7713, "personally": 7714, "temperatures": 7715, "##od": 7716, "brisbane": 7717, "tested": 7718, "sits": 7719, "marble": 7720, "comprehensive": 7721, "oxygen": 7722, "leonard": 7723, "##kov": 7724, "inaugural": 7725, "iranian": 7726, "referring": 7727, "quarters": 7728, "attitude": 7729, "##ivity": 7730, "mainstream": 7731, "lined": 7732, "mars": 7733, "dakota": 7734, "norfolk": 7735, "unsuccessful": 7736, "##°": 7737, "explosion": 7738, "helicopter": 7739, "congressional": 7740, "##sing": 7741, "inspector": 7742, "bitch": 7743, "seal": 7744, "departed": 7745, "divine": 7746, "##ters": 7747, "coaching": 7748, "examination": 7749, "punishment": 7750, "manufacturer": 7751, "sink": 7752, "columns": 7753, "unincorporated": 7754, "signals": 7755, "nevada": 7756, "squeezed": 7757, "dylan": 7758, "dining": 7759, "photos": 7760, "martial": 7761, "manuel": 7762, "eighteen": 7763, "elevator": 7764, "brushed": 7765, "plates": 7766, "ministers": 7767, "ivy": 7768, "congregation": 7769, "##len": 7770, "slept": 7771, "specialized": 7772, "taxes": 7773, "curve": 7774, "restricted": 7775, "negotiations": 7776, "likes": 7777, "statistical": 7778, "arnold": 7779, "inspiration": 7780, "execution": 7781, "bold": 7782, "intermediate": 7783, "significance": 7784, "margin": 7785, "ruler": 7786, "wheels": 7787, "gothic": 7788, "intellectual": 7789, "dependent": 7790, "listened": 7791, "eligible": 7792, "buses": 7793, "widow": 7794, "syria": 7795, "earn": 7796, "cincinnati": 7797, "collapsed": 7798, "recipient": 7799, "secrets": 7800, "accessible": 7801, "philippine": 7802, "maritime": 7803, "goddess": 7804, "clerk": 7805, "surrender": 7806, "breaks": 7807, "playoff": 7808, "database": 7809, "##ified": 7810, "##lon": 7811, "ideal": 7812, "beetle": 7813, "aspect": 7814, "soap": 7815, "regulation": 7816, "strings": 7817, "expand": 7818, "anglo": 7819, "shorter": 7820, "crosses": 7821, "retreat": 7822, "tough": 7823, "coins": 7824, "wallace": 7825, "directions": 7826, "pressing": 7827, "##oon": 7828, "shipping": 7829, "locomotives": 7830, "comparison": 7831, "topics": 7832, "nephew": 7833, "##mes": 7834, "distinction": 7835, "honors": 7836, "travelled": 7837, "sierra": 7838, "ibn": 7839, "##over": 7840, "fortress": 7841, "sa": 7842, "recognised": 7843, "carved": 7844, "1869": 7845, "clients": 7846, "##dan": 7847, "intent": 7848, "##mar": 7849, "coaches": 7850, "describing": 7851, "bread": 7852, "##ington": 7853, "beaten": 7854, "northwestern": 7855, "##ona": 7856, "merit": 7857, "youtube": 7858, "collapse": 7859, "challenges": 7860, "em": 7861, "historians": 7862, "objective": 7863, "submitted": 7864, "virus": 7865, "attacking": 7866, "drake": 7867, "assume": 7868, "##ere": 7869, "diseases": 7870, "marc": 7871, "stem": 7872, "leeds": 7873, "##cus": 7874, "##ab": 7875, "farming": 7876, "glasses": 7877, "##lock": 7878, "visits": 7879, "nowhere": 7880, "fellowship": 7881, "relevant": 7882, "carries": 7883, "restaurants": 7884, "experiments": 7885, "101": 7886, "constantly": 7887, "bases": 7888, "targets": 7889, "shah": 7890, "tenth": 7891, "opponents": 7892, "verse": 7893, "territorial": 7894, "##ira": 7895, "writings": 7896, "corruption": 7897, "##hs": 7898, "instruction": 7899, "inherited": 7900, "reverse": 7901, "emphasis": 7902, "##vic": 7903, "employee": 7904, "arch": 7905, "keeps": 7906, "rabbi": 7907, "watson": 7908, "payment": 7909, "uh": 7910, "##ala": 7911, "nancy": 7912, "##tre": 7913, "venice": 7914, "fastest": 7915, "sexy": 7916, "banned": 7917, "adrian": 7918, "properly": 7919, "ruth": 7920, "touchdown": 7921, "dollar": 7922, "boards": 7923, "metre": 7924, "circles": 7925, "edges": 7926, "favour": 7927, "comments": 7928, "ok": 7929, "travels": 7930, "liberation": 7931, "scattered": 7932, "firmly": 7933, "##ular": 7934, "holland": 7935, "permitted": 7936, "diesel": 7937, "kenya": 7938, "den": 7939, "originated": 7940, "##ral": 7941, "demons": 7942, "resumed": 7943, "dragged": 7944, "rider": 7945, "##rus": 7946, "servant": 7947, "blinked": 7948, "extend": 7949, "torn": 7950, "##ias": 7951, "##sey": 7952, "input": 7953, "meal": 7954, "everybody": 7955, "cylinder": 7956, "kinds": 7957, "camps": 7958, "##fe": 7959, "bullet": 7960, "logic": 7961, "##wn": 7962, "croatian": 7963, "evolved": 7964, "healthy": 7965, "fool": 7966, "chocolate": 7967, "wise": 7968, "preserve": 7969, "pradesh": 7970, "##ess": 7971, "respective": 7972, "1850": 7973, "##ew": 7974, "chicken": 7975, "artificial": 7976, "gross": 7977, "corresponding": 7978, "convicted": 7979, "cage": 7980, "caroline": 7981, "dialogue": 7982, "##dor": 7983, "narrative": 7984, "stranger": 7985, "mario": 7986, "br": 7987, "christianity": 7988, "failing": 7989, "trent": 7990, "commanding": 7991, "buddhist": 7992, "1848": 7993, "maurice": 7994, "focusing": 7995, "yale": 7996, "bike": 7997, "altitude": 7998, "##ering": 7999, "mouse": 8000, "revised": 8001, "##sley": 8002, "veteran": 8003, "##ig": 8004, "pulls": 8005, "theology": 8006, "crashed": 8007, "campaigns": 8008, "legion": 8009, "##ability": 8010, "drag": 8011, "excellence": 8012, "customer": 8013, "cancelled": 8014, "intensity": 8015, "excuse": 8016, "##lar": 8017, "liga": 8018, "participating": 8019, "contributing": 8020, "printing": 8021, "##burn": 8022, "variable": 8023, "##rk": 8024, "curious": 8025, "bin": 8026, "legacy": 8027, "renaissance": 8028, "##my": 8029, "symptoms": 8030, "binding": 8031, "vocalist": 8032, "dancer": 8033, "##nie": 8034, "grammar": 8035, "gospel": 8036, "democrats": 8037, "ya": 8038, "enters": 8039, "sc": 8040, "diplomatic": 8041, "hitler": 8042, "##ser": 8043, "clouds": 8044, "mathematical": 8045, "quit": 8046, "defended": 8047, "oriented": 8048, "##heim": 8049, "fundamental": 8050, "hardware": 8051, "impressive": 8052, "equally": 8053, "convince": 8054, "confederate": 8055, "guilt": 8056, "chuck": 8057, "sliding": 8058, "##ware": 8059, "magnetic": 8060, "narrowed": 8061, "petersburg": 8062, "bulgaria": 8063, "otto": 8064, "phd": 8065, "skill": 8066, "##ama": 8067, "reader": 8068, "hopes": 8069, "pitcher": 8070, "reservoir": 8071, "hearts": 8072, "automatically": 8073, "expecting": 8074, "mysterious": 8075, "bennett": 8076, "extensively": 8077, "imagined": 8078, "seeds": 8079, "monitor": 8080, "fix": 8081, "##ative": 8082, "journalism": 8083, "struggling": 8084, "signature": 8085, "ranch": 8086, "encounter": 8087, "photographer": 8088, "observation": 8089, "protests": 8090, "##pin": 8091, "influences": 8092, "##hr": 8093, "calendar": 8094, "##all": 8095, "cruz": 8096, "croatia": 8097, "locomotive": 8098, "hughes": 8099, "naturally": 8100, "shakespeare": 8101, "basement": 8102, "hook": 8103, "uncredited": 8104, "faded": 8105, "theories": 8106, "approaches": 8107, "dare": 8108, "phillips": 8109, "filling": 8110, "fury": 8111, "obama": 8112, "##ain": 8113, "efficient": 8114, "arc": 8115, "deliver": 8116, "min": 8117, "raid": 8118, "breeding": 8119, "inducted": 8120, "leagues": 8121, "efficiency": 8122, "axis": 8123, "montana": 8124, "eagles": 8125, "##ked": 8126, "supplied": 8127, "instructions": 8128, "karen": 8129, "picking": 8130, "indicating": 8131, "trap": 8132, "anchor": 8133, "practically": 8134, "christians": 8135, "tomb": 8136, "vary": 8137, "occasional": 8138, "electronics": 8139, "lords": 8140, "readers": 8141, "newcastle": 8142, "faint": 8143, "innovation": 8144, "collect": 8145, "situations": 8146, "engagement": 8147, "160": 8148, "claude": 8149, "mixture": 8150, "##feld": 8151, "peer": 8152, "tissue": 8153, "logo": 8154, "lean": 8155, "##ration": 8156, "°f": 8157, "floors": 8158, "##ven": 8159, "architects": 8160, "reducing": 8161, "##our": 8162, "##ments": 8163, "rope": 8164, "1859": 8165, "ottawa": 8166, "##har": 8167, "samples": 8168, "banking": 8169, "declaration": 8170, "proteins": 8171, "resignation": 8172, "francois": 8173, "saudi": 8174, "advocate": 8175, "exhibited": 8176, "armor": 8177, "twins": 8178, "divorce": 8179, "##ras": 8180, "abraham": 8181, "reviewed": 8182, "jo": 8183, "temporarily": 8184, "matrix": 8185, "physically": 8186, "pulse": 8187, "curled": 8188, "##ena": 8189, "difficulties": 8190, "bengal": 8191, "usage": 8192, "##ban": 8193, "annie": 8194, "riders": 8195, "certificate": 8196, "##pi": 8197, "holes": 8198, "warsaw": 8199, "distinctive": 8200, "jessica": 8201, "##mon": 8202, "mutual": 8203, "1857": 8204, "customs": 8205, "circular": 8206, "eugene": 8207, "removal": 8208, "loaded": 8209, "mere": 8210, "vulnerable": 8211, "depicted": 8212, "generations": 8213, "dame": 8214, "heir": 8215, "enormous": 8216, "lightly": 8217, "climbing": 8218, "pitched": 8219, "lessons": 8220, "pilots": 8221, "nepal": 8222, "ram": 8223, "google": 8224, "preparing": 8225, "brad": 8226, "louise": 8227, "renowned": 8228, "##₂": 8229, "liam": 8230, "##ably": 8231, "plaza": 8232, "shaw": 8233, "sophie": 8234, "brilliant": 8235, "bills": 8236, "##bar": 8237, "##nik": 8238, "fucking": 8239, "mainland": 8240, "server": 8241, "pleasant": 8242, "seized": 8243, "veterans": 8244, "jerked": 8245, "fail": 8246, "beta": 8247, "brush": 8248, "radiation": 8249, "stored": 8250, "warmth": 8251, "southeastern": 8252, "nate": 8253, "sin": 8254, "raced": 8255, "berkeley": 8256, "joke": 8257, "athlete": 8258, "designation": 8259, "trunk": 8260, "##low": 8261, "roland": 8262, "qualification": 8263, "archives": 8264, "heels": 8265, "artwork": 8266, "receives": 8267, "judicial": 8268, "reserves": 8269, "##bed": 8270, "woke": 8271, "installation": 8272, "abu": 8273, "floating": 8274, "fake": 8275, "lesser": 8276, "excitement": 8277, "interface": 8278, "concentrated": 8279, "addressed": 8280, "characteristic": 8281, "amanda": 8282, "saxophone": 8283, "monk": 8284, "auto": 8285, "##bus": 8286, "releasing": 8287, "egg": 8288, "dies": 8289, "interaction": 8290, "defender": 8291, "ce": 8292, "outbreak": 8293, "glory": 8294, "loving": 8295, "##bert": 8296, "sequel": 8297, "consciousness": 8298, "http": 8299, "awake": 8300, "ski": 8301, "enrolled": 8302, "##ress": 8303, "handling": 8304, "rookie": 8305, "brow": 8306, "somebody": 8307, "biography": 8308, "warfare": 8309, "amounts": 8310, "contracts": 8311, "presentation": 8312, "fabric": 8313, "dissolved": 8314, "challenged": 8315, "meter": 8316, "psychological": 8317, "lt": 8318, "elevated": 8319, "rally": 8320, "accurate": 8321, "##tha": 8322, "hospitals": 8323, "undergraduate": 8324, "specialist": 8325, "venezuela": 8326, "exhibit": 8327, "shed": 8328, "nursing": 8329, "protestant": 8330, "fluid": 8331, "structural": 8332, "footage": 8333, "jared": 8334, "consistent": 8335, "prey": 8336, "##ska": 8337, "succession": 8338, "reflect": 8339, "exile": 8340, "lebanon": 8341, "wiped": 8342, "suspect": 8343, "shanghai": 8344, "resting": 8345, "integration": 8346, "preservation": 8347, "marvel": 8348, "variant": 8349, "pirates": 8350, "sheep": 8351, "rounded": 8352, "capita": 8353, "sailing": 8354, "colonies": 8355, "manuscript": 8356, "deemed": 8357, "variations": 8358, "clarke": 8359, "functional": 8360, "emerging": 8361, "boxing": 8362, "relaxed": 8363, "curse": 8364, "azerbaijan": 8365, "heavyweight": 8366, "nickname": 8367, "editorial": 8368, "rang": 8369, "grid": 8370, "tightened": 8371, "earthquake": 8372, "flashed": 8373, "miguel": 8374, "rushing": 8375, "##ches": 8376, "improvements": 8377, "boxes": 8378, "brooks": 8379, "180": 8380, "consumption": 8381, "molecular": 8382, "felix": 8383, "societies": 8384, "repeatedly": 8385, "variation": 8386, "aids": 8387, "civic": 8388, "graphics": 8389, "professionals": 8390, "realm": 8391, "autonomous": 8392, "receiver": 8393, "delayed": 8394, "workshop": 8395, "militia": 8396, "chairs": 8397, "trump": 8398, "canyon": 8399, "##point": 8400, "harsh": 8401, "extending": 8402, "lovely": 8403, "happiness": 8404, "##jan": 8405, "stake": 8406, "eyebrows": 8407, "embassy": 8408, "wellington": 8409, "hannah": 8410, "##ella": 8411, "sony": 8412, "corners": 8413, "bishops": 8414, "swear": 8415, "cloth": 8416, "contents": 8417, "xi": 8418, "namely": 8419, "commenced": 8420, "1854": 8421, "stanford": 8422, "nashville": 8423, "courage": 8424, "graphic": 8425, "commitment": 8426, "garrison": 8427, "##bin": 8428, "hamlet": 8429, "clearing": 8430, "rebels": 8431, "attraction": 8432, "literacy": 8433, "cooking": 8434, "ruins": 8435, "temples": 8436, "jenny": 8437, "humanity": 8438, "celebrate": 8439, "hasn": 8440, "freight": 8441, "sixty": 8442, "rebel": 8443, "bastard": 8444, "##art": 8445, "newton": 8446, "##ada": 8447, "deer": 8448, "##ges": 8449, "##ching": 8450, "smiles": 8451, "delaware": 8452, "singers": 8453, "##ets": 8454, "approaching": 8455, "assists": 8456, "flame": 8457, "##ph": 8458, "boulevard": 8459, "barrel": 8460, "planted": 8461, "##ome": 8462, "pursuit": 8463, "##sia": 8464, "consequences": 8465, "posts": 8466, "shallow": 8467, "invitation": 8468, "rode": 8469, "depot": 8470, "ernest": 8471, "kane": 8472, "rod": 8473, "concepts": 8474, "preston": 8475, "topic": 8476, "chambers": 8477, "striking": 8478, "blast": 8479, "arrives": 8480, "descendants": 8481, "montgomery": 8482, "ranges": 8483, "worlds": 8484, "##lay": 8485, "##ari": 8486, "span": 8487, "chaos": 8488, "praise": 8489, "##ag": 8490, "fewer": 8491, "1855": 8492, "sanctuary": 8493, "mud": 8494, "fbi": 8495, "##ions": 8496, "programmes": 8497, "maintaining": 8498, "unity": 8499, "harper": 8500, "bore": 8501, "handsome": 8502, "closure": 8503, "tournaments": 8504, "thunder": 8505, "nebraska": 8506, "linda": 8507, "facade": 8508, "puts": 8509, "satisfied": 8510, "argentine": 8511, "dale": 8512, "cork": 8513, "dome": 8514, "panama": 8515, "##yl": 8516, "1858": 8517, "tasks": 8518, "experts": 8519, "##ates": 8520, "feeding": 8521, "equation": 8522, "##las": 8523, "##ida": 8524, "##tu": 8525, "engage": 8526, "bryan": 8527, "##ax": 8528, "um": 8529, "quartet": 8530, "melody": 8531, "disbanded": 8532, "sheffield": 8533, "blocked": 8534, "gasped": 8535, "delay": 8536, "kisses": 8537, "maggie": 8538, "connects": 8539, "##non": 8540, "sts": 8541, "poured": 8542, "creator": 8543, "publishers": 8544, "##we": 8545, "guided": 8546, "ellis": 8547, "extinct": 8548, "hug": 8549, "gaining": 8550, "##ord": 8551, "complicated": 8552, "##bility": 8553, "poll": 8554, "clenched": 8555, "investigate": 8556, "##use": 8557, "thereby": 8558, "quantum": 8559, "spine": 8560, "cdp": 8561, "humor": 8562, "kills": 8563, "administered": 8564, "semifinals": 8565, "##du": 8566, "encountered": 8567, "ignore": 8568, "##bu": 8569, "commentary": 8570, "##maker": 8571, "bother": 8572, "roosevelt": 8573, "140": 8574, "plains": 8575, "halfway": 8576, "flowing": 8577, "cultures": 8578, "crack": 8579, "imprisoned": 8580, "neighboring": 8581, "airline": 8582, "##ses": 8583, "##view": 8584, "##mate": 8585, "##ec": 8586, "gather": 8587, "wolves": 8588, "marathon": 8589, "transformed": 8590, "##ill": 8591, "cruise": 8592, "organisations": 8593, "carol": 8594, "punch": 8595, "exhibitions": 8596, "numbered": 8597, "alarm": 8598, "ratings": 8599, "daddy": 8600, "silently": 8601, "##stein": 8602, "queens": 8603, "colours": 8604, "impression": 8605, "guidance": 8606, "liu": 8607, "tactical": 8608, "##rat": 8609, "marshal": 8610, "della": 8611, "arrow": 8612, "##ings": 8613, "rested": 8614, "feared": 8615, "tender": 8616, "owns": 8617, "bitter": 8618, "advisor": 8619, "escort": 8620, "##ides": 8621, "spare": 8622, "farms": 8623, "grants": 8624, "##ene": 8625, "dragons": 8626, "encourage": 8627, "colleagues": 8628, "cameras": 8629, "##und": 8630, "sucked": 8631, "pile": 8632, "spirits": 8633, "prague": 8634, "statements": 8635, "suspension": 8636, "landmark": 8637, "fence": 8638, "torture": 8639, "recreation": 8640, "bags": 8641, "permanently": 8642, "survivors": 8643, "pond": 8644, "spy": 8645, "predecessor": 8646, "bombing": 8647, "coup": 8648, "##og": 8649, "protecting": 8650, "transformation": 8651, "glow": 8652, "##lands": 8653, "##book": 8654, "dug": 8655, "priests": 8656, "andrea": 8657, "feat": 8658, "barn": 8659, "jumping": 8660, "##chen": 8661, "##ologist": 8662, "##con": 8663, "casualties": 8664, "stern": 8665, "auckland": 8666, "pipe": 8667, "serie": 8668, "revealing": 8669, "ba": 8670, "##bel": 8671, "trevor": 8672, "mercy": 8673, "spectrum": 8674, "yang": 8675, "consist": 8676, "governing": 8677, "collaborated": 8678, "possessed": 8679, "epic": 8680, "comprises": 8681, "blew": 8682, "shane": 8683, "##ack": 8684, "lopez": 8685, "honored": 8686, "magical": 8687, "sacrifice": 8688, "judgment": 8689, "perceived": 8690, "hammer": 8691, "mtv": 8692, "baronet": 8693, "tune": 8694, "das": 8695, "missionary": 8696, "sheets": 8697, "350": 8698, "neutral": 8699, "oral": 8700, "threatening": 8701, "attractive": 8702, "shade": 8703, "aims": 8704, "seminary": 8705, "##master": 8706, "estates": 8707, "1856": 8708, "michel": 8709, "wounds": 8710, "refugees": 8711, "manufacturers": 8712, "##nic": 8713, "mercury": 8714, "syndrome": 8715, "porter": 8716, "##iya": 8717, "##din": 8718, "hamburg": 8719, "identification": 8720, "upstairs": 8721, "purse": 8722, "widened": 8723, "pause": 8724, "cared": 8725, "breathed": 8726, "affiliate": 8727, "santiago": 8728, "prevented": 8729, "celtic": 8730, "fisher": 8731, "125": 8732, "recruited": 8733, "byzantine": 8734, "reconstruction": 8735, "farther": 8736, "##mp": 8737, "diet": 8738, "sake": 8739, "au": 8740, "spite": 8741, "sensation": 8742, "##ert": 8743, "blank": 8744, "separation": 8745, "105": 8746, "##hon": 8747, "vladimir": 8748, "armies": 8749, "anime": 8750, "##lie": 8751, "accommodate": 8752, "orbit": 8753, "cult": 8754, "sofia": 8755, "archive": 8756, "##ify": 8757, "##box": 8758, "founders": 8759, "sustained": 8760, "disorder": 8761, "honours": 8762, "northeastern": 8763, "mia": 8764, "crops": 8765, "violet": 8766, "threats": 8767, "blanket": 8768, "fires": 8769, "canton": 8770, "followers": 8771, "southwestern": 8772, "prototype": 8773, "voyage": 8774, "assignment": 8775, "altered": 8776, "moderate": 8777, "protocol": 8778, "pistol": 8779, "##eo": 8780, "questioned": 8781, "brass": 8782, "lifting": 8783, "1852": 8784, "math": 8785, "authored": 8786, "##ual": 8787, "doug": 8788, "dimensional": 8789, "dynamic": 8790, "##san": 8791, "1851": 8792, "pronounced": 8793, "grateful": 8794, "quest": 8795, "uncomfortable": 8796, "boom": 8797, "presidency": 8798, "stevens": 8799, "relating": 8800, "politicians": 8801, "chen": 8802, "barrier": 8803, "quinn": 8804, "diana": 8805, "mosque": 8806, "tribal": 8807, "cheese": 8808, "palmer": 8809, "portions": 8810, "sometime": 8811, "chester": 8812, "treasure": 8813, "wu": 8814, "bend": 8815, "download": 8816, "millions": 8817, "reforms": 8818, "registration": 8819, "##osa": 8820, "consequently": 8821, "monitoring": 8822, "ate": 8823, "preliminary": 8824, "brandon": 8825, "invented": 8826, "ps": 8827, "eaten": 8828, "exterior": 8829, "intervention": 8830, "ports": 8831, "documented": 8832, "log": 8833, "displays": 8834, "lecture": 8835, "sally": 8836, "favourite": 8837, "##itz": 8838, "vermont": 8839, "lo": 8840, "invisible": 8841, "isle": 8842, "breed": 8843, "##ator": 8844, "journalists": 8845, "relay": 8846, "speaks": 8847, "backward": 8848, "explore": 8849, "midfielder": 8850, "actively": 8851, "stefan": 8852, "procedures": 8853, "cannon": 8854, "blond": 8855, "kenneth": 8856, "centered": 8857, "servants": 8858, "chains": 8859, "libraries": 8860, "malcolm": 8861, "essex": 8862, "henri": 8863, "slavery": 8864, "##hal": 8865, "facts": 8866, "fairy": 8867, "coached": 8868, "cassie": 8869, "cats": 8870, "washed": 8871, "cop": 8872, "##fi": 8873, "announcement": 8874, "item": 8875, "2000s": 8876, "vinyl": 8877, "activated": 8878, "marco": 8879, "frontier": 8880, "growled": 8881, "curriculum": 8882, "##das": 8883, "loyal": 8884, "accomplished": 8885, "leslie": 8886, "ritual": 8887, "kenny": 8888, "##00": 8889, "vii": 8890, "napoleon": 8891, "hollow": 8892, "hybrid": 8893, "jungle": 8894, "stationed": 8895, "friedrich": 8896, "counted": 8897, "##ulated": 8898, "platinum": 8899, "theatrical": 8900, "seated": 8901, "col": 8902, "rubber": 8903, "glen": 8904, "1840": 8905, "diversity": 8906, "healing": 8907, "extends": 8908, "id": 8909, "provisions": 8910, "administrator": 8911, "columbus": 8912, "##oe": 8913, "tributary": 8914, "te": 8915, "assured": 8916, "org": 8917, "##uous": 8918, "prestigious": 8919, "examined": 8920, "lectures": 8921, "grammy": 8922, "ronald": 8923, "associations": 8924, "bailey": 8925, "allan": 8926, "essays": 8927, "flute": 8928, "believing": 8929, "consultant": 8930, "proceedings": 8931, "travelling": 8932, "1853": 8933, "kit": 8934, "kerala": 8935, "yugoslavia": 8936, "buddy": 8937, "methodist": 8938, "##ith": 8939, "burial": 8940, "centres": 8941, "batman": 8942, "##nda": 8943, "discontinued": 8944, "bo": 8945, "dock": 8946, "stockholm": 8947, "lungs": 8948, "severely": 8949, "##nk": 8950, "citing": 8951, "manga": 8952, "##ugh": 8953, "steal": 8954, "mumbai": 8955, "iraqi": 8956, "robot": 8957, "celebrity": 8958, "bride": 8959, "broadcasts": 8960, "abolished": 8961, "pot": 8962, "joel": 8963, "overhead": 8964, "franz": 8965, "packed": 8966, "reconnaissance": 8967, "johann": 8968, "acknowledged": 8969, "introduce": 8970, "handled": 8971, "doctorate": 8972, "developments": 8973, "drinks": 8974, "alley": 8975, "palestine": 8976, "##nis": 8977, "##aki": 8978, "proceeded": 8979, "recover": 8980, "bradley": 8981, "grain": 8982, "patch": 8983, "afford": 8984, "infection": 8985, "nationalist": 8986, "legendary": 8987, "##ath": 8988, "interchange": 8989, "virtually": 8990, "gen": 8991, "gravity": 8992, "exploration": 8993, "amber": 8994, "vital": 8995, "wishes": 8996, "powell": 8997, "doctrine": 8998, "elbow": 8999, "screenplay": 9000, "##bird": 9001, "contribute": 9002, "indonesian": 9003, "pet": 9004, "creates": 9005, "##com": 9006, "enzyme": 9007, "kylie": 9008, "discipline": 9009, "drops": 9010, "manila": 9011, "hunger": 9012, "##ien": 9013, "layers": 9014, "suffer": 9015, "fever": 9016, "bits": 9017, "monica": 9018, "keyboard": 9019, "manages": 9020, "##hood": 9021, "searched": 9022, "appeals": 9023, "##bad": 9024, "testament": 9025, "grande": 9026, "reid": 9027, "##war": 9028, "beliefs": 9029, "congo": 9030, "##ification": 9031, "##dia": 9032, "si": 9033, "requiring": 9034, "##via": 9035, "casey": 9036, "1849": 9037, "regret": 9038, "streak": 9039, "rape": 9040, "depends": 9041, "syrian": 9042, "sprint": 9043, "pound": 9044, "tourists": 9045, "upcoming": 9046, "pub": 9047, "##xi": 9048, "tense": 9049, "##els": 9050, "practiced": 9051, "echo": 9052, "nationwide": 9053, "guild": 9054, "motorcycle": 9055, "liz": 9056, "##zar": 9057, "chiefs": 9058, "desired": 9059, "elena": 9060, "bye": 9061, "precious": 9062, "absorbed": 9063, "relatives": 9064, "booth": 9065, "pianist": 9066, "##mal": 9067, "citizenship": 9068, "exhausted": 9069, "wilhelm": 9070, "##ceae": 9071, "##hed": 9072, "noting": 9073, "quarterback": 9074, "urge": 9075, "hectares": 9076, "##gue": 9077, "ace": 9078, "holly": 9079, "##tal": 9080, "blonde": 9081, "davies": 9082, "parked": 9083, "sustainable": 9084, "stepping": 9085, "twentieth": 9086, "airfield": 9087, "galaxy": 9088, "nest": 9089, "chip": 9090, "##nell": 9091, "tan": 9092, "shaft": 9093, "paulo": 9094, "requirement": 9095, "##zy": 9096, "paradise": 9097, "tobacco": 9098, "trans": 9099, "renewed": 9100, "vietnamese": 9101, "##cker": 9102, "##ju": 9103, "suggesting": 9104, "catching": 9105, "holmes": 9106, "enjoying": 9107, "md": 9108, "trips": 9109, "colt": 9110, "holder": 9111, "butterfly": 9112, "nerve": 9113, "reformed": 9114, "cherry": 9115, "bowling": 9116, "trailer": 9117, "carriage": 9118, "goodbye": 9119, "appreciate": 9120, "toy": 9121, "joshua": 9122, "interactive": 9123, "enabled": 9124, "involve": 9125, "##kan": 9126, "collar": 9127, "determination": 9128, "bunch": 9129, "facebook": 9130, "recall": 9131, "shorts": 9132, "superintendent": 9133, "episcopal": 9134, "frustration": 9135, "giovanni": 9136, "nineteenth": 9137, "laser": 9138, "privately": 9139, "array": 9140, "circulation": 9141, "##ovic": 9142, "armstrong": 9143, "deals": 9144, "painful": 9145, "permit": 9146, "discrimination": 9147, "##wi": 9148, "aires": 9149, "retiring": 9150, "cottage": 9151, "ni": 9152, "##sta": 9153, "horizon": 9154, "ellen": 9155, "jamaica": 9156, "ripped": 9157, "fernando": 9158, "chapters": 9159, "playstation": 9160, "patron": 9161, "lecturer": 9162, "navigation": 9163, "behaviour": 9164, "genes": 9165, "georgian": 9166, "export": 9167, "solomon": 9168, "rivals": 9169, "swift": 9170, "seventeen": 9171, "rodriguez": 9172, "princeton": 9173, "independently": 9174, "sox": 9175, "1847": 9176, "arguing": 9177, "entity": 9178, "casting": 9179, "hank": 9180, "criteria": 9181, "oakland": 9182, "geographic": 9183, "milwaukee": 9184, "reflection": 9185, "expanding": 9186, "conquest": 9187, "dubbed": 9188, "##tv": 9189, "halt": 9190, "brave": 9191, "brunswick": 9192, "doi": 9193, "arched": 9194, "curtis": 9195, "divorced": 9196, "predominantly": 9197, "somerset": 9198, "streams": 9199, "ugly": 9200, "zoo": 9201, "horrible": 9202, "curved": 9203, "buenos": 9204, "fierce": 9205, "dictionary": 9206, "vector": 9207, "theological": 9208, "unions": 9209, "handful": 9210, "stability": 9211, "chan": 9212, "punjab": 9213, "segments": 9214, "##lly": 9215, "altar": 9216, "ignoring": 9217, "gesture": 9218, "monsters": 9219, "pastor": 9220, "##stone": 9221, "thighs": 9222, "unexpected": 9223, "operators": 9224, "abruptly": 9225, "coin": 9226, "compiled": 9227, "associates": 9228, "improving": 9229, "migration": 9230, "pin": 9231, "##ose": 9232, "compact": 9233, "collegiate": 9234, "reserved": 9235, "##urs": 9236, "quarterfinals": 9237, "roster": 9238, "restore": 9239, "assembled": 9240, "hurry": 9241, "oval": 9242, "##cies": 9243, "1846": 9244, "flags": 9245, "martha": 9246, "##del": 9247, "victories": 9248, "sharply": 9249, "##rated": 9250, "argues": 9251, "deadly": 9252, "neo": 9253, "drawings": 9254, "symbols": 9255, "performer": 9256, "##iel": 9257, "griffin": 9258, "restrictions": 9259, "editing": 9260, "andrews": 9261, "java": 9262, "journals": 9263, "arabia": 9264, "compositions": 9265, "dee": 9266, "pierce": 9267, "removing": 9268, "hindi": 9269, "casino": 9270, "runway": 9271, "civilians": 9272, "minds": 9273, "nasa": 9274, "hotels": 9275, "##zation": 9276, "refuge": 9277, "rent": 9278, "retain": 9279, "potentially": 9280, "conferences": 9281, "suburban": 9282, "conducting": 9283, "##tto": 9284, "##tions": 9285, "##tle": 9286, "descended": 9287, "massacre": 9288, "##cal": 9289, "ammunition": 9290, "terrain": 9291, "fork": 9292, "souls": 9293, "counts": 9294, "chelsea": 9295, "durham": 9296, "drives": 9297, "cab": 9298, "##bank": 9299, "perth": 9300, "realizing": 9301, "palestinian": 9302, "finn": 9303, "simpson": 9304, "##dal": 9305, "betty": 9306, "##ule": 9307, "moreover": 9308, "particles": 9309, "cardinals": 9310, "tent": 9311, "evaluation": 9312, "extraordinary": 9313, "##oid": 9314, "inscription": 9315, "##works": 9316, "wednesday": 9317, "chloe": 9318, "maintains": 9319, "panels": 9320, "ashley": 9321, "trucks": 9322, "##nation": 9323, "cluster": 9324, "sunlight": 9325, "strikes": 9326, "zhang": 9327, "##wing": 9328, "dialect": 9329, "canon": 9330, "##ap": 9331, "tucked": 9332, "##ws": 9333, "collecting": 9334, "##mas": 9335, "##can": 9336, "##sville": 9337, "maker": 9338, "quoted": 9339, "evan": 9340, "franco": 9341, "aria": 9342, "buying": 9343, "cleaning": 9344, "eva": 9345, "closet": 9346, "provision": 9347, "apollo": 9348, "clinic": 9349, "rat": 9350, "##ez": 9351, "necessarily": 9352, "ac": 9353, "##gle": 9354, "##ising": 9355, "venues": 9356, "flipped": 9357, "cent": 9358, "spreading": 9359, "trustees": 9360, "checking": 9361, "authorized": 9362, "##sco": 9363, "disappointed": 9364, "##ado": 9365, "notion": 9366, "duration": 9367, "trumpet": 9368, "hesitated": 9369, "topped": 9370, "brussels": 9371, "rolls": 9372, "theoretical": 9373, "hint": 9374, "define": 9375, "aggressive": 9376, "repeat": 9377, "wash": 9378, "peaceful": 9379, "optical": 9380, "width": 9381, "allegedly": 9382, "mcdonald": 9383, "strict": 9384, "copyright": 9385, "##illa": 9386, "investors": 9387, "mar": 9388, "jam": 9389, "witnesses": 9390, "sounding": 9391, "miranda": 9392, "michelle": 9393, "privacy": 9394, "hugo": 9395, "harmony": 9396, "##pp": 9397, "valid": 9398, "lynn": 9399, "glared": 9400, "nina": 9401, "102": 9402, "headquartered": 9403, "diving": 9404, "boarding": 9405, "gibson": 9406, "##ncy": 9407, "albanian": 9408, "marsh": 9409, "routine": 9410, "dealt": 9411, "enhanced": 9412, "er": 9413, "intelligent": 9414, "substance": 9415, "targeted": 9416, "enlisted": 9417, "discovers": 9418, "spinning": 9419, "observations": 9420, "pissed": 9421, "smoking": 9422, "rebecca": 9423, "capitol": 9424, "visa": 9425, "varied": 9426, "costume": 9427, "seemingly": 9428, "indies": 9429, "compensation": 9430, "surgeon": 9431, "thursday": 9432, "arsenal": 9433, "westminster": 9434, "suburbs": 9435, "rid": 9436, "anglican": 9437, "##ridge": 9438, "knots": 9439, "foods": 9440, "alumni": 9441, "lighter": 9442, "fraser": 9443, "whoever": 9444, "portal": 9445, "scandal": 9446, "##ray": 9447, "gavin": 9448, "advised": 9449, "instructor": 9450, "flooding": 9451, "terrorist": 9452, "##ale": 9453, "teenage": 9454, "interim": 9455, "senses": 9456, "duck": 9457, "teen": 9458, "thesis": 9459, "abby": 9460, "eager": 9461, "overcome": 9462, "##ile": 9463, "newport": 9464, "glenn": 9465, "rises": 9466, "shame": 9467, "##cc": 9468, "prompted": 9469, "priority": 9470, "forgot": 9471, "bomber": 9472, "nicolas": 9473, "protective": 9474, "360": 9475, "cartoon": 9476, "katherine": 9477, "breeze": 9478, "lonely": 9479, "trusted": 9480, "henderson": 9481, "richardson": 9482, "relax": 9483, "banner": 9484, "candy": 9485, "palms": 9486, "remarkable": 9487, "##rio": 9488, "legends": 9489, "cricketer": 9490, "essay": 9491, "ordained": 9492, "edmund": 9493, "rifles": 9494, "trigger": 9495, "##uri": 9496, "##away": 9497, "sail": 9498, "alert": 9499, "1830": 9500, "audiences": 9501, "penn": 9502, "sussex": 9503, "siblings": 9504, "pursued": 9505, "indianapolis": 9506, "resist": 9507, "rosa": 9508, "consequence": 9509, "succeed": 9510, "avoided": 9511, "1845": 9512, "##ulation": 9513, "inland": 9514, "##tie": 9515, "##nna": 9516, "counsel": 9517, "profession": 9518, "chronicle": 9519, "hurried": 9520, "##una": 9521, "eyebrow": 9522, "eventual": 9523, "bleeding": 9524, "innovative": 9525, "cure": 9526, "##dom": 9527, "committees": 9528, "accounting": 9529, "con": 9530, "scope": 9531, "hardy": 9532, "heather": 9533, "tenor": 9534, "gut": 9535, "herald": 9536, "codes": 9537, "tore": 9538, "scales": 9539, "wagon": 9540, "##oo": 9541, "luxury": 9542, "tin": 9543, "prefer": 9544, "fountain": 9545, "triangle": 9546, "bonds": 9547, "darling": 9548, "convoy": 9549, "dried": 9550, "traced": 9551, "beings": 9552, "troy": 9553, "accidentally": 9554, "slam": 9555, "findings": 9556, "smelled": 9557, "joey": 9558, "lawyers": 9559, "outcome": 9560, "steep": 9561, "bosnia": 9562, "configuration": 9563, "shifting": 9564, "toll": 9565, "brook": 9566, "performers": 9567, "lobby": 9568, "philosophical": 9569, "construct": 9570, "shrine": 9571, "aggregate": 9572, "boot": 9573, "cox": 9574, "phenomenon": 9575, "savage": 9576, "insane": 9577, "solely": 9578, "reynolds": 9579, "lifestyle": 9580, "##ima": 9581, "nationally": 9582, "holdings": 9583, "consideration": 9584, "enable": 9585, "edgar": 9586, "mo": 9587, "mama": 9588, "##tein": 9589, "fights": 9590, "relegation": 9591, "chances": 9592, "atomic": 9593, "hub": 9594, "conjunction": 9595, "awkward": 9596, "reactions": 9597, "currency": 9598, "finale": 9599, "kumar": 9600, "underwent": 9601, "steering": 9602, "elaborate": 9603, "gifts": 9604, "comprising": 9605, "melissa": 9606, "veins": 9607, "reasonable": 9608, "sunshine": 9609, "chi": 9610, "solve": 9611, "trails": 9612, "inhabited": 9613, "elimination": 9614, "ethics": 9615, "huh": 9616, "ana": 9617, "molly": 9618, "consent": 9619, "apartments": 9620, "layout": 9621, "marines": 9622, "##ces": 9623, "hunters": 9624, "bulk": 9625, "##oma": 9626, "hometown": 9627, "##wall": 9628, "##mont": 9629, "cracked": 9630, "reads": 9631, "neighbouring": 9632, "withdrawn": 9633, "admission": 9634, "wingspan": 9635, "damned": 9636, "anthology": 9637, "lancashire": 9638, "brands": 9639, "batting": 9640, "forgive": 9641, "cuban": 9642, "awful": 9643, "##lyn": 9644, "104": 9645, "dimensions": 9646, "imagination": 9647, "##ade": 9648, "dante": 9649, "##ship": 9650, "tracking": 9651, "desperately": 9652, "goalkeeper": 9653, "##yne": 9654, "groaned": 9655, "workshops": 9656, "confident": 9657, "burton": 9658, "gerald": 9659, "milton": 9660, "circus": 9661, "uncertain": 9662, "slope": 9663, "copenhagen": 9664, "sophia": 9665, "fog": 9666, "philosopher": 9667, "portraits": 9668, "accent": 9669, "cycling": 9670, "varying": 9671, "gripped": 9672, "larvae": 9673, "garrett": 9674, "specified": 9675, "scotia": 9676, "mature": 9677, "luther": 9678, "kurt": 9679, "rap": 9680, "##kes": 9681, "aerial": 9682, "750": 9683, "ferdinand": 9684, "heated": 9685, "es": 9686, "transported": 9687, "##shan": 9688, "safely": 9689, "nonetheless": 9690, "##orn": 9691, "##gal": 9692, "motors": 9693, "demanding": 9694, "##sburg": 9695, "startled": 9696, "##brook": 9697, "ally": 9698, "generate": 9699, "caps": 9700, "ghana": 9701, "stained": 9702, "demo": 9703, "mentions": 9704, "beds": 9705, "ap": 9706, "afterward": 9707, "diary": 9708, "##bling": 9709, "utility": 9710, "##iro": 9711, "richards": 9712, "1837": 9713, "conspiracy": 9714, "conscious": 9715, "shining": 9716, "footsteps": 9717, "observer": 9718, "cyprus": 9719, "urged": 9720, "loyalty": 9721, "developer": 9722, "probability": 9723, "olive": 9724, "upgraded": 9725, "gym": 9726, "miracle": 9727, "insects": 9728, "graves": 9729, "1844": 9730, "ourselves": 9731, "hydrogen": 9732, "amazon": 9733, "katie": 9734, "tickets": 9735, "poets": 9736, "##pm": 9737, "planes": 9738, "##pan": 9739, "prevention": 9740, "witnessed": 9741, "dense": 9742, "jin": 9743, "randy": 9744, "tang": 9745, "warehouse": 9746, "monroe": 9747, "bang": 9748, "archived": 9749, "elderly": 9750, "investigations": 9751, "alec": 9752, "granite": 9753, "mineral": 9754, "conflicts": 9755, "controlling": 9756, "aboriginal": 9757, "carlo": 9758, "##zu": 9759, "mechanics": 9760, "stan": 9761, "stark": 9762, "rhode": 9763, "skirt": 9764, "est": 9765, "##berry": 9766, "bombs": 9767, "respected": 9768, "##horn": 9769, "imposed": 9770, "limestone": 9771, "deny": 9772, "nominee": 9773, "memphis": 9774, "grabbing": 9775, "disabled": 9776, "##als": 9777, "amusement": 9778, "aa": 9779, "frankfurt": 9780, "corn": 9781, "referendum": 9782, "varies": 9783, "slowed": 9784, "disk": 9785, "firms": 9786, "unconscious": 9787, "incredible": 9788, "clue": 9789, "sue": 9790, "##zhou": 9791, "twist": 9792, "##cio": 9793, "joins": 9794, "idaho": 9795, "chad": 9796, "developers": 9797, "computing": 9798, "destroyer": 9799, "103": 9800, "mortal": 9801, "tucker": 9802, "kingston": 9803, "choices": 9804, "yu": 9805, "carson": 9806, "1800": 9807, "os": 9808, "whitney": 9809, "geneva": 9810, "pretend": 9811, "dimension": 9812, "staged": 9813, "plateau": 9814, "maya": 9815, "##une": 9816, "freestyle": 9817, "##bc": 9818, "rovers": 9819, "hiv": 9820, "##ids": 9821, "tristan": 9822, "classroom": 9823, "prospect": 9824, "##hus": 9825, "honestly": 9826, "diploma": 9827, "lied": 9828, "thermal": 9829, "auxiliary": 9830, "feast": 9831, "unlikely": 9832, "iata": 9833, "##tel": 9834, "morocco": 9835, "pounding": 9836, "treasury": 9837, "lithuania": 9838, "considerably": 9839, "1841": 9840, "dish": 9841, "1812": 9842, "geological": 9843, "matching": 9844, "stumbled": 9845, "destroying": 9846, "marched": 9847, "brien": 9848, "advances": 9849, "cake": 9850, "nicole": 9851, "belle": 9852, "settling": 9853, "measuring": 9854, "directing": 9855, "##mie": 9856, "tuesday": 9857, "bassist": 9858, "capabilities": 9859, "stunned": 9860, "fraud": 9861, "torpedo": 9862, "##list": 9863, "##phone": 9864, "anton": 9865, "wisdom": 9866, "surveillance": 9867, "ruined": 9868, "##ulate": 9869, "lawsuit": 9870, "healthcare": 9871, "theorem": 9872, "halls": 9873, "trend": 9874, "aka": 9875, "horizontal": 9876, "dozens": 9877, "acquire": 9878, "lasting": 9879, "swim": 9880, "hawk": 9881, "gorgeous": 9882, "fees": 9883, "vicinity": 9884, "decrease": 9885, "adoption": 9886, "tactics": 9887, "##ography": 9888, "pakistani": 9889, "##ole": 9890, "draws": 9891, "##hall": 9892, "willie": 9893, "burke": 9894, "heath": 9895, "algorithm": 9896, "integral": 9897, "powder": 9898, "elliott": 9899, "brigadier": 9900, "jackie": 9901, "tate": 9902, "varieties": 9903, "darker": 9904, "##cho": 9905, "lately": 9906, "cigarette": 9907, "specimens": 9908, "adds": 9909, "##ree": 9910, "##ensis": 9911, "##inger": 9912, "exploded": 9913, "finalist": 9914, "cia": 9915, "murders": 9916, "wilderness": 9917, "arguments": 9918, "nicknamed": 9919, "acceptance": 9920, "onwards": 9921, "manufacture": 9922, "robertson": 9923, "jets": 9924, "tampa": 9925, "enterprises": 9926, "blog": 9927, "loudly": 9928, "composers": 9929, "nominations": 9930, "1838": 9931, "ai": 9932, "malta": 9933, "inquiry": 9934, "automobile": 9935, "hosting": 9936, "viii": 9937, "rays": 9938, "tilted": 9939, "grief": 9940, "museums": 9941, "strategies": 9942, "furious": 9943, "euro": 9944, "equality": 9945, "cohen": 9946, "poison": 9947, "surrey": 9948, "wireless": 9949, "governed": 9950, "ridiculous": 9951, "moses": 9952, "##esh": 9953, "##room": 9954, "vanished": 9955, "##ito": 9956, "barnes": 9957, "attract": 9958, "morrison": 9959, "istanbul": 9960, "##iness": 9961, "absent": 9962, "rotation": 9963, "petition": 9964, "janet": 9965, "##logical": 9966, "satisfaction": 9967, "custody": 9968, "deliberately": 9969, "observatory": 9970, "comedian": 9971, "surfaces": 9972, "pinyin": 9973, "novelist": 9974, "strictly": 9975, "canterbury": 9976, "oslo": 9977, "monks": 9978, "embrace": 9979, "ibm": 9980, "jealous": 9981, "photograph": 9982, "continent": 9983, "dorothy": 9984, "marina": 9985, "doc": 9986, "excess": 9987, "holden": 9988, "allegations": 9989, "explaining": 9990, "stack": 9991, "avoiding": 9992, "lance": 9993, "storyline": 9994, "majesty": 9995, "poorly": 9996, "spike": 9997, "dos": 9998, "bradford": 9999, "raven": 10000, "travis": 10001, "classics": 10002, "proven": 10003, "voltage": 10004, "pillow": 10005, "fists": 10006, "butt": 10007, "1842": 10008, "interpreted": 10009, "##car": 10010, "1839": 10011, "gage": 10012, "telegraph": 10013, "lens": 10014, "promising": 10015, "expelled": 10016, "casual": 10017, "collector": 10018, "zones": 10019, "##min": 10020, "silly": 10021, "nintendo": 10022, "##kh": 10023, "##bra": 10024, "downstairs": 10025, "chef": 10026, "suspicious": 10027, "afl": 10028, "flies": 10029, "vacant": 10030, "uganda": 10031, "pregnancy": 10032, "condemned": 10033, "lutheran": 10034, "estimates": 10035, "cheap": 10036, "decree": 10037, "saxon": 10038, "proximity": 10039, "stripped": 10040, "idiot": 10041, "deposits": 10042, "contrary": 10043, "presenter": 10044, "magnus": 10045, "glacier": 10046, "im": 10047, "offense": 10048, "edwin": 10049, "##ori": 10050, "upright": 10051, "##long": 10052, "bolt": 10053, "##ois": 10054, "toss": 10055, "geographical": 10056, "##izes": 10057, "environments": 10058, "delicate": 10059, "marking": 10060, "abstract": 10061, "xavier": 10062, "nails": 10063, "windsor": 10064, "plantation": 10065, "occurring": 10066, "equity": 10067, "saskatchewan": 10068, "fears": 10069, "drifted": 10070, "sequences": 10071, "vegetation": 10072, "revolt": 10073, "##stic": 10074, "1843": 10075, "sooner": 10076, "fusion": 10077, "opposing": 10078, "nato": 10079, "skating": 10080, "1836": 10081, "secretly": 10082, "ruin": 10083, "lease": 10084, "##oc": 10085, "edit": 10086, "##nne": 10087, "flora": 10088, "anxiety": 10089, "ruby": 10090, "##ological": 10091, "##mia": 10092, "tel": 10093, "bout": 10094, "taxi": 10095, "emmy": 10096, "frost": 10097, "rainbow": 10098, "compounds": 10099, "foundations": 10100, "rainfall": 10101, "assassination": 10102, "nightmare": 10103, "dominican": 10104, "##win": 10105, "achievements": 10106, "deserve": 10107, "orlando": 10108, "intact": 10109, "armenia": 10110, "##nte": 10111, "calgary": 10112, "valentine": 10113, "106": 10114, "marion": 10115, "proclaimed": 10116, "theodore": 10117, "bells": 10118, "courtyard": 10119, "thigh": 10120, "gonzalez": 10121, "console": 10122, "troop": 10123, "minimal": 10124, "monte": 10125, "everyday": 10126, "##ence": 10127, "##if": 10128, "supporter": 10129, "terrorism": 10130, "buck": 10131, "openly": 10132, "presbyterian": 10133, "activists": 10134, "carpet": 10135, "##iers": 10136, "rubbing": 10137, "uprising": 10138, "##yi": 10139, "cute": 10140, "conceived": 10141, "legally": 10142, "##cht": 10143, "millennium": 10144, "cello": 10145, "velocity": 10146, "ji": 10147, "rescued": 10148, "cardiff": 10149, "1835": 10150, "rex": 10151, "concentrate": 10152, "senators": 10153, "beard": 10154, "rendered": 10155, "glowing": 10156, "battalions": 10157, "scouts": 10158, "competitors": 10159, "sculptor": 10160, "catalogue": 10161, "arctic": 10162, "ion": 10163, "raja": 10164, "bicycle": 10165, "wow": 10166, "glancing": 10167, "lawn": 10168, "##woman": 10169, "gentleman": 10170, "lighthouse": 10171, "publish": 10172, "predicted": 10173, "calculated": 10174, "##val": 10175, "variants": 10176, "##gne": 10177, "strain": 10178, "##ui": 10179, "winston": 10180, "deceased": 10181, "##nus": 10182, "touchdowns": 10183, "brady": 10184, "caleb": 10185, "sinking": 10186, "echoed": 10187, "crush": 10188, "hon": 10189, "blessed": 10190, "protagonist": 10191, "hayes": 10192, "endangered": 10193, "magnitude": 10194, "editors": 10195, "##tine": 10196, "estimate": 10197, "responsibilities": 10198, "##mel": 10199, "backup": 10200, "laying": 10201, "consumed": 10202, "sealed": 10203, "zurich": 10204, "lovers": 10205, "frustrated": 10206, "##eau": 10207, "ahmed": 10208, "kicking": 10209, "mit": 10210, "treasurer": 10211, "1832": 10212, "biblical": 10213, "refuse": 10214, "terrified": 10215, "pump": 10216, "agrees": 10217, "genuine": 10218, "imprisonment": 10219, "refuses": 10220, "plymouth": 10221, "##hen": 10222, "lou": 10223, "##nen": 10224, "tara": 10225, "trembling": 10226, "antarctic": 10227, "ton": 10228, "learns": 10229, "##tas": 10230, "crap": 10231, "crucial": 10232, "faction": 10233, "atop": 10234, "##borough": 10235, "wrap": 10236, "lancaster": 10237, "odds": 10238, "hopkins": 10239, "erik": 10240, "lyon": 10241, "##eon": 10242, "bros": 10243, "##ode": 10244, "snap": 10245, "locality": 10246, "tips": 10247, "empress": 10248, "crowned": 10249, "cal": 10250, "acclaimed": 10251, "chuckled": 10252, "##ory": 10253, "clara": 10254, "sends": 10255, "mild": 10256, "towel": 10257, "##fl": 10258, "##day": 10259, "##а": 10260, "wishing": 10261, "assuming": 10262, "interviewed": 10263, "##bal": 10264, "##die": 10265, "interactions": 10266, "eden": 10267, "cups": 10268, "helena": 10269, "##lf": 10270, "indie": 10271, "beck": 10272, "##fire": 10273, "batteries": 10274, "filipino": 10275, "wizard": 10276, "parted": 10277, "##lam": 10278, "traces": 10279, "##born": 10280, "rows": 10281, "idol": 10282, "albany": 10283, "delegates": 10284, "##ees": 10285, "##sar": 10286, "discussions": 10287, "##ex": 10288, "notre": 10289, "instructed": 10290, "belgrade": 10291, "highways": 10292, "suggestion": 10293, "lauren": 10294, "possess": 10295, "orientation": 10296, "alexandria": 10297, "abdul": 10298, "beats": 10299, "salary": 10300, "reunion": 10301, "ludwig": 10302, "alright": 10303, "wagner": 10304, "intimate": 10305, "pockets": 10306, "slovenia": 10307, "hugged": 10308, "brighton": 10309, "merchants": 10310, "cruel": 10311, "stole": 10312, "trek": 10313, "slopes": 10314, "repairs": 10315, "enrollment": 10316, "politically": 10317, "underlying": 10318, "promotional": 10319, "counting": 10320, "boeing": 10321, "##bb": 10322, "isabella": 10323, "naming": 10324, "##и": 10325, "keen": 10326, "bacteria": 10327, "listing": 10328, "separately": 10329, "belfast": 10330, "ussr": 10331, "450": 10332, "lithuanian": 10333, "anybody": 10334, "ribs": 10335, "sphere": 10336, "martinez": 10337, "cock": 10338, "embarrassed": 10339, "proposals": 10340, "fragments": 10341, "nationals": 10342, "##fs": 10343, "##wski": 10344, "premises": 10345, "fin": 10346, "1500": 10347, "alpine": 10348, "matched": 10349, "freely": 10350, "bounded": 10351, "jace": 10352, "sleeve": 10353, "##af": 10354, "gaming": 10355, "pier": 10356, "populated": 10357, "evident": 10358, "##like": 10359, "frances": 10360, "flooded": 10361, "##dle": 10362, "frightened": 10363, "pour": 10364, "trainer": 10365, "framed": 10366, "visitor": 10367, "challenging": 10368, "pig": 10369, "wickets": 10370, "##fold": 10371, "infected": 10372, "email": 10373, "##pes": 10374, "arose": 10375, "##aw": 10376, "reward": 10377, "ecuador": 10378, "oblast": 10379, "vale": 10380, "ch": 10381, "shuttle": 10382, "##usa": 10383, "bach": 10384, "rankings": 10385, "forbidden": 10386, "cornwall": 10387, "accordance": 10388, "salem": 10389, "consumers": 10390, "bruno": 10391, "fantastic": 10392, "toes": 10393, "machinery": 10394, "resolved": 10395, "julius": 10396, "remembering": 10397, "propaganda": 10398, "iceland": 10399, "bombardment": 10400, "tide": 10401, "contacts": 10402, "wives": 10403, "##rah": 10404, "concerto": 10405, "macdonald": 10406, "albania": 10407, "implement": 10408, "daisy": 10409, "tapped": 10410, "sudan": 10411, "helmet": 10412, "angela": 10413, "mistress": 10414, "##lic": 10415, "crop": 10416, "sunk": 10417, "finest": 10418, "##craft": 10419, "hostile": 10420, "##ute": 10421, "##tsu": 10422, "boxer": 10423, "fr": 10424, "paths": 10425, "adjusted": 10426, "habit": 10427, "ballot": 10428, "supervision": 10429, "soprano": 10430, "##zen": 10431, "bullets": 10432, "wicked": 10433, "sunset": 10434, "regiments": 10435, "disappear": 10436, "lamp": 10437, "performs": 10438, "app": 10439, "##gia": 10440, "##oa": 10441, "rabbit": 10442, "digging": 10443, "incidents": 10444, "entries": 10445, "##cion": 10446, "dishes": 10447, "##oi": 10448, "introducing": 10449, "##ati": 10450, "##fied": 10451, "freshman": 10452, "slot": 10453, "jill": 10454, "tackles": 10455, "baroque": 10456, "backs": 10457, "##iest": 10458, "lone": 10459, "sponsor": 10460, "destiny": 10461, "altogether": 10462, "convert": 10463, "##aro": 10464, "consensus": 10465, "shapes": 10466, "demonstration": 10467, "basically": 10468, "feminist": 10469, "auction": 10470, "artifacts": 10471, "##bing": 10472, "strongest": 10473, "twitter": 10474, "halifax": 10475, "2019": 10476, "allmusic": 10477, "mighty": 10478, "smallest": 10479, "precise": 10480, "alexandra": 10481, "viola": 10482, "##los": 10483, "##ille": 10484, "manuscripts": 10485, "##illo": 10486, "dancers": 10487, "ari": 10488, "managers": 10489, "monuments": 10490, "blades": 10491, "barracks": 10492, "springfield": 10493, "maiden": 10494, "consolidated": 10495, "electron": 10496, "##end": 10497, "berry": 10498, "airing": 10499, "wheat": 10500, "nobel": 10501, "inclusion": 10502, "blair": 10503, "payments": 10504, "geography": 10505, "bee": 10506, "cc": 10507, "eleanor": 10508, "react": 10509, "##hurst": 10510, "afc": 10511, "manitoba": 10512, "##yu": 10513, "su": 10514, "lineup": 10515, "fitness": 10516, "recreational": 10517, "investments": 10518, "airborne": 10519, "disappointment": 10520, "##dis": 10521, "edmonton": 10522, "viewing": 10523, "##row": 10524, "renovation": 10525, "##cast": 10526, "infant": 10527, "bankruptcy": 10528, "roses": 10529, "aftermath": 10530, "pavilion": 10531, "##yer": 10532, "carpenter": 10533, "withdrawal": 10534, "ladder": 10535, "##hy": 10536, "discussing": 10537, "popped": 10538, "reliable": 10539, "agreements": 10540, "rochester": 10541, "##abad": 10542, "curves": 10543, "bombers": 10544, "220": 10545, "rao": 10546, "reverend": 10547, "decreased": 10548, "choosing": 10549, "107": 10550, "stiff": 10551, "consulting": 10552, "naples": 10553, "crawford": 10554, "tracy": 10555, "ka": 10556, "ribbon": 10557, "cops": 10558, "##lee": 10559, "crushed": 10560, "deciding": 10561, "unified": 10562, "teenager": 10563, "accepting": 10564, "flagship": 10565, "explorer": 10566, "poles": 10567, "sanchez": 10568, "inspection": 10569, "revived": 10570, "skilled": 10571, "induced": 10572, "exchanged": 10573, "flee": 10574, "locals": 10575, "tragedy": 10576, "swallow": 10577, "loading": 10578, "hanna": 10579, "demonstrate": 10580, "##ela": 10581, "salvador": 10582, "flown": 10583, "contestants": 10584, "civilization": 10585, "##ines": 10586, "wanna": 10587, "rhodes": 10588, "fletcher": 10589, "hector": 10590, "knocking": 10591, "considers": 10592, "##ough": 10593, "nash": 10594, "mechanisms": 10595, "sensed": 10596, "mentally": 10597, "walt": 10598, "unclear": 10599, "##eus": 10600, "renovated": 10601, "madame": 10602, "##cks": 10603, "crews": 10604, "governmental": 10605, "##hin": 10606, "undertaken": 10607, "monkey": 10608, "##ben": 10609, "##ato": 10610, "fatal": 10611, "armored": 10612, "copa": 10613, "caves": 10614, "governance": 10615, "grasp": 10616, "perception": 10617, "certification": 10618, "froze": 10619, "damp": 10620, "tugged": 10621, "wyoming": 10622, "##rg": 10623, "##ero": 10624, "newman": 10625, "##lor": 10626, "nerves": 10627, "curiosity": 10628, "graph": 10629, "115": 10630, "##ami": 10631, "withdraw": 10632, "tunnels": 10633, "dull": 10634, "meredith": 10635, "moss": 10636, "exhibits": 10637, "neighbors": 10638, "communicate": 10639, "accuracy": 10640, "explored": 10641, "raiders": 10642, "republicans": 10643, "secular": 10644, "kat": 10645, "superman": 10646, "penny": 10647, "criticised": 10648, "##tch": 10649, "freed": 10650, "update": 10651, "conviction": 10652, "wade": 10653, "ham": 10654, "likewise": 10655, "delegation": 10656, "gotta": 10657, "doll": 10658, "promises": 10659, "technological": 10660, "myth": 10661, "nationality": 10662, "resolve": 10663, "convent": 10664, "##mark": 10665, "sharon": 10666, "dig": 10667, "sip": 10668, "coordinator": 10669, "entrepreneur": 10670, "fold": 10671, "##dine": 10672, "capability": 10673, "councillor": 10674, "synonym": 10675, "blown": 10676, "swan": 10677, "cursed": 10678, "1815": 10679, "jonas": 10680, "haired": 10681, "sofa": 10682, "canvas": 10683, "keeper": 10684, "rivalry": 10685, "##hart": 10686, "rapper": 10687, "speedway": 10688, "swords": 10689, "postal": 10690, "maxwell": 10691, "estonia": 10692, "potter": 10693, "recurring": 10694, "##nn": 10695, "##ave": 10696, "errors": 10697, "##oni": 10698, "cognitive": 10699, "1834": 10700, "##²": 10701, "claws": 10702, "nadu": 10703, "roberto": 10704, "bce": 10705, "wrestler": 10706, "ellie": 10707, "##ations": 10708, "infinite": 10709, "ink": 10710, "##tia": 10711, "presumably": 10712, "finite": 10713, "staircase": 10714, "108": 10715, "noel": 10716, "patricia": 10717, "nacional": 10718, "##cation": 10719, "chill": 10720, "eternal": 10721, "tu": 10722, "preventing": 10723, "prussia": 10724, "fossil": 10725, "limbs": 10726, "##logist": 10727, "ernst": 10728, "frog": 10729, "perez": 10730, "rene": 10731, "##ace": 10732, "pizza": 10733, "prussian": 10734, "##ios": 10735, "##vy": 10736, "molecules": 10737, "regulatory": 10738, "answering": 10739, "opinions": 10740, "sworn": 10741, "lengths": 10742, "supposedly": 10743, "hypothesis": 10744, "upward": 10745, "habitats": 10746, "seating": 10747, "ancestors": 10748, "drank": 10749, "yield": 10750, "hd": 10751, "synthesis": 10752, "researcher": 10753, "modest": 10754, "##var": 10755, "mothers": 10756, "peered": 10757, "voluntary": 10758, "homeland": 10759, "##the": 10760, "acclaim": 10761, "##igan": 10762, "static": 10763, "valve": 10764, "luxembourg": 10765, "alto": 10766, "carroll": 10767, "fe": 10768, "receptor": 10769, "norton": 10770, "ambulance": 10771, "##tian": 10772, "johnston": 10773, "catholics": 10774, "depicting": 10775, "jointly": 10776, "elephant": 10777, "gloria": 10778, "mentor": 10779, "badge": 10780, "ahmad": 10781, "distinguish": 10782, "remarked": 10783, "councils": 10784, "precisely": 10785, "allison": 10786, "advancing": 10787, "detection": 10788, "crowded": 10789, "##10": 10790, "cooperative": 10791, "ankle": 10792, "mercedes": 10793, "dagger": 10794, "surrendered": 10795, "pollution": 10796, "commit": 10797, "subway": 10798, "jeffrey": 10799, "lesson": 10800, "sculptures": 10801, "provider": 10802, "##fication": 10803, "membrane": 10804, "timothy": 10805, "rectangular": 10806, "fiscal": 10807, "heating": 10808, "teammate": 10809, "basket": 10810, "particle": 10811, "anonymous": 10812, "deployment": 10813, "##ple": 10814, "missiles": 10815, "courthouse": 10816, "proportion": 10817, "shoe": 10818, "sec": 10819, "##ller": 10820, "complaints": 10821, "forbes": 10822, "blacks": 10823, "abandon": 10824, "remind": 10825, "sizes": 10826, "overwhelming": 10827, "autobiography": 10828, "natalie": 10829, "##awa": 10830, "risks": 10831, "contestant": 10832, "countryside": 10833, "babies": 10834, "scorer": 10835, "invaded": 10836, "enclosed": 10837, "proceed": 10838, "hurling": 10839, "disorders": 10840, "##cu": 10841, "reflecting": 10842, "continuously": 10843, "cruiser": 10844, "graduates": 10845, "freeway": 10846, "investigated": 10847, "ore": 10848, "deserved": 10849, "maid": 10850, "blocking": 10851, "phillip": 10852, "jorge": 10853, "shakes": 10854, "dove": 10855, "mann": 10856, "variables": 10857, "lacked": 10858, "burden": 10859, "accompanying": 10860, "que": 10861, "consistently": 10862, "organizing": 10863, "provisional": 10864, "complained": 10865, "endless": 10866, "##rm": 10867, "tubes": 10868, "juice": 10869, "georges": 10870, "krishna": 10871, "mick": 10872, "labels": 10873, "thriller": 10874, "##uch": 10875, "laps": 10876, "arcade": 10877, "sage": 10878, "snail": 10879, "##table": 10880, "shannon": 10881, "fi": 10882, "laurence": 10883, "seoul": 10884, "vacation": 10885, "presenting": 10886, "hire": 10887, "churchill": 10888, "surprisingly": 10889, "prohibited": 10890, "savannah": 10891, "technically": 10892, "##oli": 10893, "170": 10894, "##lessly": 10895, "testimony": 10896, "suited": 10897, "speeds": 10898, "toys": 10899, "romans": 10900, "mlb": 10901, "flowering": 10902, "measurement": 10903, "talented": 10904, "kay": 10905, "settings": 10906, "charleston": 10907, "expectations": 10908, "shattered": 10909, "achieving": 10910, "triumph": 10911, "ceremonies": 10912, "portsmouth": 10913, "lanes": 10914, "mandatory": 10915, "loser": 10916, "stretching": 10917, "cologne": 10918, "realizes": 10919, "seventy": 10920, "cornell": 10921, "careers": 10922, "webb": 10923, "##ulating": 10924, "americas": 10925, "budapest": 10926, "ava": 10927, "suspicion": 10928, "##ison": 10929, "yo": 10930, "conrad": 10931, "##hai": 10932, "sterling": 10933, "jessie": 10934, "rector": 10935, "##az": 10936, "1831": 10937, "transform": 10938, "organize": 10939, "loans": 10940, "christine": 10941, "volcanic": 10942, "warrant": 10943, "slender": 10944, "summers": 10945, "subfamily": 10946, "newer": 10947, "danced": 10948, "dynamics": 10949, "rhine": 10950, "proceeds": 10951, "heinrich": 10952, "gastropod": 10953, "commands": 10954, "sings": 10955, "facilitate": 10956, "easter": 10957, "ra": 10958, "positioned": 10959, "responses": 10960, "expense": 10961, "fruits": 10962, "yanked": 10963, "imported": 10964, "25th": 10965, "velvet": 10966, "vic": 10967, "primitive": 10968, "tribune": 10969, "baldwin": 10970, "neighbourhood": 10971, "donna": 10972, "rip": 10973, "hay": 10974, "pr": 10975, "##uro": 10976, "1814": 10977, "espn": 10978, "welcomed": 10979, "##aria": 10980, "qualifier": 10981, "glare": 10982, "highland": 10983, "timing": 10984, "##cted": 10985, "shells": 10986, "eased": 10987, "geometry": 10988, "louder": 10989, "exciting": 10990, "slovakia": 10991, "##sion": 10992, "##iz": 10993, "##lot": 10994, "savings": 10995, "prairie": 10996, "##ques": 10997, "marching": 10998, "rafael": 10999, "tonnes": 11000, "##lled": 11001, "curtain": 11002, "preceding": 11003, "shy": 11004, "heal": 11005, "greene": 11006, "worthy": 11007, "##pot": 11008, "detachment": 11009, "bury": 11010, "sherman": 11011, "##eck": 11012, "reinforced": 11013, "seeks": 11014, "bottles": 11015, "contracted": 11016, "duchess": 11017, "outfit": 11018, "walsh": 11019, "##sc": 11020, "mickey": 11021, "##ase": 11022, "geoffrey": 11023, "archer": 11024, "squeeze": 11025, "dawson": 11026, "eliminate": 11027, "invention": 11028, "##enberg": 11029, "neal": 11030, "##eth": 11031, "stance": 11032, "dealer": 11033, "coral": 11034, "maple": 11035, "retire": 11036, "polo": 11037, "simplified": 11038, "##ht": 11039, "1833": 11040, "hid": 11041, "watts": 11042, "backwards": 11043, "jules": 11044, "##oke": 11045, "genesis": 11046, "mt": 11047, "frames": 11048, "rebounds": 11049, "burma": 11050, "woodland": 11051, "moist": 11052, "santos": 11053, "whispers": 11054, "drained": 11055, "subspecies": 11056, "##aa": 11057, "streaming": 11058, "ulster": 11059, "burnt": 11060, "correspondence": 11061, "maternal": 11062, "gerard": 11063, "denis": 11064, "stealing": 11065, "##load": 11066, "genius": 11067, "duchy": 11068, "##oria": 11069, "inaugurated": 11070, "momentum": 11071, "suits": 11072, "placement": 11073, "sovereign": 11074, "clause": 11075, "thames": 11076, "##hara": 11077, "confederation": 11078, "reservation": 11079, "sketch": 11080, "yankees": 11081, "lets": 11082, "rotten": 11083, "charm": 11084, "hal": 11085, "verses": 11086, "ultra": 11087, "commercially": 11088, "dot": 11089, "salon": 11090, "citation": 11091, "adopt": 11092, "winnipeg": 11093, "mist": 11094, "allocated": 11095, "cairo": 11096, "##boy": 11097, "jenkins": 11098, "interference": 11099, "objectives": 11100, "##wind": 11101, "1820": 11102, "portfolio": 11103, "armoured": 11104, "sectors": 11105, "##eh": 11106, "initiatives": 11107, "##world": 11108, "integrity": 11109, "exercises": 11110, "robe": 11111, "tap": 11112, "ab": 11113, "gazed": 11114, "##tones": 11115, "distracted": 11116, "rulers": 11117, "111": 11118, "favorable": 11119, "jerome": 11120, "tended": 11121, "cart": 11122, "factories": 11123, "##eri": 11124, "diplomat": 11125, "valued": 11126, "gravel": 11127, "charitable": 11128, "##try": 11129, "calvin": 11130, "exploring": 11131, "chang": 11132, "shepherd": 11133, "terrace": 11134, "pdf": 11135, "pupil": 11136, "##ural": 11137, "reflects": 11138, "ups": 11139, "##rch": 11140, "governors": 11141, "shelf": 11142, "depths": 11143, "##nberg": 11144, "trailed": 11145, "crest": 11146, "tackle": 11147, "##nian": 11148, "##ats": 11149, "hatred": 11150, "##kai": 11151, "clare": 11152, "makers": 11153, "ethiopia": 11154, "longtime": 11155, "detected": 11156, "embedded": 11157, "lacking": 11158, "slapped": 11159, "rely": 11160, "thomson": 11161, "anticipation": 11162, "iso": 11163, "morton": 11164, "successive": 11165, "agnes": 11166, "screenwriter": 11167, "straightened": 11168, "philippe": 11169, "playwright": 11170, "haunted": 11171, "licence": 11172, "iris": 11173, "intentions": 11174, "sutton": 11175, "112": 11176, "logical": 11177, "correctly": 11178, "##weight": 11179, "branded": 11180, "licked": 11181, "tipped": 11182, "silva": 11183, "ricky": 11184, "narrator": 11185, "requests": 11186, "##ents": 11187, "greeted": 11188, "supernatural": 11189, "cow": 11190, "##wald": 11191, "lung": 11192, "refusing": 11193, "employer": 11194, "strait": 11195, "gaelic": 11196, "liner": 11197, "##piece": 11198, "zoe": 11199, "sabha": 11200, "##mba": 11201, "driveway": 11202, "harvest": 11203, "prints": 11204, "bates": 11205, "reluctantly": 11206, "threshold": 11207, "algebra": 11208, "ira": 11209, "wherever": 11210, "coupled": 11211, "240": 11212, "assumption": 11213, "picks": 11214, "##air": 11215, "designers": 11216, "raids": 11217, "gentlemen": 11218, "##ean": 11219, "roller": 11220, "blowing": 11221, "leipzig": 11222, "locks": 11223, "screw": 11224, "dressing": 11225, "strand": 11226, "##lings": 11227, "scar": 11228, "dwarf": 11229, "depicts": 11230, "##nu": 11231, "nods": 11232, "##mine": 11233, "differ": 11234, "boris": 11235, "##eur": 11236, "yuan": 11237, "flip": 11238, "##gie": 11239, "mob": 11240, "invested": 11241, "questioning": 11242, "applying": 11243, "##ture": 11244, "shout": 11245, "##sel": 11246, "gameplay": 11247, "blamed": 11248, "illustrations": 11249, "bothered": 11250, "weakness": 11251, "rehabilitation": 11252, "##of": 11253, "##zes": 11254, "envelope": 11255, "rumors": 11256, "miners": 11257, "leicester": 11258, "subtle": 11259, "kerry": 11260, "##ico": 11261, "ferguson": 11262, "##fu": 11263, "premiership": 11264, "ne": 11265, "##cat": 11266, "bengali": 11267, "prof": 11268, "catches": 11269, "remnants": 11270, "dana": 11271, "##rily": 11272, "shouting": 11273, "presidents": 11274, "baltic": 11275, "ought": 11276, "ghosts": 11277, "dances": 11278, "sailors": 11279, "shirley": 11280, "fancy": 11281, "dominic": 11282, "##bie": 11283, "madonna": 11284, "##rick": 11285, "bark": 11286, "buttons": 11287, "gymnasium": 11288, "ashes": 11289, "liver": 11290, "toby": 11291, "oath": 11292, "providence": 11293, "doyle": 11294, "evangelical": 11295, "nixon": 11296, "cement": 11297, "carnegie": 11298, "embarked": 11299, "hatch": 11300, "surroundings": 11301, "guarantee": 11302, "needing": 11303, "pirate": 11304, "essence": 11305, "##bee": 11306, "filter": 11307, "crane": 11308, "hammond": 11309, "projected": 11310, "immune": 11311, "percy": 11312, "twelfth": 11313, "##ult": 11314, "regent": 11315, "doctoral": 11316, "damon": 11317, "mikhail": 11318, "##ichi": 11319, "lu": 11320, "critically": 11321, "elect": 11322, "realised": 11323, "abortion": 11324, "acute": 11325, "screening": 11326, "mythology": 11327, "steadily": 11328, "##fc": 11329, "frown": 11330, "nottingham": 11331, "kirk": 11332, "wa": 11333, "minneapolis": 11334, "##rra": 11335, "module": 11336, "algeria": 11337, "mc": 11338, "nautical": 11339, "encounters": 11340, "surprising": 11341, "statues": 11342, "availability": 11343, "shirts": 11344, "pie": 11345, "alma": 11346, "brows": 11347, "munster": 11348, "mack": 11349, "soup": 11350, "crater": 11351, "tornado": 11352, "sanskrit": 11353, "cedar": 11354, "explosive": 11355, "bordered": 11356, "dixon": 11357, "planets": 11358, "stamp": 11359, "exam": 11360, "happily": 11361, "##bble": 11362, "carriers": 11363, "kidnapped": 11364, "##vis": 11365, "accommodation": 11366, "emigrated": 11367, "##met": 11368, "knockout": 11369, "correspondent": 11370, "violation": 11371, "profits": 11372, "peaks": 11373, "lang": 11374, "specimen": 11375, "agenda": 11376, "ancestry": 11377, "pottery": 11378, "spelling": 11379, "equations": 11380, "obtaining": 11381, "ki": 11382, "linking": 11383, "1825": 11384, "debris": 11385, "asylum": 11386, "##20": 11387, "buddhism": 11388, "teddy": 11389, "##ants": 11390, "gazette": 11391, "##nger": 11392, "##sse": 11393, "dental": 11394, "eligibility": 11395, "utc": 11396, "fathers": 11397, "averaged": 11398, "zimbabwe": 11399, "francesco": 11400, "coloured": 11401, "hissed": 11402, "translator": 11403, "lynch": 11404, "mandate": 11405, "humanities": 11406, "mackenzie": 11407, "uniforms": 11408, "lin": 11409, "##iana": 11410, "##gio": 11411, "asset": 11412, "mhz": 11413, "fitting": 11414, "samantha": 11415, "genera": 11416, "wei": 11417, "rim": 11418, "beloved": 11419, "shark": 11420, "riot": 11421, "entities": 11422, "expressions": 11423, "indo": 11424, "carmen": 11425, "slipping": 11426, "owing": 11427, "abbot": 11428, "neighbor": 11429, "sidney": 11430, "##av": 11431, "rats": 11432, "recommendations": 11433, "encouraging": 11434, "squadrons": 11435, "anticipated": 11436, "commanders": 11437, "conquered": 11438, "##oto": 11439, "donations": 11440, "diagnosed": 11441, "##mond": 11442, "divide": 11443, "##iva": 11444, "guessed": 11445, "decoration": 11446, "vernon": 11447, "auditorium": 11448, "revelation": 11449, "conversations": 11450, "##kers": 11451, "##power": 11452, "herzegovina": 11453, "dash": 11454, "alike": 11455, "protested": 11456, "lateral": 11457, "herman": 11458, "accredited": 11459, "mg": 11460, "##gent": 11461, "freeman": 11462, "mel": 11463, "fiji": 11464, "crow": 11465, "crimson": 11466, "##rine": 11467, "livestock": 11468, "##pped": 11469, "humanitarian": 11470, "bored": 11471, "oz": 11472, "whip": 11473, "##lene": 11474, "##ali": 11475, "legitimate": 11476, "alter": 11477, "grinning": 11478, "spelled": 11479, "anxious": 11480, "oriental": 11481, "wesley": 11482, "##nin": 11483, "##hole": 11484, "carnival": 11485, "controller": 11486, "detect": 11487, "##ssa": 11488, "bowed": 11489, "educator": 11490, "kosovo": 11491, "macedonia": 11492, "##sin": 11493, "occupy": 11494, "mastering": 11495, "stephanie": 11496, "janeiro": 11497, "para": 11498, "unaware": 11499, "nurses": 11500, "noon": 11501, "135": 11502, "cam": 11503, "hopefully": 11504, "ranger": 11505, "combine": 11506, "sociology": 11507, "polar": 11508, "rica": 11509, "##eer": 11510, "neill": 11511, "##sman": 11512, "holocaust": 11513, "##ip": 11514, "doubled": 11515, "lust": 11516, "1828": 11517, "109": 11518, "decent": 11519, "cooling": 11520, "unveiled": 11521, "##card": 11522, "1829": 11523, "nsw": 11524, "homer": 11525, "chapman": 11526, "meyer": 11527, "##gin": 11528, "dive": 11529, "mae": 11530, "reagan": 11531, "expertise": 11532, "##gled": 11533, "darwin": 11534, "brooke": 11535, "sided": 11536, "prosecution": 11537, "investigating": 11538, "comprised": 11539, "petroleum": 11540, "genres": 11541, "reluctant": 11542, "differently": 11543, "trilogy": 11544, "johns": 11545, "vegetables": 11546, "corpse": 11547, "highlighted": 11548, "lounge": 11549, "pension": 11550, "unsuccessfully": 11551, "elegant": 11552, "aided": 11553, "ivory": 11554, "beatles": 11555, "amelia": 11556, "cain": 11557, "dubai": 11558, "sunny": 11559, "immigrant": 11560, "babe": 11561, "click": 11562, "##nder": 11563, "underwater": 11564, "pepper": 11565, "combining": 11566, "mumbled": 11567, "atlas": 11568, "horns": 11569, "accessed": 11570, "ballad": 11571, "physicians": 11572, "homeless": 11573, "gestured": 11574, "rpm": 11575, "freak": 11576, "louisville": 11577, "corporations": 11578, "patriots": 11579, "prizes": 11580, "rational": 11581, "warn": 11582, "modes": 11583, "decorative": 11584, "overnight": 11585, "din": 11586, "troubled": 11587, "phantom": 11588, "##ort": 11589, "monarch": 11590, "sheer": 11591, "##dorf": 11592, "generals": 11593, "guidelines": 11594, "organs": 11595, "addresses": 11596, "##zon": 11597, "enhance": 11598, "curling": 11599, "parishes": 11600, "cord": 11601, "##kie": 11602, "linux": 11603, "caesar": 11604, "deutsche": 11605, "bavaria": 11606, "##bia": 11607, "coleman": 11608, "cyclone": 11609, "##eria": 11610, "bacon": 11611, "petty": 11612, "##yama": 11613, "##old": 11614, "hampton": 11615, "diagnosis": 11616, "1824": 11617, "throws": 11618, "complexity": 11619, "rita": 11620, "disputed": 11621, "##₃": 11622, "pablo": 11623, "##sch": 11624, "marketed": 11625, "trafficking": 11626, "##ulus": 11627, "examine": 11628, "plague": 11629, "formats": 11630, "##oh": 11631, "vault": 11632, "faithful": 11633, "##bourne": 11634, "webster": 11635, "##ox": 11636, "highlights": 11637, "##ient": 11638, "##ann": 11639, "phones": 11640, "vacuum": 11641, "sandwich": 11642, "modeling": 11643, "##gated": 11644, "bolivia": 11645, "clergy": 11646, "qualities": 11647, "isabel": 11648, "##nas": 11649, "##ars": 11650, "wears": 11651, "screams": 11652, "reunited": 11653, "annoyed": 11654, "bra": 11655, "##ancy": 11656, "##rate": 11657, "differential": 11658, "transmitter": 11659, "tattoo": 11660, "container": 11661, "poker": 11662, "##och": 11663, "excessive": 11664, "resides": 11665, "cowboys": 11666, "##tum": 11667, "augustus": 11668, "trash": 11669, "providers": 11670, "statute": 11671, "retreated": 11672, "balcony": 11673, "reversed": 11674, "void": 11675, "storey": 11676, "preceded": 11677, "masses": 11678, "leap": 11679, "laughs": 11680, "neighborhoods": 11681, "wards": 11682, "schemes": 11683, "falcon": 11684, "santo": 11685, "battlefield": 11686, "pad": 11687, "ronnie": 11688, "thread": 11689, "lesbian": 11690, "venus": 11691, "##dian": 11692, "beg": 11693, "sandstone": 11694, "daylight": 11695, "punched": 11696, "gwen": 11697, "analog": 11698, "stroked": 11699, "wwe": 11700, "acceptable": 11701, "measurements": 11702, "dec": 11703, "toxic": 11704, "##kel": 11705, "adequate": 11706, "surgical": 11707, "economist": 11708, "parameters": 11709, "varsity": 11710, "##sberg": 11711, "quantity": 11712, "ella": 11713, "##chy": 11714, "##rton": 11715, "countess": 11716, "generating": 11717, "precision": 11718, "diamonds": 11719, "expressway": 11720, "ga": 11721, "##ı": 11722, "1821": 11723, "uruguay": 11724, "talents": 11725, "galleries": 11726, "expenses": 11727, "scanned": 11728, "colleague": 11729, "outlets": 11730, "ryder": 11731, "lucien": 11732, "##ila": 11733, "paramount": 11734, "##bon": 11735, "syracuse": 11736, "dim": 11737, "fangs": 11738, "gown": 11739, "sweep": 11740, "##sie": 11741, "toyota": 11742, "missionaries": 11743, "websites": 11744, "##nsis": 11745, "sentences": 11746, "adviser": 11747, "val": 11748, "trademark": 11749, "spells": 11750, "##plane": 11751, "patience": 11752, "starter": 11753, "slim": 11754, "##borg": 11755, "toe": 11756, "incredibly": 11757, "shoots": 11758, "elliot": 11759, "nobility": 11760, "##wyn": 11761, "cowboy": 11762, "endorsed": 11763, "gardner": 11764, "tendency": 11765, "persuaded": 11766, "organisms": 11767, "emissions": 11768, "kazakhstan": 11769, "amused": 11770, "boring": 11771, "chips": 11772, "themed": 11773, "##hand": 11774, "llc": 11775, "constantinople": 11776, "chasing": 11777, "systematic": 11778, "guatemala": 11779, "borrowed": 11780, "erin": 11781, "carey": 11782, "##hard": 11783, "highlands": 11784, "struggles": 11785, "1810": 11786, "##ifying": 11787, "##ced": 11788, "wong": 11789, "exceptions": 11790, "develops": 11791, "enlarged": 11792, "kindergarten": 11793, "castro": 11794, "##ern": 11795, "##rina": 11796, "leigh": 11797, "zombie": 11798, "juvenile": 11799, "##most": 11800, "consul": 11801, "##nar": 11802, "sailor": 11803, "hyde": 11804, "clarence": 11805, "intensive": 11806, "pinned": 11807, "nasty": 11808, "useless": 11809, "jung": 11810, "clayton": 11811, "stuffed": 11812, "exceptional": 11813, "ix": 11814, "apostolic": 11815, "230": 11816, "transactions": 11817, "##dge": 11818, "exempt": 11819, "swinging": 11820, "cove": 11821, "religions": 11822, "##ash": 11823, "shields": 11824, "dairy": 11825, "bypass": 11826, "190": 11827, "pursuing": 11828, "bug": 11829, "joyce": 11830, "bombay": 11831, "chassis": 11832, "southampton": 11833, "chat": 11834, "interact": 11835, "redesignated": 11836, "##pen": 11837, "nascar": 11838, "pray": 11839, "salmon": 11840, "rigid": 11841, "regained": 11842, "malaysian": 11843, "grim": 11844, "publicity": 11845, "constituted": 11846, "capturing": 11847, "toilet": 11848, "delegate": 11849, "purely": 11850, "tray": 11851, "drift": 11852, "loosely": 11853, "striker": 11854, "weakened": 11855, "trinidad": 11856, "mitch": 11857, "itv": 11858, "defines": 11859, "transmitted": 11860, "ming": 11861, "scarlet": 11862, "nodding": 11863, "fitzgerald": 11864, "fu": 11865, "narrowly": 11866, "sp": 11867, "tooth": 11868, "standings": 11869, "virtue": 11870, "##₁": 11871, "##wara": 11872, "##cting": 11873, "chateau": 11874, "gloves": 11875, "lid": 11876, "##nel": 11877, "hurting": 11878, "conservatory": 11879, "##pel": 11880, "sinclair": 11881, "reopened": 11882, "sympathy": 11883, "nigerian": 11884, "strode": 11885, "advocated": 11886, "optional": 11887, "chronic": 11888, "discharge": 11889, "##rc": 11890, "suck": 11891, "compatible": 11892, "laurel": 11893, "stella": 11894, "shi": 11895, "fails": 11896, "wage": 11897, "dodge": 11898, "128": 11899, "informal": 11900, "sorts": 11901, "levi": 11902, "buddha": 11903, "villagers": 11904, "##aka": 11905, "chronicles": 11906, "heavier": 11907, "summoned": 11908, "gateway": 11909, "3000": 11910, "eleventh": 11911, "jewelry": 11912, "translations": 11913, "accordingly": 11914, "seas": 11915, "##ency": 11916, "fiber": 11917, "pyramid": 11918, "cubic": 11919, "dragging": 11920, "##ista": 11921, "caring": 11922, "##ops": 11923, "android": 11924, "contacted": 11925, "lunar": 11926, "##dt": 11927, "kai": 11928, "lisbon": 11929, "patted": 11930, "1826": 11931, "sacramento": 11932, "theft": 11933, "madagascar": 11934, "subtropical": 11935, "disputes": 11936, "ta": 11937, "holidays": 11938, "piper": 11939, "willow": 11940, "mare": 11941, "cane": 11942, "itunes": 11943, "newfoundland": 11944, "benny": 11945, "companions": 11946, "dong": 11947, "raj": 11948, "observe": 11949, "roar": 11950, "charming": 11951, "plaque": 11952, "tibetan": 11953, "fossils": 11954, "enacted": 11955, "manning": 11956, "bubble": 11957, "tina": 11958, "tanzania": 11959, "##eda": 11960, "##hir": 11961, "funk": 11962, "swamp": 11963, "deputies": 11964, "cloak": 11965, "ufc": 11966, "scenario": 11967, "par": 11968, "scratch": 11969, "metals": 11970, "anthem": 11971, "guru": 11972, "engaging": 11973, "specially": 11974, "##boat": 11975, "dialects": 11976, "nineteen": 11977, "cecil": 11978, "duet": 11979, "disability": 11980, "messenger": 11981, "unofficial": 11982, "##lies": 11983, "defunct": 11984, "eds": 11985, "moonlight": 11986, "drainage": 11987, "surname": 11988, "puzzle": 11989, "honda": 11990, "switching": 11991, "conservatives": 11992, "mammals": 11993, "knox": 11994, "broadcaster": 11995, "sidewalk": 11996, "cope": 11997, "##ried": 11998, "benson": 11999, "princes": 12000, "peterson": 12001, "##sal": 12002, "bedford": 12003, "sharks": 12004, "eli": 12005, "wreck": 12006, "alberto": 12007, "gasp": 12008, "archaeology": 12009, "lgbt": 12010, "teaches": 12011, "securities": 12012, "madness": 12013, "compromise": 12014, "waving": 12015, "coordination": 12016, "davidson": 12017, "visions": 12018, "leased": 12019, "possibilities": 12020, "eighty": 12021, "jun": 12022, "fernandez": 12023, "enthusiasm": 12024, "assassin": 12025, "sponsorship": 12026, "reviewer": 12027, "kingdoms": 12028, "estonian": 12029, "laboratories": 12030, "##fy": 12031, "##nal": 12032, "applies": 12033, "verb": 12034, "celebrations": 12035, "##zzo": 12036, "rowing": 12037, "lightweight": 12038, "sadness": 12039, "submit": 12040, "mvp": 12041, "balanced": 12042, "dude": 12043, "##vas": 12044, "explicitly": 12045, "metric": 12046, "magnificent": 12047, "mound": 12048, "brett": 12049, "mohammad": 12050, "mistakes": 12051, "irregular": 12052, "##hing": 12053, "##ass": 12054, "sanders": 12055, "betrayed": 12056, "shipped": 12057, "surge": 12058, "##enburg": 12059, "reporters": 12060, "termed": 12061, "georg": 12062, "pity": 12063, "verbal": 12064, "bulls": 12065, "abbreviated": 12066, "enabling": 12067, "appealed": 12068, "##are": 12069, "##atic": 12070, "sicily": 12071, "sting": 12072, "heel": 12073, "sweetheart": 12074, "bart": 12075, "spacecraft": 12076, "brutal": 12077, "monarchy": 12078, "##tter": 12079, "aberdeen": 12080, "cameo": 12081, "diane": 12082, "##ub": 12083, "survivor": 12084, "clyde": 12085, "##aries": 12086, "complaint": 12087, "##makers": 12088, "clarinet": 12089, "delicious": 12090, "chilean": 12091, "karnataka": 12092, "coordinates": 12093, "1818": 12094, "panties": 12095, "##rst": 12096, "pretending": 12097, "ar": 12098, "dramatically": 12099, "kiev": 12100, "bella": 12101, "tends": 12102, "distances": 12103, "113": 12104, "catalog": 12105, "launching": 12106, "instances": 12107, "telecommunications": 12108, "portable": 12109, "lindsay": 12110, "vatican": 12111, "##eim": 12112, "angles": 12113, "aliens": 12114, "marker": 12115, "stint": 12116, "screens": 12117, "bolton": 12118, "##rne": 12119, "judy": 12120, "wool": 12121, "benedict": 12122, "plasma": 12123, "europa": 12124, "spark": 12125, "imaging": 12126, "filmmaker": 12127, "swiftly": 12128, "##een": 12129, "contributor": 12130, "##nor": 12131, "opted": 12132, "stamps": 12133, "apologize": 12134, "financing": 12135, "butter": 12136, "gideon": 12137, "sophisticated": 12138, "alignment": 12139, "avery": 12140, "chemicals": 12141, "yearly": 12142, "speculation": 12143, "prominence": 12144, "professionally": 12145, "##ils": 12146, "immortal": 12147, "institutional": 12148, "inception": 12149, "wrists": 12150, "identifying": 12151, "tribunal": 12152, "derives": 12153, "gains": 12154, "##wo": 12155, "papal": 12156, "preference": 12157, "linguistic": 12158, "vince": 12159, "operative": 12160, "brewery": 12161, "##ont": 12162, "unemployment": 12163, "boyd": 12164, "##ured": 12165, "##outs": 12166, "albeit": 12167, "prophet": 12168, "1813": 12169, "bi": 12170, "##rr": 12171, "##face": 12172, "##rad": 12173, "quarterly": 12174, "asteroid": 12175, "cleaned": 12176, "radius": 12177, "temper": 12178, "##llen": 12179, "telugu": 12180, "jerk": 12181, "viscount": 12182, "menu": 12183, "##ote": 12184, "glimpse": 12185, "##aya": 12186, "yacht": 12187, "hawaiian": 12188, "baden": 12189, "##rl": 12190, "laptop": 12191, "readily": 12192, "##gu": 12193, "monetary": 12194, "offshore": 12195, "scots": 12196, "watches": 12197, "##yang": 12198, "##arian": 12199, "upgrade": 12200, "needle": 12201, "xbox": 12202, "lea": 12203, "encyclopedia": 12204, "flank": 12205, "fingertips": 12206, "##pus": 12207, "delight": 12208, "teachings": 12209, "confirm": 12210, "roth": 12211, "beaches": 12212, "midway": 12213, "winters": 12214, "##iah": 12215, "teasing": 12216, "daytime": 12217, "beverly": 12218, "gambling": 12219, "bonnie": 12220, "##backs": 12221, "regulated": 12222, "clement": 12223, "hermann": 12224, "tricks": 12225, "knot": 12226, "##shing": 12227, "##uring": 12228, "##vre": 12229, "detached": 12230, "ecological": 12231, "owed": 12232, "specialty": 12233, "byron": 12234, "inventor": 12235, "bats": 12236, "stays": 12237, "screened": 12238, "unesco": 12239, "midland": 12240, "trim": 12241, "affection": 12242, "##ander": 12243, "##rry": 12244, "jess": 12245, "thoroughly": 12246, "feedback": 12247, "##uma": 12248, "chennai": 12249, "strained": 12250, "heartbeat": 12251, "wrapping": 12252, "overtime": 12253, "pleaded": 12254, "##sworth": 12255, "mon": 12256, "leisure": 12257, "oclc": 12258, "##tate": 12259, "##ele": 12260, "feathers": 12261, "angelo": 12262, "thirds": 12263, "nuts": 12264, "surveys": 12265, "clever": 12266, "gill": 12267, "commentator": 12268, "##dos": 12269, "darren": 12270, "rides": 12271, "gibraltar": 12272, "##nc": 12273, "##mu": 12274, "dissolution": 12275, "dedication": 12276, "shin": 12277, "meals": 12278, "saddle": 12279, "elvis": 12280, "reds": 12281, "chaired": 12282, "taller": 12283, "appreciation": 12284, "functioning": 12285, "niece": 12286, "favored": 12287, "advocacy": 12288, "robbie": 12289, "criminals": 12290, "suffolk": 12291, "yugoslav": 12292, "passport": 12293, "constable": 12294, "congressman": 12295, "hastings": 12296, "vera": 12297, "##rov": 12298, "consecrated": 12299, "sparks": 12300, "ecclesiastical": 12301, "confined": 12302, "##ovich": 12303, "muller": 12304, "floyd": 12305, "nora": 12306, "1822": 12307, "paved": 12308, "1827": 12309, "cumberland": 12310, "ned": 12311, "saga": 12312, "spiral": 12313, "##flow": 12314, "appreciated": 12315, "yi": 12316, "collaborative": 12317, "treating": 12318, "similarities": 12319, "feminine": 12320, "finishes": 12321, "##ib": 12322, "jade": 12323, "import": 12324, "##nse": 12325, "##hot": 12326, "champagne": 12327, "mice": 12328, "securing": 12329, "celebrities": 12330, "helsinki": 12331, "attributes": 12332, "##gos": 12333, "cousins": 12334, "phases": 12335, "ache": 12336, "lucia": 12337, "gandhi": 12338, "submission": 12339, "vicar": 12340, "spear": 12341, "shine": 12342, "tasmania": 12343, "biting": 12344, "detention": 12345, "constitute": 12346, "tighter": 12347, "seasonal": 12348, "##gus": 12349, "terrestrial": 12350, "matthews": 12351, "##oka": 12352, "effectiveness": 12353, "parody": 12354, "philharmonic": 12355, "##onic": 12356, "1816": 12357, "strangers": 12358, "encoded": 12359, "consortium": 12360, "guaranteed": 12361, "regards": 12362, "shifts": 12363, "tortured": 12364, "collision": 12365, "supervisor": 12366, "inform": 12367, "broader": 12368, "insight": 12369, "theaters": 12370, "armour": 12371, "emeritus": 12372, "blink": 12373, "incorporates": 12374, "mapping": 12375, "##50": 12376, "##ein": 12377, "handball": 12378, "flexible": 12379, "##nta": 12380, "substantially": 12381, "generous": 12382, "thief": 12383, "##own": 12384, "carr": 12385, "loses": 12386, "1793": 12387, "prose": 12388, "ucla": 12389, "romeo": 12390, "generic": 12391, "metallic": 12392, "realization": 12393, "damages": 12394, "mk": 12395, "commissioners": 12396, "zach": 12397, "default": 12398, "##ther": 12399, "helicopters": 12400, "lengthy": 12401, "stems": 12402, "spa": 12403, "partnered": 12404, "spectators": 12405, "rogue": 12406, "indication": 12407, "penalties": 12408, "teresa": 12409, "1801": 12410, "sen": 12411, "##tric": 12412, "dalton": 12413, "##wich": 12414, "irving": 12415, "photographic": 12416, "##vey": 12417, "dell": 12418, "deaf": 12419, "peters": 12420, "excluded": 12421, "unsure": 12422, "##vable": 12423, "patterson": 12424, "crawled": 12425, "##zio": 12426, "resided": 12427, "whipped": 12428, "latvia": 12429, "slower": 12430, "ecole": 12431, "pipes": 12432, "employers": 12433, "maharashtra": 12434, "comparable": 12435, "va": 12436, "textile": 12437, "pageant": 12438, "##gel": 12439, "alphabet": 12440, "binary": 12441, "irrigation": 12442, "chartered": 12443, "choked": 12444, "antoine": 12445, "offs": 12446, "waking": 12447, "supplement": 12448, "##wen": 12449, "quantities": 12450, "demolition": 12451, "regain": 12452, "locate": 12453, "urdu": 12454, "folks": 12455, "alt": 12456, "114": 12457, "##mc": 12458, "scary": 12459, "andreas": 12460, "whites": 12461, "##ava": 12462, "classrooms": 12463, "mw": 12464, "aesthetic": 12465, "publishes": 12466, "valleys": 12467, "guides": 12468, "cubs": 12469, "johannes": 12470, "bryant": 12471, "conventions": 12472, "affecting": 12473, "##itt": 12474, "drain": 12475, "awesome": 12476, "isolation": 12477, "prosecutor": 12478, "ambitious": 12479, "apology": 12480, "captive": 12481, "downs": 12482, "atmospheric": 12483, "lorenzo": 12484, "aisle": 12485, "beef": 12486, "foul": 12487, "##onia": 12488, "kidding": 12489, "composite": 12490, "disturbed": 12491, "illusion": 12492, "natives": 12493, "##ffer": 12494, "emi": 12495, "rockets": 12496, "riverside": 12497, "wartime": 12498, "painters": 12499, "adolf": 12500, "melted": 12501, "##ail": 12502, "uncertainty": 12503, "simulation": 12504, "hawks": 12505, "progressed": 12506, "meantime": 12507, "builder": 12508, "spray": 12509, "breach": 12510, "unhappy": 12511, "regina": 12512, "russians": 12513, "##urg": 12514, "determining": 12515, "##tation": 12516, "tram": 12517, "1806": 12518, "##quin": 12519, "aging": 12520, "##12": 12521, "1823": 12522, "garion": 12523, "rented": 12524, "mister": 12525, "diaz": 12526, "terminated": 12527, "clip": 12528, "1817": 12529, "depend": 12530, "nervously": 12531, "disco": 12532, "owe": 12533, "defenders": 12534, "shiva": 12535, "notorious": 12536, "disbelief": 12537, "shiny": 12538, "worcester": 12539, "##gation": 12540, "##yr": 12541, "trailing": 12542, "undertook": 12543, "islander": 12544, "belarus": 12545, "limitations": 12546, "watershed": 12547, "fuller": 12548, "overlooking": 12549, "utilized": 12550, "raphael": 12551, "1819": 12552, "synthetic": 12553, "breakdown": 12554, "klein": 12555, "##nate": 12556, "moaned": 12557, "memoir": 12558, "lamb": 12559, "practicing": 12560, "##erly": 12561, "cellular": 12562, "arrows": 12563, "exotic": 12564, "##graphy": 12565, "witches": 12566, "117": 12567, "charted": 12568, "rey": 12569, "hut": 12570, "hierarchy": 12571, "subdivision": 12572, "freshwater": 12573, "giuseppe": 12574, "aloud": 12575, "reyes": 12576, "qatar": 12577, "marty": 12578, "sideways": 12579, "utterly": 12580, "sexually": 12581, "jude": 12582, "prayers": 12583, "mccarthy": 12584, "softball": 12585, "blend": 12586, "damien": 12587, "##gging": 12588, "##metric": 12589, "wholly": 12590, "erupted": 12591, "lebanese": 12592, "negro": 12593, "revenues": 12594, "tasted": 12595, "comparative": 12596, "teamed": 12597, "transaction": 12598, "labeled": 12599, "maori": 12600, "sovereignty": 12601, "parkway": 12602, "trauma": 12603, "gran": 12604, "malay": 12605, "121": 12606, "advancement": 12607, "descendant": 12608, "2020": 12609, "buzz": 12610, "salvation": 12611, "inventory": 12612, "symbolic": 12613, "##making": 12614, "antarctica": 12615, "mps": 12616, "##gas": 12617, "##bro": 12618, "mohammed": 12619, "myanmar": 12620, "holt": 12621, "submarines": 12622, "tones": 12623, "##lman": 12624, "locker": 12625, "patriarch": 12626, "bangkok": 12627, "emerson": 12628, "remarks": 12629, "predators": 12630, "kin": 12631, "afghan": 12632, "confession": 12633, "norwich": 12634, "rental": 12635, "emerge": 12636, "advantages": 12637, "##zel": 12638, "rca": 12639, "##hold": 12640, "shortened": 12641, "storms": 12642, "aidan": 12643, "##matic": 12644, "autonomy": 12645, "compliance": 12646, "##quet": 12647, "dudley": 12648, "atp": 12649, "##osis": 12650, "1803": 12651, "motto": 12652, "documentation": 12653, "summary": 12654, "professors": 12655, "spectacular": 12656, "christina": 12657, "archdiocese": 12658, "flashing": 12659, "innocence": 12660, "remake": 12661, "##dell": 12662, "psychic": 12663, "reef": 12664, "scare": 12665, "employ": 12666, "rs": 12667, "sticks": 12668, "meg": 12669, "gus": 12670, "leans": 12671, "##ude": 12672, "accompany": 12673, "bergen": 12674, "tomas": 12675, "##iko": 12676, "doom": 12677, "wages": 12678, "pools": 12679, "##nch": 12680, "##bes": 12681, "breasts": 12682, "scholarly": 12683, "alison": 12684, "outline": 12685, "brittany": 12686, "breakthrough": 12687, "willis": 12688, "realistic": 12689, "##cut": 12690, "##boro": 12691, "competitor": 12692, "##stan": 12693, "pike": 12694, "picnic": 12695, "icon": 12696, "designing": 12697, "commercials": 12698, "washing": 12699, "villain": 12700, "skiing": 12701, "micro": 12702, "costumes": 12703, "auburn": 12704, "halted": 12705, "executives": 12706, "##hat": 12707, "logistics": 12708, "cycles": 12709, "vowel": 12710, "applicable": 12711, "barrett": 12712, "exclaimed": 12713, "eurovision": 12714, "eternity": 12715, "ramon": 12716, "##umi": 12717, "##lls": 12718, "modifications": 12719, "sweeping": 12720, "disgust": 12721, "##uck": 12722, "torch": 12723, "aviv": 12724, "ensuring": 12725, "rude": 12726, "dusty": 12727, "sonic": 12728, "donovan": 12729, "outskirts": 12730, "cu": 12731, "pathway": 12732, "##band": 12733, "##gun": 12734, "##lines": 12735, "disciplines": 12736, "acids": 12737, "cadet": 12738, "paired": 12739, "##40": 12740, "sketches": 12741, "##sive": 12742, "marriages": 12743, "##⁺": 12744, "folding": 12745, "peers": 12746, "slovak": 12747, "implies": 12748, "admired": 12749, "##beck": 12750, "1880s": 12751, "leopold": 12752, "instinct": 12753, "attained": 12754, "weston": 12755, "megan": 12756, "horace": 12757, "##ination": 12758, "dorsal": 12759, "ingredients": 12760, "evolutionary": 12761, "##its": 12762, "complications": 12763, "deity": 12764, "lethal": 12765, "brushing": 12766, "levy": 12767, "deserted": 12768, "institutes": 12769, "posthumously": 12770, "delivering": 12771, "telescope": 12772, "coronation": 12773, "motivated": 12774, "rapids": 12775, "luc": 12776, "flicked": 12777, "pays": 12778, "volcano": 12779, "tanner": 12780, "weighed": 12781, "##nica": 12782, "crowds": 12783, "frankie": 12784, "gifted": 12785, "addressing": 12786, "granddaughter": 12787, "winding": 12788, "##rna": 12789, "constantine": 12790, "gomez": 12791, "##front": 12792, "landscapes": 12793, "rudolf": 12794, "anthropology": 12795, "slate": 12796, "werewolf": 12797, "##lio": 12798, "astronomy": 12799, "circa": 12800, "rouge": 12801, "dreaming": 12802, "sack": 12803, "knelt": 12804, "drowned": 12805, "naomi": 12806, "prolific": 12807, "tracked": 12808, "freezing": 12809, "herb": 12810, "##dium": 12811, "agony": 12812, "randall": 12813, "twisting": 12814, "wendy": 12815, "deposit": 12816, "touches": 12817, "vein": 12818, "wheeler": 12819, "##bbled": 12820, "##bor": 12821, "batted": 12822, "retaining": 12823, "tire": 12824, "presently": 12825, "compare": 12826, "specification": 12827, "daemon": 12828, "nigel": 12829, "##grave": 12830, "merry": 12831, "recommendation": 12832, "czechoslovakia": 12833, "sandra": 12834, "ng": 12835, "roma": 12836, "##sts": 12837, "lambert": 12838, "inheritance": 12839, "sheikh": 12840, "winchester": 12841, "cries": 12842, "examining": 12843, "##yle": 12844, "comeback": 12845, "cuisine": 12846, "nave": 12847, "##iv": 12848, "ko": 12849, "retrieve": 12850, "tomatoes": 12851, "barker": 12852, "polished": 12853, "defining": 12854, "irene": 12855, "lantern": 12856, "personalities": 12857, "begging": 12858, "tract": 12859, "swore": 12860, "1809": 12861, "175": 12862, "##gic": 12863, "omaha": 12864, "brotherhood": 12865, "##rley": 12866, "haiti": 12867, "##ots": 12868, "exeter": 12869, "##ete": 12870, "##zia": 12871, "steele": 12872, "dumb": 12873, "pearson": 12874, "210": 12875, "surveyed": 12876, "elisabeth": 12877, "trends": 12878, "##ef": 12879, "fritz": 12880, "##rf": 12881, "premium": 12882, "bugs": 12883, "fraction": 12884, "calmly": 12885, "viking": 12886, "##birds": 12887, "tug": 12888, "inserted": 12889, "unusually": 12890, "##ield": 12891, "confronted": 12892, "distress": 12893, "crashing": 12894, "brent": 12895, "turks": 12896, "resign": 12897, "##olo": 12898, "cambodia": 12899, "gabe": 12900, "sauce": 12901, "##kal": 12902, "evelyn": 12903, "116": 12904, "extant": 12905, "clusters": 12906, "quarry": 12907, "teenagers": 12908, "luna": 12909, "##lers": 12910, "##ister": 12911, "affiliation": 12912, "drill": 12913, "##ashi": 12914, "panthers": 12915, "scenic": 12916, "libya": 12917, "anita": 12918, "strengthen": 12919, "inscriptions": 12920, "##cated": 12921, "lace": 12922, "sued": 12923, "judith": 12924, "riots": 12925, "##uted": 12926, "mint": 12927, "##eta": 12928, "preparations": 12929, "midst": 12930, "dub": 12931, "challenger": 12932, "##vich": 12933, "mock": 12934, "cf": 12935, "displaced": 12936, "wicket": 12937, "breaths": 12938, "enables": 12939, "schmidt": 12940, "analyst": 12941, "##lum": 12942, "ag": 12943, "highlight": 12944, "automotive": 12945, "axe": 12946, "josef": 12947, "newark": 12948, "sufficiently": 12949, "resembles": 12950, "50th": 12951, "##pal": 12952, "flushed": 12953, "mum": 12954, "traits": 12955, "##ante": 12956, "commodore": 12957, "incomplete": 12958, "warming": 12959, "titular": 12960, "ceremonial": 12961, "ethical": 12962, "118": 12963, "celebrating": 12964, "eighteenth": 12965, "cao": 12966, "lima": 12967, "medalist": 12968, "mobility": 12969, "strips": 12970, "snakes": 12971, "##city": 12972, "miniature": 12973, "zagreb": 12974, "barton": 12975, "escapes": 12976, "umbrella": 12977, "automated": 12978, "doubted": 12979, "differs": 12980, "cooled": 12981, "georgetown": 12982, "dresden": 12983, "cooked": 12984, "fade": 12985, "wyatt": 12986, "rna": 12987, "jacobs": 12988, "carlton": 12989, "abundant": 12990, "stereo": 12991, "boost": 12992, "madras": 12993, "inning": 12994, "##hia": 12995, "spur": 12996, "ip": 12997, "malayalam": 12998, "begged": 12999, "osaka": 13000, "groan": 13001, "escaping": 13002, "charging": 13003, "dose": 13004, "vista": 13005, "##aj": 13006, "bud": 13007, "papa": 13008, "communists": 13009, "advocates": 13010, "edged": 13011, "tri": 13012, "##cent": 13013, "resemble": 13014, "peaking": 13015, "necklace": 13016, "fried": 13017, "montenegro": 13018, "saxony": 13019, "goose": 13020, "glances": 13021, "stuttgart": 13022, "curator": 13023, "recruit": 13024, "grocery": 13025, "sympathetic": 13026, "##tting": 13027, "##fort": 13028, "127": 13029, "lotus": 13030, "randolph": 13031, "ancestor": 13032, "##rand": 13033, "succeeding": 13034, "jupiter": 13035, "1798": 13036, "macedonian": 13037, "##heads": 13038, "hiking": 13039, "1808": 13040, "handing": 13041, "fischer": 13042, "##itive": 13043, "garbage": 13044, "node": 13045, "##pies": 13046, "prone": 13047, "singular": 13048, "papua": 13049, "inclined": 13050, "attractions": 13051, "italia": 13052, "pouring": 13053, "motioned": 13054, "grandma": 13055, "garnered": 13056, "jacksonville": 13057, "corp": 13058, "ego": 13059, "ringing": 13060, "aluminum": 13061, "##hausen": 13062, "ordering": 13063, "##foot": 13064, "drawer": 13065, "traders": 13066, "synagogue": 13067, "##play": 13068, "##kawa": 13069, "resistant": 13070, "wandering": 13071, "fragile": 13072, "fiona": 13073, "teased": 13074, "var": 13075, "hardcore": 13076, "soaked": 13077, "jubilee": 13078, "decisive": 13079, "exposition": 13080, "mercer": 13081, "poster": 13082, "valencia": 13083, "hale": 13084, "kuwait": 13085, "1811": 13086, "##ises": 13087, "##wr": 13088, "##eed": 13089, "tavern": 13090, "gamma": 13091, "122": 13092, "johan": 13093, "##uer": 13094, "airways": 13095, "amino": 13096, "gil": 13097, "##ury": 13098, "vocational": 13099, "domains": 13100, "torres": 13101, "##sp": 13102, "generator": 13103, "folklore": 13104, "outcomes": 13105, "##keeper": 13106, "canberra": 13107, "shooter": 13108, "fl": 13109, "beams": 13110, "confrontation": 13111, "##lling": 13112, "##gram": 13113, "feb": 13114, "aligned": 13115, "forestry": 13116, "pipeline": 13117, "jax": 13118, "motorway": 13119, "conception": 13120, "decay": 13121, "##tos": 13122, "coffin": 13123, "##cott": 13124, "stalin": 13125, "1805": 13126, "escorted": 13127, "minded": 13128, "##nam": 13129, "sitcom": 13130, "purchasing": 13131, "twilight": 13132, "veronica": 13133, "additions": 13134, "passive": 13135, "tensions": 13136, "straw": 13137, "123": 13138, "frequencies": 13139, "1804": 13140, "refugee": 13141, "cultivation": 13142, "##iate": 13143, "christie": 13144, "clary": 13145, "bulletin": 13146, "crept": 13147, "disposal": 13148, "##rich": 13149, "##zong": 13150, "processor": 13151, "crescent": 13152, "##rol": 13153, "bmw": 13154, "emphasized": 13155, "whale": 13156, "nazis": 13157, "aurora": 13158, "##eng": 13159, "dwelling": 13160, "hauled": 13161, "sponsors": 13162, "toledo": 13163, "mega": 13164, "ideology": 13165, "theatres": 13166, "tessa": 13167, "cerambycidae": 13168, "saves": 13169, "turtle": 13170, "cone": 13171, "suspects": 13172, "kara": 13173, "rusty": 13174, "yelling": 13175, "greeks": 13176, "mozart": 13177, "shades": 13178, "cocked": 13179, "participant": 13180, "##tro": 13181, "shire": 13182, "spit": 13183, "freeze": 13184, "necessity": 13185, "##cos": 13186, "inmates": 13187, "nielsen": 13188, "councillors": 13189, "loaned": 13190, "uncommon": 13191, "omar": 13192, "peasants": 13193, "botanical": 13194, "offspring": 13195, "daniels": 13196, "formations": 13197, "jokes": 13198, "1794": 13199, "pioneers": 13200, "sigma": 13201, "licensing": 13202, "##sus": 13203, "wheelchair": 13204, "polite": 13205, "1807": 13206, "liquor": 13207, "pratt": 13208, "trustee": 13209, "##uta": 13210, "forewings": 13211, "balloon": 13212, "##zz": 13213, "kilometre": 13214, "camping": 13215, "explicit": 13216, "casually": 13217, "shawn": 13218, "foolish": 13219, "teammates": 13220, "nm": 13221, "hassan": 13222, "carrie": 13223, "judged": 13224, "satisfy": 13225, "vanessa": 13226, "knives": 13227, "selective": 13228, "cnn": 13229, "flowed": 13230, "##lice": 13231, "eclipse": 13232, "stressed": 13233, "eliza": 13234, "mathematician": 13235, "cease": 13236, "cultivated": 13237, "##roy": 13238, "commissions": 13239, "browns": 13240, "##ania": 13241, "destroyers": 13242, "sheridan": 13243, "meadow": 13244, "##rius": 13245, "minerals": 13246, "##cial": 13247, "downstream": 13248, "clash": 13249, "gram": 13250, "memoirs": 13251, "ventures": 13252, "baha": 13253, "seymour": 13254, "archie": 13255, "midlands": 13256, "edith": 13257, "fare": 13258, "flynn": 13259, "invite": 13260, "canceled": 13261, "tiles": 13262, "stabbed": 13263, "boulder": 13264, "incorporate": 13265, "amended": 13266, "camden": 13267, "facial": 13268, "mollusk": 13269, "unreleased": 13270, "descriptions": 13271, "yoga": 13272, "grabs": 13273, "550": 13274, "raises": 13275, "ramp": 13276, "shiver": 13277, "##rose": 13278, "coined": 13279, "pioneering": 13280, "tunes": 13281, "qing": 13282, "warwick": 13283, "tops": 13284, "119": 13285, "melanie": 13286, "giles": 13287, "##rous": 13288, "wandered": 13289, "##inal": 13290, "annexed": 13291, "nov": 13292, "30th": 13293, "unnamed": 13294, "##ished": 13295, "organizational": 13296, "airplane": 13297, "normandy": 13298, "stoke": 13299, "whistle": 13300, "blessing": 13301, "violations": 13302, "chased": 13303, "holders": 13304, "shotgun": 13305, "##ctic": 13306, "outlet": 13307, "reactor": 13308, "##vik": 13309, "tires": 13310, "tearing": 13311, "shores": 13312, "fortified": 13313, "mascot": 13314, "constituencies": 13315, "nc": 13316, "columnist": 13317, "productive": 13318, "tibet": 13319, "##rta": 13320, "lineage": 13321, "hooked": 13322, "oct": 13323, "tapes": 13324, "judging": 13325, "cody": 13326, "##gger": 13327, "hansen": 13328, "kashmir": 13329, "triggered": 13330, "##eva": 13331, "solved": 13332, "cliffs": 13333, "##tree": 13334, "resisted": 13335, "anatomy": 13336, "protesters": 13337, "transparent": 13338, "implied": 13339, "##iga": 13340, "injection": 13341, "mattress": 13342, "excluding": 13343, "##mbo": 13344, "defenses": 13345, "helpless": 13346, "devotion": 13347, "##elli": 13348, "growl": 13349, "liberals": 13350, "weber": 13351, "phenomena": 13352, "atoms": 13353, "plug": 13354, "##iff": 13355, "mortality": 13356, "apprentice": 13357, "howe": 13358, "convincing": 13359, "aaa": 13360, "swimmer": 13361, "barber": 13362, "leone": 13363, "promptly": 13364, "sodium": 13365, "def": 13366, "nowadays": 13367, "arise": 13368, "##oning": 13369, "gloucester": 13370, "corrected": 13371, "dignity": 13372, "norm": 13373, "erie": 13374, "##ders": 13375, "elders": 13376, "evacuated": 13377, "sylvia": 13378, "compression": 13379, "##yar": 13380, "hartford": 13381, "pose": 13382, "backpack": 13383, "reasoning": 13384, "accepts": 13385, "24th": 13386, "wipe": 13387, "millimetres": 13388, "marcel": 13389, "##oda": 13390, "dodgers": 13391, "albion": 13392, "1790": 13393, "overwhelmed": 13394, "aerospace": 13395, "oaks": 13396, "1795": 13397, "showcase": 13398, "acknowledge": 13399, "recovering": 13400, "nolan": 13401, "ashe": 13402, "hurts": 13403, "geology": 13404, "fashioned": 13405, "disappearance": 13406, "farewell": 13407, "swollen": 13408, "shrug": 13409, "marquis": 13410, "wimbledon": 13411, "124": 13412, "rue": 13413, "1792": 13414, "commemorate": 13415, "reduces": 13416, "experiencing": 13417, "inevitable": 13418, "calcutta": 13419, "intel": 13420, "##court": 13421, "murderer": 13422, "sticking": 13423, "fisheries": 13424, "imagery": 13425, "bloom": 13426, "280": 13427, "brake": 13428, "##inus": 13429, "gustav": 13430, "hesitation": 13431, "memorable": 13432, "po": 13433, "viral": 13434, "beans": 13435, "accidents": 13436, "tunisia": 13437, "antenna": 13438, "spilled": 13439, "consort": 13440, "treatments": 13441, "aye": 13442, "perimeter": 13443, "##gard": 13444, "donation": 13445, "hostage": 13446, "migrated": 13447, "banker": 13448, "addiction": 13449, "apex": 13450, "lil": 13451, "trout": 13452, "##ously": 13453, "conscience": 13454, "##nova": 13455, "rams": 13456, "sands": 13457, "genome": 13458, "passionate": 13459, "troubles": 13460, "##lets": 13461, "##set": 13462, "amid": 13463, "##ibility": 13464, "##ret": 13465, "higgins": 13466, "exceed": 13467, "vikings": 13468, "##vie": 13469, "payne": 13470, "##zan": 13471, "muscular": 13472, "##ste": 13473, "defendant": 13474, "sucking": 13475, "##wal": 13476, "ibrahim": 13477, "fuselage": 13478, "claudia": 13479, "vfl": 13480, "europeans": 13481, "snails": 13482, "interval": 13483, "##garh": 13484, "preparatory": 13485, "statewide": 13486, "tasked": 13487, "lacrosse": 13488, "viktor": 13489, "##lation": 13490, "angola": 13491, "##hra": 13492, "flint": 13493, "implications": 13494, "employs": 13495, "teens": 13496, "patrons": 13497, "stall": 13498, "weekends": 13499, "barriers": 13500, "scrambled": 13501, "nucleus": 13502, "tehran": 13503, "jenna": 13504, "parsons": 13505, "lifelong": 13506, "robots": 13507, "displacement": 13508, "5000": 13509, "##bles": 13510, "precipitation": 13511, "##gt": 13512, "knuckles": 13513, "clutched": 13514, "1802": 13515, "marrying": 13516, "ecology": 13517, "marx": 13518, "accusations": 13519, "declare": 13520, "scars": 13521, "kolkata": 13522, "mat": 13523, "meadows": 13524, "bermuda": 13525, "skeleton": 13526, "finalists": 13527, "vintage": 13528, "crawl": 13529, "coordinate": 13530, "affects": 13531, "subjected": 13532, "orchestral": 13533, "mistaken": 13534, "##tc": 13535, "mirrors": 13536, "dipped": 13537, "relied": 13538, "260": 13539, "arches": 13540, "candle": 13541, "##nick": 13542, "incorporating": 13543, "wildly": 13544, "fond": 13545, "basilica": 13546, "owl": 13547, "fringe": 13548, "rituals": 13549, "whispering": 13550, "stirred": 13551, "feud": 13552, "tertiary": 13553, "slick": 13554, "goat": 13555, "honorable": 13556, "whereby": 13557, "skip": 13558, "ricardo": 13559, "stripes": 13560, "parachute": 13561, "adjoining": 13562, "submerged": 13563, "synthesizer": 13564, "##gren": 13565, "intend": 13566, "positively": 13567, "ninety": 13568, "phi": 13569, "beaver": 13570, "partition": 13571, "fellows": 13572, "alexis": 13573, "prohibition": 13574, "carlisle": 13575, "bizarre": 13576, "fraternity": 13577, "##bre": 13578, "doubts": 13579, "icy": 13580, "cbc": 13581, "aquatic": 13582, "sneak": 13583, "sonny": 13584, "combines": 13585, "airports": 13586, "crude": 13587, "supervised": 13588, "spatial": 13589, "merge": 13590, "alfonso": 13591, "##bic": 13592, "corrupt": 13593, "scan": 13594, "undergo": 13595, "##ams": 13596, "disabilities": 13597, "colombian": 13598, "comparing": 13599, "dolphins": 13600, "perkins": 13601, "##lish": 13602, "reprinted": 13603, "unanimous": 13604, "bounced": 13605, "hairs": 13606, "underworld": 13607, "midwest": 13608, "semester": 13609, "bucket": 13610, "paperback": 13611, "miniseries": 13612, "coventry": 13613, "demise": 13614, "##leigh": 13615, "demonstrations": 13616, "sensor": 13617, "rotating": 13618, "yan": 13619, "##hler": 13620, "arrange": 13621, "soils": 13622, "##idge": 13623, "hyderabad": 13624, "labs": 13625, "##dr": 13626, "brakes": 13627, "grandchildren": 13628, "##nde": 13629, "negotiated": 13630, "rover": 13631, "ferrari": 13632, "continuation": 13633, "directorate": 13634, "augusta": 13635, "stevenson": 13636, "counterpart": 13637, "gore": 13638, "##rda": 13639, "nursery": 13640, "rican": 13641, "ave": 13642, "collectively": 13643, "broadly": 13644, "pastoral": 13645, "repertoire": 13646, "asserted": 13647, "discovering": 13648, "nordic": 13649, "styled": 13650, "fiba": 13651, "cunningham": 13652, "harley": 13653, "middlesex": 13654, "survives": 13655, "tumor": 13656, "tempo": 13657, "zack": 13658, "aiming": 13659, "lok": 13660, "urgent": 13661, "##rade": 13662, "##nto": 13663, "devils": 13664, "##ement": 13665, "contractor": 13666, "turin": 13667, "##wl": 13668, "##ool": 13669, "bliss": 13670, "repaired": 13671, "simmons": 13672, "moan": 13673, "astronomical": 13674, "cr": 13675, "negotiate": 13676, "lyric": 13677, "1890s": 13678, "lara": 13679, "bred": 13680, "clad": 13681, "angus": 13682, "pbs": 13683, "##ience": 13684, "engineered": 13685, "posed": 13686, "##lk": 13687, "hernandez": 13688, "possessions": 13689, "elbows": 13690, "psychiatric": 13691, "strokes": 13692, "confluence": 13693, "electorate": 13694, "lifts": 13695, "campuses": 13696, "lava": 13697, "alps": 13698, "##ep": 13699, "##ution": 13700, "##date": 13701, "physicist": 13702, "woody": 13703, "##page": 13704, "##ographic": 13705, "##itis": 13706, "juliet": 13707, "reformation": 13708, "sparhawk": 13709, "320": 13710, "complement": 13711, "suppressed": 13712, "jewel": 13713, "##½": 13714, "floated": 13715, "##kas": 13716, "continuity": 13717, "sadly": 13718, "##ische": 13719, "inability": 13720, "melting": 13721, "scanning": 13722, "paula": 13723, "flour": 13724, "judaism": 13725, "safer": 13726, "vague": 13727, "##lm": 13728, "solving": 13729, "curb": 13730, "##stown": 13731, "financially": 13732, "gable": 13733, "bees": 13734, "expired": 13735, "miserable": 13736, "cassidy": 13737, "dominion": 13738, "1789": 13739, "cupped": 13740, "145": 13741, "robbery": 13742, "facto": 13743, "amos": 13744, "warden": 13745, "resume": 13746, "tallest": 13747, "marvin": 13748, "ing": 13749, "pounded": 13750, "usd": 13751, "declaring": 13752, "gasoline": 13753, "##aux": 13754, "darkened": 13755, "270": 13756, "650": 13757, "sophomore": 13758, "##mere": 13759, "erection": 13760, "gossip": 13761, "televised": 13762, "risen": 13763, "dial": 13764, "##eu": 13765, "pillars": 13766, "##link": 13767, "passages": 13768, "profound": 13769, "##tina": 13770, "arabian": 13771, "ashton": 13772, "silicon": 13773, "nail": 13774, "##ead": 13775, "##lated": 13776, "##wer": 13777, "##hardt": 13778, "fleming": 13779, "firearms": 13780, "ducked": 13781, "circuits": 13782, "blows": 13783, "waterloo": 13784, "titans": 13785, "##lina": 13786, "atom": 13787, "fireplace": 13788, "cheshire": 13789, "financed": 13790, "activation": 13791, "algorithms": 13792, "##zzi": 13793, "constituent": 13794, "catcher": 13795, "cherokee": 13796, "partnerships": 13797, "sexuality": 13798, "platoon": 13799, "tragic": 13800, "vivian": 13801, "guarded": 13802, "whiskey": 13803, "meditation": 13804, "poetic": 13805, "##late": 13806, "##nga": 13807, "##ake": 13808, "porto": 13809, "listeners": 13810, "dominance": 13811, "kendra": 13812, "mona": 13813, "chandler": 13814, "factions": 13815, "22nd": 13816, "salisbury": 13817, "attitudes": 13818, "derivative": 13819, "##ido": 13820, "##haus": 13821, "intake": 13822, "paced": 13823, "javier": 13824, "illustrator": 13825, "barrels": 13826, "bias": 13827, "cockpit": 13828, "burnett": 13829, "dreamed": 13830, "ensuing": 13831, "##anda": 13832, "receptors": 13833, "someday": 13834, "hawkins": 13835, "mattered": 13836, "##lal": 13837, "slavic": 13838, "1799": 13839, "jesuit": 13840, "cameroon": 13841, "wasted": 13842, "tai": 13843, "wax": 13844, "lowering": 13845, "victorious": 13846, "freaking": 13847, "outright": 13848, "hancock": 13849, "librarian": 13850, "sensing": 13851, "bald": 13852, "calcium": 13853, "myers": 13854, "tablet": 13855, "announcing": 13856, "barack": 13857, "shipyard": 13858, "pharmaceutical": 13859, "##uan": 13860, "greenwich": 13861, "flush": 13862, "medley": 13863, "patches": 13864, "wolfgang": 13865, "pt": 13866, "speeches": 13867, "acquiring": 13868, "exams": 13869, "nikolai": 13870, "##gg": 13871, "hayden": 13872, "kannada": 13873, "##type": 13874, "reilly": 13875, "##pt": 13876, "waitress": 13877, "abdomen": 13878, "devastated": 13879, "capped": 13880, "pseudonym": 13881, "pharmacy": 13882, "fulfill": 13883, "paraguay": 13884, "1796": 13885, "clicked": 13886, "##trom": 13887, "archipelago": 13888, "syndicated": 13889, "##hman": 13890, "lumber": 13891, "orgasm": 13892, "rejection": 13893, "clifford": 13894, "lorraine": 13895, "advent": 13896, "mafia": 13897, "rodney": 13898, "brock": 13899, "##ght": 13900, "##used": 13901, "##elia": 13902, "cassette": 13903, "chamberlain": 13904, "despair": 13905, "mongolia": 13906, "sensors": 13907, "developmental": 13908, "upstream": 13909, "##eg": 13910, "##alis": 13911, "spanning": 13912, "165": 13913, "trombone": 13914, "basque": 13915, "seeded": 13916, "interred": 13917, "renewable": 13918, "rhys": 13919, "leapt": 13920, "revision": 13921, "molecule": 13922, "##ages": 13923, "chord": 13924, "vicious": 13925, "nord": 13926, "shivered": 13927, "23rd": 13928, "arlington": 13929, "debts": 13930, "corpus": 13931, "sunrise": 13932, "bays": 13933, "blackburn": 13934, "centimetres": 13935, "##uded": 13936, "shuddered": 13937, "gm": 13938, "strangely": 13939, "gripping": 13940, "cartoons": 13941, "isabelle": 13942, "orbital": 13943, "##ppa": 13944, "seals": 13945, "proving": 13946, "##lton": 13947, "refusal": 13948, "strengthened": 13949, "bust": 13950, "assisting": 13951, "baghdad": 13952, "batsman": 13953, "portrayal": 13954, "mara": 13955, "pushes": 13956, "spears": 13957, "og": 13958, "##cock": 13959, "reside": 13960, "nathaniel": 13961, "brennan": 13962, "1776": 13963, "confirmation": 13964, "caucus": 13965, "##worthy": 13966, "markings": 13967, "yemen": 13968, "nobles": 13969, "ku": 13970, "lazy": 13971, "viewer": 13972, "catalan": 13973, "encompasses": 13974, "sawyer": 13975, "##fall": 13976, "sparked": 13977, "substances": 13978, "patents": 13979, "braves": 13980, "arranger": 13981, "evacuation": 13982, "sergio": 13983, "persuade": 13984, "dover": 13985, "tolerance": 13986, "penguin": 13987, "cum": 13988, "jockey": 13989, "insufficient": 13990, "townships": 13991, "occupying": 13992, "declining": 13993, "plural": 13994, "processed": 13995, "projection": 13996, "puppet": 13997, "flanders": 13998, "introduces": 13999, "liability": 14000, "##yon": 14001, "gymnastics": 14002, "antwerp": 14003, "taipei": 14004, "hobart": 14005, "candles": 14006, "jeep": 14007, "wes": 14008, "observers": 14009, "126": 14010, "chaplain": 14011, "bundle": 14012, "glorious": 14013, "##hine": 14014, "hazel": 14015, "flung": 14016, "sol": 14017, "excavations": 14018, "dumped": 14019, "stares": 14020, "sh": 14021, "bangalore": 14022, "triangular": 14023, "icelandic": 14024, "intervals": 14025, "expressing": 14026, "turbine": 14027, "##vers": 14028, "songwriting": 14029, "crafts": 14030, "##igo": 14031, "jasmine": 14032, "ditch": 14033, "rite": 14034, "##ways": 14035, "entertaining": 14036, "comply": 14037, "sorrow": 14038, "wrestlers": 14039, "basel": 14040, "emirates": 14041, "marian": 14042, "rivera": 14043, "helpful": 14044, "##some": 14045, "caution": 14046, "downward": 14047, "networking": 14048, "##atory": 14049, "##tered": 14050, "darted": 14051, "genocide": 14052, "emergence": 14053, "replies": 14054, "specializing": 14055, "spokesman": 14056, "convenient": 14057, "unlocked": 14058, "fading": 14059, "augustine": 14060, "concentrations": 14061, "resemblance": 14062, "elijah": 14063, "investigator": 14064, "andhra": 14065, "##uda": 14066, "promotes": 14067, "bean": 14068, "##rrell": 14069, "fleeing": 14070, "wan": 14071, "simone": 14072, "announcer": 14073, "##ame": 14074, "##bby": 14075, "lydia": 14076, "weaver": 14077, "132": 14078, "residency": 14079, "modification": 14080, "##fest": 14081, "stretches": 14082, "##ast": 14083, "alternatively": 14084, "nat": 14085, "lowe": 14086, "lacks": 14087, "##ented": 14088, "pam": 14089, "tile": 14090, "concealed": 14091, "inferior": 14092, "abdullah": 14093, "residences": 14094, "tissues": 14095, "vengeance": 14096, "##ided": 14097, "moisture": 14098, "peculiar": 14099, "groove": 14100, "zip": 14101, "bologna": 14102, "jennings": 14103, "ninja": 14104, "oversaw": 14105, "zombies": 14106, "pumping": 14107, "batch": 14108, "livingston": 14109, "emerald": 14110, "installations": 14111, "1797": 14112, "peel": 14113, "nitrogen": 14114, "rama": 14115, "##fying": 14116, "##star": 14117, "schooling": 14118, "strands": 14119, "responding": 14120, "werner": 14121, "##ost": 14122, "lime": 14123, "casa": 14124, "accurately": 14125, "targeting": 14126, "##rod": 14127, "underway": 14128, "##uru": 14129, "hemisphere": 14130, "lester": 14131, "##yard": 14132, "occupies": 14133, "2d": 14134, "griffith": 14135, "angrily": 14136, "reorganized": 14137, "##owing": 14138, "courtney": 14139, "deposited": 14140, "##dd": 14141, "##30": 14142, "estadio": 14143, "##ifies": 14144, "dunn": 14145, "exiled": 14146, "##ying": 14147, "checks": 14148, "##combe": 14149, "##о": 14150, "##fly": 14151, "successes": 14152, "unexpectedly": 14153, "blu": 14154, "assessed": 14155, "##flower": 14156, "##ه": 14157, "observing": 14158, "sacked": 14159, "spiders": 14160, "kn": 14161, "##tail": 14162, "mu": 14163, "nodes": 14164, "prosperity": 14165, "audrey": 14166, "divisional": 14167, "155": 14168, "broncos": 14169, "tangled": 14170, "adjust": 14171, "feeds": 14172, "erosion": 14173, "paolo": 14174, "surf": 14175, "directory": 14176, "snatched": 14177, "humid": 14178, "admiralty": 14179, "screwed": 14180, "gt": 14181, "reddish": 14182, "##nese": 14183, "modules": 14184, "trench": 14185, "lamps": 14186, "bind": 14187, "leah": 14188, "bucks": 14189, "competes": 14190, "##nz": 14191, "##form": 14192, "transcription": 14193, "##uc": 14194, "isles": 14195, "violently": 14196, "clutching": 14197, "pga": 14198, "cyclist": 14199, "inflation": 14200, "flats": 14201, "ragged": 14202, "unnecessary": 14203, "##hian": 14204, "stubborn": 14205, "coordinated": 14206, "harriet": 14207, "baba": 14208, "disqualified": 14209, "330": 14210, "insect": 14211, "wolfe": 14212, "##fies": 14213, "reinforcements": 14214, "rocked": 14215, "duel": 14216, "winked": 14217, "embraced": 14218, "bricks": 14219, "##raj": 14220, "hiatus": 14221, "defeats": 14222, "pending": 14223, "brightly": 14224, "jealousy": 14225, "##xton": 14226, "##hm": 14227, "##uki": 14228, "lena": 14229, "gdp": 14230, "colorful": 14231, "##dley": 14232, "stein": 14233, "kidney": 14234, "##shu": 14235, "underwear": 14236, "wanderers": 14237, "##haw": 14238, "##icus": 14239, "guardians": 14240, "m³": 14241, "roared": 14242, "habits": 14243, "##wise": 14244, "permits": 14245, "gp": 14246, "uranium": 14247, "punished": 14248, "disguise": 14249, "bundesliga": 14250, "elise": 14251, "dundee": 14252, "erotic": 14253, "partisan": 14254, "pi": 14255, "collectors": 14256, "float": 14257, "individually": 14258, "rendering": 14259, "behavioral": 14260, "bucharest": 14261, "ser": 14262, "hare": 14263, "valerie": 14264, "corporal": 14265, "nutrition": 14266, "proportional": 14267, "##isa": 14268, "immense": 14269, "##kis": 14270, "pavement": 14271, "##zie": 14272, "##eld": 14273, "sutherland": 14274, "crouched": 14275, "1775": 14276, "##lp": 14277, "suzuki": 14278, "trades": 14279, "endurance": 14280, "operas": 14281, "crosby": 14282, "prayed": 14283, "priory": 14284, "rory": 14285, "socially": 14286, "##urn": 14287, "gujarat": 14288, "##pu": 14289, "walton": 14290, "cube": 14291, "pasha": 14292, "privilege": 14293, "lennon": 14294, "floods": 14295, "thorne": 14296, "waterfall": 14297, "nipple": 14298, "scouting": 14299, "approve": 14300, "##lov": 14301, "minorities": 14302, "voter": 14303, "dwight": 14304, "extensions": 14305, "assure": 14306, "ballroom": 14307, "slap": 14308, "dripping": 14309, "privileges": 14310, "rejoined": 14311, "confessed": 14312, "demonstrating": 14313, "patriotic": 14314, "yell": 14315, "investor": 14316, "##uth": 14317, "pagan": 14318, "slumped": 14319, "squares": 14320, "##cle": 14321, "##kins": 14322, "confront": 14323, "bert": 14324, "embarrassment": 14325, "##aid": 14326, "aston": 14327, "urging": 14328, "sweater": 14329, "starr": 14330, "yuri": 14331, "brains": 14332, "williamson": 14333, "commuter": 14334, "mortar": 14335, "structured": 14336, "selfish": 14337, "exports": 14338, "##jon": 14339, "cds": 14340, "##him": 14341, "unfinished": 14342, "##rre": 14343, "mortgage": 14344, "destinations": 14345, "##nagar": 14346, "canoe": 14347, "solitary": 14348, "buchanan": 14349, "delays": 14350, "magistrate": 14351, "fk": 14352, "##pling": 14353, "motivation": 14354, "##lier": 14355, "##vier": 14356, "recruiting": 14357, "assess": 14358, "##mouth": 14359, "malik": 14360, "antique": 14361, "1791": 14362, "pius": 14363, "rahman": 14364, "reich": 14365, "tub": 14366, "zhou": 14367, "smashed": 14368, "airs": 14369, "galway": 14370, "xii": 14371, "conditioning": 14372, "honduras": 14373, "discharged": 14374, "dexter": 14375, "##pf": 14376, "lionel": 14377, "129": 14378, "debates": 14379, "lemon": 14380, "tiffany": 14381, "volunteered": 14382, "dom": 14383, "dioxide": 14384, "procession": 14385, "devi": 14386, "sic": 14387, "tremendous": 14388, "advertisements": 14389, "colts": 14390, "transferring": 14391, "verdict": 14392, "hanover": 14393, "decommissioned": 14394, "utter": 14395, "relate": 14396, "pac": 14397, "racism": 14398, "##top": 14399, "beacon": 14400, "limp": 14401, "similarity": 14402, "terra": 14403, "occurrence": 14404, "ant": 14405, "##how": 14406, "becky": 14407, "capt": 14408, "updates": 14409, "armament": 14410, "richie": 14411, "pal": 14412, "##graph": 14413, "halloween": 14414, "mayo": 14415, "##ssen": 14416, "##bone": 14417, "cara": 14418, "serena": 14419, "fcc": 14420, "dolls": 14421, "obligations": 14422, "##dling": 14423, "violated": 14424, "lafayette": 14425, "jakarta": 14426, "exploitation": 14427, "##ime": 14428, "infamous": 14429, "iconic": 14430, "##lah": 14431, "##park": 14432, "kitty": 14433, "moody": 14434, "reginald": 14435, "dread": 14436, "spill": 14437, "crystals": 14438, "olivier": 14439, "modeled": 14440, "bluff": 14441, "equilibrium": 14442, "separating": 14443, "notices": 14444, "ordnance": 14445, "extinction": 14446, "onset": 14447, "cosmic": 14448, "attachment": 14449, "sammy": 14450, "expose": 14451, "privy": 14452, "anchored": 14453, "##bil": 14454, "abbott": 14455, "admits": 14456, "bending": 14457, "baritone": 14458, "emmanuel": 14459, "policeman": 14460, "vaughan": 14461, "winged": 14462, "climax": 14463, "dresses": 14464, "denny": 14465, "polytechnic": 14466, "mohamed": 14467, "burmese": 14468, "authentic": 14469, "nikki": 14470, "genetics": 14471, "grandparents": 14472, "homestead": 14473, "gaza": 14474, "postponed": 14475, "metacritic": 14476, "una": 14477, "##sby": 14478, "##bat": 14479, "unstable": 14480, "dissertation": 14481, "##rial": 14482, "##cian": 14483, "curls": 14484, "obscure": 14485, "uncovered": 14486, "bronx": 14487, "praying": 14488, "disappearing": 14489, "##hoe": 14490, "prehistoric": 14491, "coke": 14492, "turret": 14493, "mutations": 14494, "nonprofit": 14495, "pits": 14496, "monaco": 14497, "##ي": 14498, "##usion": 14499, "prominently": 14500, "dispatched": 14501, "podium": 14502, "##mir": 14503, "uci": 14504, "##uation": 14505, "133": 14506, "fortifications": 14507, "birthplace": 14508, "kendall": 14509, "##lby": 14510, "##oll": 14511, "preacher": 14512, "rack": 14513, "goodman": 14514, "##rman": 14515, "persistent": 14516, "##ott": 14517, "countless": 14518, "jaime": 14519, "recorder": 14520, "lexington": 14521, "persecution": 14522, "jumps": 14523, "renewal": 14524, "wagons": 14525, "##11": 14526, "crushing": 14527, "##holder": 14528, "decorations": 14529, "##lake": 14530, "abundance": 14531, "wrath": 14532, "laundry": 14533, "£1": 14534, "garde": 14535, "##rp": 14536, "jeanne": 14537, "beetles": 14538, "peasant": 14539, "##sl": 14540, "splitting": 14541, "caste": 14542, "sergei": 14543, "##rer": 14544, "##ema": 14545, "scripts": 14546, "##ively": 14547, "rub": 14548, "satellites": 14549, "##vor": 14550, "inscribed": 14551, "verlag": 14552, "scrapped": 14553, "gale": 14554, "packages": 14555, "chick": 14556, "potato": 14557, "slogan": 14558, "kathleen": 14559, "arabs": 14560, "##culture": 14561, "counterparts": 14562, "reminiscent": 14563, "choral": 14564, "##tead": 14565, "rand": 14566, "retains": 14567, "bushes": 14568, "dane": 14569, "accomplish": 14570, "courtesy": 14571, "closes": 14572, "##oth": 14573, "slaughter": 14574, "hague": 14575, "krakow": 14576, "lawson": 14577, "tailed": 14578, "elias": 14579, "ginger": 14580, "##ttes": 14581, "canopy": 14582, "betrayal": 14583, "rebuilding": 14584, "turf": 14585, "##hof": 14586, "frowning": 14587, "allegiance": 14588, "brigades": 14589, "kicks": 14590, "rebuild": 14591, "polls": 14592, "alias": 14593, "nationalism": 14594, "td": 14595, "rowan": 14596, "audition": 14597, "bowie": 14598, "fortunately": 14599, "recognizes": 14600, "harp": 14601, "dillon": 14602, "horrified": 14603, "##oro": 14604, "renault": 14605, "##tics": 14606, "ropes": 14607, "##α": 14608, "presumed": 14609, "rewarded": 14610, "infrared": 14611, "wiping": 14612, "accelerated": 14613, "illustration": 14614, "##rid": 14615, "presses": 14616, "practitioners": 14617, "badminton": 14618, "##iard": 14619, "detained": 14620, "##tera": 14621, "recognizing": 14622, "relates": 14623, "misery": 14624, "##sies": 14625, "##tly": 14626, "reproduction": 14627, "piercing": 14628, "potatoes": 14629, "thornton": 14630, "esther": 14631, "manners": 14632, "hbo": 14633, "##aan": 14634, "ours": 14635, "bullshit": 14636, "ernie": 14637, "perennial": 14638, "sensitivity": 14639, "illuminated": 14640, "rupert": 14641, "##jin": 14642, "##iss": 14643, "##ear": 14644, "rfc": 14645, "nassau": 14646, "##dock": 14647, "staggered": 14648, "socialism": 14649, "##haven": 14650, "appointments": 14651, "nonsense": 14652, "prestige": 14653, "sharma": 14654, "haul": 14655, "##tical": 14656, "solidarity": 14657, "gps": 14658, "##ook": 14659, "##rata": 14660, "igor": 14661, "pedestrian": 14662, "##uit": 14663, "baxter": 14664, "tenants": 14665, "wires": 14666, "medication": 14667, "unlimited": 14668, "guiding": 14669, "impacts": 14670, "diabetes": 14671, "##rama": 14672, "sasha": 14673, "pas": 14674, "clive": 14675, "extraction": 14676, "131": 14677, "continually": 14678, "constraints": 14679, "##bilities": 14680, "sonata": 14681, "hunted": 14682, "sixteenth": 14683, "chu": 14684, "planting": 14685, "quote": 14686, "mayer": 14687, "pretended": 14688, "abs": 14689, "spat": 14690, "##hua": 14691, "ceramic": 14692, "##cci": 14693, "curtains": 14694, "pigs": 14695, "pitching": 14696, "##dad": 14697, "latvian": 14698, "sore": 14699, "dayton": 14700, "##sted": 14701, "##qi": 14702, "patrols": 14703, "slice": 14704, "playground": 14705, "##nted": 14706, "shone": 14707, "stool": 14708, "apparatus": 14709, "inadequate": 14710, "mates": 14711, "treason": 14712, "##ija": 14713, "desires": 14714, "##liga": 14715, "##croft": 14716, "somalia": 14717, "laurent": 14718, "mir": 14719, "leonardo": 14720, "oracle": 14721, "grape": 14722, "obliged": 14723, "chevrolet": 14724, "thirteenth": 14725, "stunning": 14726, "enthusiastic": 14727, "##ede": 14728, "accounted": 14729, "concludes": 14730, "currents": 14731, "basil": 14732, "##kovic": 14733, "drought": 14734, "##rica": 14735, "mai": 14736, "##aire": 14737, "shove": 14738, "posting": 14739, "##shed": 14740, "pilgrimage": 14741, "humorous": 14742, "packing": 14743, "fry": 14744, "pencil": 14745, "wines": 14746, "smells": 14747, "144": 14748, "marilyn": 14749, "aching": 14750, "newest": 14751, "clung": 14752, "bon": 14753, "neighbours": 14754, "sanctioned": 14755, "##pie": 14756, "mug": 14757, "##stock": 14758, "drowning": 14759, "##mma": 14760, "hydraulic": 14761, "##vil": 14762, "hiring": 14763, "reminder": 14764, "lilly": 14765, "investigators": 14766, "##ncies": 14767, "sour": 14768, "##eous": 14769, "compulsory": 14770, "packet": 14771, "##rion": 14772, "##graphic": 14773, "##elle": 14774, "cannes": 14775, "##inate": 14776, "depressed": 14777, "##rit": 14778, "heroic": 14779, "importantly": 14780, "theresa": 14781, "##tled": 14782, "conway": 14783, "saturn": 14784, "marginal": 14785, "rae": 14786, "##xia": 14787, "corresponds": 14788, "royce": 14789, "pact": 14790, "jasper": 14791, "explosives": 14792, "packaging": 14793, "aluminium": 14794, "##ttered": 14795, "denotes": 14796, "rhythmic": 14797, "spans": 14798, "assignments": 14799, "hereditary": 14800, "outlined": 14801, "originating": 14802, "sundays": 14803, "lad": 14804, "reissued": 14805, "greeting": 14806, "beatrice": 14807, "##dic": 14808, "pillar": 14809, "marcos": 14810, "plots": 14811, "handbook": 14812, "alcoholic": 14813, "judiciary": 14814, "avant": 14815, "slides": 14816, "extract": 14817, "masculine": 14818, "blur": 14819, "##eum": 14820, "##force": 14821, "homage": 14822, "trembled": 14823, "owens": 14824, "hymn": 14825, "trey": 14826, "omega": 14827, "signaling": 14828, "socks": 14829, "accumulated": 14830, "reacted": 14831, "attic": 14832, "theo": 14833, "lining": 14834, "angie": 14835, "distraction": 14836, "primera": 14837, "talbot": 14838, "##key": 14839, "1200": 14840, "ti": 14841, "creativity": 14842, "billed": 14843, "##hey": 14844, "deacon": 14845, "eduardo": 14846, "identifies": 14847, "proposition": 14848, "dizzy": 14849, "gunner": 14850, "hogan": 14851, "##yam": 14852, "##pping": 14853, "##hol": 14854, "ja": 14855, "##chan": 14856, "jensen": 14857, "reconstructed": 14858, "##berger": 14859, "clearance": 14860, "darius": 14861, "##nier": 14862, "abe": 14863, "harlem": 14864, "plea": 14865, "dei": 14866, "circled": 14867, "emotionally": 14868, "notation": 14869, "fascist": 14870, "neville": 14871, "exceeded": 14872, "upwards": 14873, "viable": 14874, "ducks": 14875, "##fo": 14876, "workforce": 14877, "racer": 14878, "limiting": 14879, "shri": 14880, "##lson": 14881, "possesses": 14882, "1600": 14883, "kerr": 14884, "moths": 14885, "devastating": 14886, "laden": 14887, "disturbing": 14888, "locking": 14889, "##cture": 14890, "gal": 14891, "fearing": 14892, "accreditation": 14893, "flavor": 14894, "aide": 14895, "1870s": 14896, "mountainous": 14897, "##baum": 14898, "melt": 14899, "##ures": 14900, "motel": 14901, "texture": 14902, "servers": 14903, "soda": 14904, "##mb": 14905, "herd": 14906, "##nium": 14907, "erect": 14908, "puzzled": 14909, "hum": 14910, "peggy": 14911, "examinations": 14912, "gould": 14913, "testified": 14914, "geoff": 14915, "ren": 14916, "devised": 14917, "sacks": 14918, "##law": 14919, "denial": 14920, "posters": 14921, "grunted": 14922, "cesar": 14923, "tutor": 14924, "ec": 14925, "gerry": 14926, "offerings": 14927, "byrne": 14928, "falcons": 14929, "combinations": 14930, "ct": 14931, "incoming": 14932, "pardon": 14933, "rocking": 14934, "26th": 14935, "avengers": 14936, "flared": 14937, "mankind": 14938, "seller": 14939, "uttar": 14940, "loch": 14941, "nadia": 14942, "stroking": 14943, "exposing": 14944, "##hd": 14945, "fertile": 14946, "ancestral": 14947, "instituted": 14948, "##has": 14949, "noises": 14950, "prophecy": 14951, "taxation": 14952, "eminent": 14953, "vivid": 14954, "pol": 14955, "##bol": 14956, "dart": 14957, "indirect": 14958, "multimedia": 14959, "notebook": 14960, "upside": 14961, "displaying": 14962, "adrenaline": 14963, "referenced": 14964, "geometric": 14965, "##iving": 14966, "progression": 14967, "##ddy": 14968, "blunt": 14969, "announce": 14970, "##far": 14971, "implementing": 14972, "##lav": 14973, "aggression": 14974, "liaison": 14975, "cooler": 14976, "cares": 14977, "headache": 14978, "plantations": 14979, "gorge": 14980, "dots": 14981, "impulse": 14982, "thickness": 14983, "ashamed": 14984, "averaging": 14985, "kathy": 14986, "obligation": 14987, "precursor": 14988, "137": 14989, "fowler": 14990, "symmetry": 14991, "thee": 14992, "225": 14993, "hears": 14994, "##rai": 14995, "undergoing": 14996, "ads": 14997, "butcher": 14998, "bowler": 14999, "##lip": 15000, "cigarettes": 15001, "subscription": 15002, "goodness": 15003, "##ically": 15004, "browne": 15005, "##hos": 15006, "##tech": 15007, "kyoto": 15008, "donor": 15009, "##erty": 15010, "damaging": 15011, "friction": 15012, "drifting": 15013, "expeditions": 15014, "hardened": 15015, "prostitution": 15016, "152": 15017, "fauna": 15018, "blankets": 15019, "claw": 15020, "tossing": 15021, "snarled": 15022, "butterflies": 15023, "recruits": 15024, "investigative": 15025, "coated": 15026, "healed": 15027, "138": 15028, "communal": 15029, "hai": 15030, "xiii": 15031, "academics": 15032, "boone": 15033, "psychologist": 15034, "restless": 15035, "lahore": 15036, "stephens": 15037, "mba": 15038, "brendan": 15039, "foreigners": 15040, "printer": 15041, "##pc": 15042, "ached": 15043, "explode": 15044, "27th": 15045, "deed": 15046, "scratched": 15047, "dared": 15048, "##pole": 15049, "cardiac": 15050, "1780": 15051, "okinawa": 15052, "proto": 15053, "commando": 15054, "compelled": 15055, "oddly": 15056, "electrons": 15057, "##base": 15058, "replica": 15059, "thanksgiving": 15060, "##rist": 15061, "sheila": 15062, "deliberate": 15063, "stafford": 15064, "tidal": 15065, "representations": 15066, "hercules": 15067, "ou": 15068, "##path": 15069, "##iated": 15070, "kidnapping": 15071, "lenses": 15072, "##tling": 15073, "deficit": 15074, "samoa": 15075, "mouths": 15076, "consuming": 15077, "computational": 15078, "maze": 15079, "granting": 15080, "smirk": 15081, "razor": 15082, "fixture": 15083, "ideals": 15084, "inviting": 15085, "aiden": 15086, "nominal": 15087, "##vs": 15088, "issuing": 15089, "julio": 15090, "pitt": 15091, "ramsey": 15092, "docks": 15093, "##oss": 15094, "exhaust": 15095, "##owed": 15096, "bavarian": 15097, "draped": 15098, "anterior": 15099, "mating": 15100, "ethiopian": 15101, "explores": 15102, "noticing": 15103, "##nton": 15104, "discarded": 15105, "convenience": 15106, "hoffman": 15107, "endowment": 15108, "beasts": 15109, "cartridge": 15110, "mormon": 15111, "paternal": 15112, "probe": 15113, "sleeves": 15114, "interfere": 15115, "lump": 15116, "deadline": 15117, "##rail": 15118, "jenks": 15119, "bulldogs": 15120, "scrap": 15121, "alternating": 15122, "justified": 15123, "reproductive": 15124, "nam": 15125, "seize": 15126, "descending": 15127, "secretariat": 15128, "kirby": 15129, "coupe": 15130, "grouped": 15131, "smash": 15132, "panther": 15133, "sedan": 15134, "tapping": 15135, "##18": 15136, "lola": 15137, "cheer": 15138, "germanic": 15139, "unfortunate": 15140, "##eter": 15141, "unrelated": 15142, "##fan": 15143, "subordinate": 15144, "##sdale": 15145, "suzanne": 15146, "advertisement": 15147, "##ility": 15148, "horsepower": 15149, "##lda": 15150, "cautiously": 15151, "discourse": 15152, "luigi": 15153, "##mans": 15154, "##fields": 15155, "noun": 15156, "prevalent": 15157, "mao": 15158, "schneider": 15159, "everett": 15160, "surround": 15161, "governorate": 15162, "kira": 15163, "##avia": 15164, "westward": 15165, "##take": 15166, "misty": 15167, "rails": 15168, "sustainability": 15169, "134": 15170, "unused": 15171, "##rating": 15172, "packs": 15173, "toast": 15174, "unwilling": 15175, "regulate": 15176, "thy": 15177, "suffrage": 15178, "nile": 15179, "awe": 15180, "assam": 15181, "definitions": 15182, "travelers": 15183, "affordable": 15184, "##rb": 15185, "conferred": 15186, "sells": 15187, "undefeated": 15188, "beneficial": 15189, "torso": 15190, "basal": 15191, "repeating": 15192, "remixes": 15193, "##pass": 15194, "bahrain": 15195, "cables": 15196, "fang": 15197, "##itated": 15198, "excavated": 15199, "numbering": 15200, "statutory": 15201, "##rey": 15202, "deluxe": 15203, "##lian": 15204, "forested": 15205, "ramirez": 15206, "derbyshire": 15207, "zeus": 15208, "slamming": 15209, "transfers": 15210, "astronomer": 15211, "banana": 15212, "lottery": 15213, "berg": 15214, "histories": 15215, "bamboo": 15216, "##uchi": 15217, "resurrection": 15218, "posterior": 15219, "bowls": 15220, "vaguely": 15221, "##thi": 15222, "thou": 15223, "preserving": 15224, "tensed": 15225, "offence": 15226, "##inas": 15227, "meyrick": 15228, "callum": 15229, "ridden": 15230, "watt": 15231, "langdon": 15232, "tying": 15233, "lowland": 15234, "snorted": 15235, "daring": 15236, "truman": 15237, "##hale": 15238, "##girl": 15239, "aura": 15240, "overly": 15241, "filing": 15242, "weighing": 15243, "goa": 15244, "infections": 15245, "philanthropist": 15246, "saunders": 15247, "eponymous": 15248, "##owski": 15249, "latitude": 15250, "perspectives": 15251, "reviewing": 15252, "mets": 15253, "commandant": 15254, "radial": 15255, "##kha": 15256, "flashlight": 15257, "reliability": 15258, "koch": 15259, "vowels": 15260, "amazed": 15261, "ada": 15262, "elaine": 15263, "supper": 15264, "##rth": 15265, "##encies": 15266, "predator": 15267, "debated": 15268, "soviets": 15269, "cola": 15270, "##boards": 15271, "##nah": 15272, "compartment": 15273, "crooked": 15274, "arbitrary": 15275, "fourteenth": 15276, "##ctive": 15277, "havana": 15278, "majors": 15279, "steelers": 15280, "clips": 15281, "profitable": 15282, "ambush": 15283, "exited": 15284, "packers": 15285, "##tile": 15286, "nude": 15287, "cracks": 15288, "fungi": 15289, "##е": 15290, "limb": 15291, "trousers": 15292, "josie": 15293, "shelby": 15294, "tens": 15295, "frederic": 15296, "##ος": 15297, "definite": 15298, "smoothly": 15299, "constellation": 15300, "insult": 15301, "baton": 15302, "discs": 15303, "lingering": 15304, "##nco": 15305, "conclusions": 15306, "lent": 15307, "staging": 15308, "becker": 15309, "grandpa": 15310, "shaky": 15311, "##tron": 15312, "einstein": 15313, "obstacles": 15314, "sk": 15315, "adverse": 15316, "elle": 15317, "economically": 15318, "##moto": 15319, "mccartney": 15320, "thor": 15321, "dismissal": 15322, "motions": 15323, "readings": 15324, "nostrils": 15325, "treatise": 15326, "##pace": 15327, "squeezing": 15328, "evidently": 15329, "prolonged": 15330, "1783": 15331, "venezuelan": 15332, "je": 15333, "marguerite": 15334, "beirut": 15335, "takeover": 15336, "shareholders": 15337, "##vent": 15338, "denise": 15339, "digit": 15340, "airplay": 15341, "norse": 15342, "##bbling": 15343, "imaginary": 15344, "pills": 15345, "hubert": 15346, "blaze": 15347, "vacated": 15348, "eliminating": 15349, "##ello": 15350, "vine": 15351, "mansfield": 15352, "##tty": 15353, "retrospective": 15354, "barrow": 15355, "borne": 15356, "clutch": 15357, "bail": 15358, "forensic": 15359, "weaving": 15360, "##nett": 15361, "##witz": 15362, "desktop": 15363, "citadel": 15364, "promotions": 15365, "worrying": 15366, "dorset": 15367, "ieee": 15368, "subdivided": 15369, "##iating": 15370, "manned": 15371, "expeditionary": 15372, "pickup": 15373, "synod": 15374, "chuckle": 15375, "185": 15376, "barney": 15377, "##rz": 15378, "##ffin": 15379, "functionality": 15380, "karachi": 15381, "litigation": 15382, "meanings": 15383, "uc": 15384, "lick": 15385, "turbo": 15386, "anders": 15387, "##ffed": 15388, "execute": 15389, "curl": 15390, "oppose": 15391, "ankles": 15392, "typhoon": 15393, "##د": 15394, "##ache": 15395, "##asia": 15396, "linguistics": 15397, "compassion": 15398, "pressures": 15399, "grazing": 15400, "perfection": 15401, "##iting": 15402, "immunity": 15403, "monopoly": 15404, "muddy": 15405, "backgrounds": 15406, "136": 15407, "namibia": 15408, "francesca": 15409, "monitors": 15410, "attracting": 15411, "stunt": 15412, "tuition": 15413, "##ии": 15414, "vegetable": 15415, "##mates": 15416, "##quent": 15417, "mgm": 15418, "jen": 15419, "complexes": 15420, "forts": 15421, "##ond": 15422, "cellar": 15423, "bites": 15424, "seventeenth": 15425, "royals": 15426, "flemish": 15427, "failures": 15428, "mast": 15429, "charities": 15430, "##cular": 15431, "peruvian": 15432, "capitals": 15433, "macmillan": 15434, "ipswich": 15435, "outward": 15436, "frigate": 15437, "postgraduate": 15438, "folds": 15439, "employing": 15440, "##ouse": 15441, "concurrently": 15442, "fiery": 15443, "##tai": 15444, "contingent": 15445, "nightmares": 15446, "monumental": 15447, "nicaragua": 15448, "##kowski": 15449, "lizard": 15450, "mal": 15451, "fielding": 15452, "gig": 15453, "reject": 15454, "##pad": 15455, "harding": 15456, "##ipe": 15457, "coastline": 15458, "##cin": 15459, "##nos": 15460, "beethoven": 15461, "humphrey": 15462, "innovations": 15463, "##tam": 15464, "##nge": 15465, "norris": 15466, "doris": 15467, "solicitor": 15468, "huang": 15469, "obey": 15470, "141": 15471, "##lc": 15472, "niagara": 15473, "##tton": 15474, "shelves": 15475, "aug": 15476, "bourbon": 15477, "curry": 15478, "nightclub": 15479, "specifications": 15480, "hilton": 15481, "##ndo": 15482, "centennial": 15483, "dispersed": 15484, "worm": 15485, "neglected": 15486, "briggs": 15487, "sm": 15488, "font": 15489, "kuala": 15490, "uneasy": 15491, "plc": 15492, "##nstein": 15493, "##bound": 15494, "##aking": 15495, "##burgh": 15496, "awaiting": 15497, "pronunciation": 15498, "##bbed": 15499, "##quest": 15500, "eh": 15501, "optimal": 15502, "zhu": 15503, "raped": 15504, "greens": 15505, "presided": 15506, "brenda": 15507, "worries": 15508, "##life": 15509, "venetian": 15510, "marxist": 15511, "turnout": 15512, "##lius": 15513, "refined": 15514, "braced": 15515, "sins": 15516, "grasped": 15517, "sunderland": 15518, "nickel": 15519, "speculated": 15520, "lowell": 15521, "cyrillic": 15522, "communism": 15523, "fundraising": 15524, "resembling": 15525, "colonists": 15526, "mutant": 15527, "freddie": 15528, "usc": 15529, "##mos": 15530, "gratitude": 15531, "##run": 15532, "mural": 15533, "##lous": 15534, "chemist": 15535, "wi": 15536, "reminds": 15537, "28th": 15538, "steals": 15539, "tess": 15540, "pietro": 15541, "##ingen": 15542, "promoter": 15543, "ri": 15544, "microphone": 15545, "honoured": 15546, "rai": 15547, "sant": 15548, "##qui": 15549, "feather": 15550, "##nson": 15551, "burlington": 15552, "kurdish": 15553, "terrorists": 15554, "deborah": 15555, "sickness": 15556, "##wed": 15557, "##eet": 15558, "hazard": 15559, "irritated": 15560, "desperation": 15561, "veil": 15562, "clarity": 15563, "##rik": 15564, "jewels": 15565, "xv": 15566, "##gged": 15567, "##ows": 15568, "##cup": 15569, "berkshire": 15570, "unfair": 15571, "mysteries": 15572, "orchid": 15573, "winced": 15574, "exhaustion": 15575, "renovations": 15576, "stranded": 15577, "obe": 15578, "infinity": 15579, "##nies": 15580, "adapt": 15581, "redevelopment": 15582, "thanked": 15583, "registry": 15584, "olga": 15585, "domingo": 15586, "noir": 15587, "tudor": 15588, "ole": 15589, "##atus": 15590, "commenting": 15591, "behaviors": 15592, "##ais": 15593, "crisp": 15594, "pauline": 15595, "probable": 15596, "stirling": 15597, "wigan": 15598, "##bian": 15599, "paralympics": 15600, "panting": 15601, "surpassed": 15602, "##rew": 15603, "luca": 15604, "barred": 15605, "pony": 15606, "famed": 15607, "##sters": 15608, "cassandra": 15609, "waiter": 15610, "carolyn": 15611, "exported": 15612, "##orted": 15613, "andres": 15614, "destructive": 15615, "deeds": 15616, "jonah": 15617, "castles": 15618, "vacancy": 15619, "suv": 15620, "##glass": 15621, "1788": 15622, "orchard": 15623, "yep": 15624, "famine": 15625, "belarusian": 15626, "sprang": 15627, "##forth": 15628, "skinny": 15629, "##mis": 15630, "administrators": 15631, "rotterdam": 15632, "zambia": 15633, "zhao": 15634, "boiler": 15635, "discoveries": 15636, "##ride": 15637, "##physics": 15638, "lucius": 15639, "disappointing": 15640, "outreach": 15641, "spoon": 15642, "##frame": 15643, "qualifications": 15644, "unanimously": 15645, "enjoys": 15646, "regency": 15647, "##iidae": 15648, "stade": 15649, "realism": 15650, "veterinary": 15651, "rodgers": 15652, "dump": 15653, "alain": 15654, "chestnut": 15655, "castile": 15656, "censorship": 15657, "rumble": 15658, "gibbs": 15659, "##itor": 15660, "communion": 15661, "reggae": 15662, "inactivated": 15663, "logs": 15664, "loads": 15665, "##houses": 15666, "homosexual": 15667, "##iano": 15668, "ale": 15669, "informs": 15670, "##cas": 15671, "phrases": 15672, "plaster": 15673, "linebacker": 15674, "ambrose": 15675, "kaiser": 15676, "fascinated": 15677, "850": 15678, "limerick": 15679, "recruitment": 15680, "forge": 15681, "mastered": 15682, "##nding": 15683, "leinster": 15684, "rooted": 15685, "threaten": 15686, "##strom": 15687, "borneo": 15688, "##hes": 15689, "suggestions": 15690, "scholarships": 15691, "propeller": 15692, "documentaries": 15693, "patronage": 15694, "coats": 15695, "constructing": 15696, "invest": 15697, "neurons": 15698, "comet": 15699, "entirety": 15700, "shouts": 15701, "identities": 15702, "annoying": 15703, "unchanged": 15704, "wary": 15705, "##antly": 15706, "##ogy": 15707, "neat": 15708, "oversight": 15709, "##kos": 15710, "phillies": 15711, "replay": 15712, "constance": 15713, "##kka": 15714, "incarnation": 15715, "humble": 15716, "skies": 15717, "minus": 15718, "##acy": 15719, "smithsonian": 15720, "##chel": 15721, "guerrilla": 15722, "jar": 15723, "cadets": 15724, "##plate": 15725, "surplus": 15726, "audit": 15727, "##aru": 15728, "cracking": 15729, "joanna": 15730, "louisa": 15731, "pacing": 15732, "##lights": 15733, "intentionally": 15734, "##iri": 15735, "diner": 15736, "nwa": 15737, "imprint": 15738, "australians": 15739, "tong": 15740, "unprecedented": 15741, "bunker": 15742, "naive": 15743, "specialists": 15744, "ark": 15745, "nichols": 15746, "railing": 15747, "leaked": 15748, "pedal": 15749, "##uka": 15750, "shrub": 15751, "longing": 15752, "roofs": 15753, "v8": 15754, "captains": 15755, "neural": 15756, "tuned": 15757, "##ntal": 15758, "##jet": 15759, "emission": 15760, "medina": 15761, "frantic": 15762, "codex": 15763, "definitive": 15764, "sid": 15765, "abolition": 15766, "intensified": 15767, "stocks": 15768, "enrique": 15769, "sustain": 15770, "genoa": 15771, "oxide": 15772, "##written": 15773, "clues": 15774, "cha": 15775, "##gers": 15776, "tributaries": 15777, "fragment": 15778, "venom": 15779, "##rity": 15780, "##ente": 15781, "##sca": 15782, "muffled": 15783, "vain": 15784, "sire": 15785, "laos": 15786, "##ingly": 15787, "##hana": 15788, "hastily": 15789, "snapping": 15790, "surfaced": 15791, "sentiment": 15792, "motive": 15793, "##oft": 15794, "contests": 15795, "approximate": 15796, "mesa": 15797, "luckily": 15798, "dinosaur": 15799, "exchanges": 15800, "propelled": 15801, "accord": 15802, "bourne": 15803, "relieve": 15804, "tow": 15805, "masks": 15806, "offended": 15807, "##ues": 15808, "cynthia": 15809, "##mmer": 15810, "rains": 15811, "bartender": 15812, "zinc": 15813, "reviewers": 15814, "lois": 15815, "##sai": 15816, "legged": 15817, "arrogant": 15818, "rafe": 15819, "rosie": 15820, "comprise": 15821, "handicap": 15822, "blockade": 15823, "inlet": 15824, "lagoon": 15825, "copied": 15826, "drilling": 15827, "shelley": 15828, "petals": 15829, "##inian": 15830, "mandarin": 15831, "obsolete": 15832, "##inated": 15833, "onward": 15834, "arguably": 15835, "productivity": 15836, "cindy": 15837, "praising": 15838, "seldom": 15839, "busch": 15840, "discusses": 15841, "raleigh": 15842, "shortage": 15843, "ranged": 15844, "stanton": 15845, "encouragement": 15846, "firstly": 15847, "conceded": 15848, "overs": 15849, "temporal": 15850, "##uke": 15851, "cbe": 15852, "##bos": 15853, "woo": 15854, "certainty": 15855, "pumps": 15856, "##pton": 15857, "stalked": 15858, "##uli": 15859, "lizzie": 15860, "periodic": 15861, "thieves": 15862, "weaker": 15863, "##night": 15864, "gases": 15865, "shoving": 15866, "chooses": 15867, "wc": 15868, "##chemical": 15869, "prompting": 15870, "weights": 15871, "##kill": 15872, "robust": 15873, "flanked": 15874, "sticky": 15875, "hu": 15876, "tuberculosis": 15877, "##eb": 15878, "##eal": 15879, "christchurch": 15880, "resembled": 15881, "wallet": 15882, "reese": 15883, "inappropriate": 15884, "pictured": 15885, "distract": 15886, "fixing": 15887, "fiddle": 15888, "giggled": 15889, "burger": 15890, "heirs": 15891, "hairy": 15892, "mechanic": 15893, "torque": 15894, "apache": 15895, "obsessed": 15896, "chiefly": 15897, "cheng": 15898, "logging": 15899, "##tag": 15900, "extracted": 15901, "meaningful": 15902, "numb": 15903, "##vsky": 15904, "gloucestershire": 15905, "reminding": 15906, "##bay": 15907, "unite": 15908, "##lit": 15909, "breeds": 15910, "diminished": 15911, "clown": 15912, "glove": 15913, "1860s": 15914, "##ن": 15915, "##ug": 15916, "archibald": 15917, "focal": 15918, "freelance": 15919, "sliced": 15920, "depiction": 15921, "##yk": 15922, "organism": 15923, "switches": 15924, "sights": 15925, "stray": 15926, "crawling": 15927, "##ril": 15928, "lever": 15929, "leningrad": 15930, "interpretations": 15931, "loops": 15932, "anytime": 15933, "reel": 15934, "alicia": 15935, "delighted": 15936, "##ech": 15937, "inhaled": 15938, "xiv": 15939, "suitcase": 15940, "bernie": 15941, "vega": 15942, "licenses": 15943, "northampton": 15944, "exclusion": 15945, "induction": 15946, "monasteries": 15947, "racecourse": 15948, "homosexuality": 15949, "##right": 15950, "##sfield": 15951, "##rky": 15952, "dimitri": 15953, "michele": 15954, "alternatives": 15955, "ions": 15956, "commentators": 15957, "genuinely": 15958, "objected": 15959, "pork": 15960, "hospitality": 15961, "fencing": 15962, "stephan": 15963, "warships": 15964, "peripheral": 15965, "wit": 15966, "drunken": 15967, "wrinkled": 15968, "quentin": 15969, "spends": 15970, "departing": 15971, "chung": 15972, "numerical": 15973, "spokesperson": 15974, "##zone": 15975, "johannesburg": 15976, "caliber": 15977, "killers": 15978, "##udge": 15979, "assumes": 15980, "neatly": 15981, "demographic": 15982, "abigail": 15983, "bloc": 15984, "##vel": 15985, "mounting": 15986, "##lain": 15987, "bentley": 15988, "slightest": 15989, "xu": 15990, "recipients": 15991, "##jk": 15992, "merlin": 15993, "##writer": 15994, "seniors": 15995, "prisons": 15996, "blinking": 15997, "hindwings": 15998, "flickered": 15999, "kappa": 16000, "##hel": 16001, "80s": 16002, "strengthening": 16003, "appealing": 16004, "brewing": 16005, "gypsy": 16006, "mali": 16007, "lashes": 16008, "hulk": 16009, "unpleasant": 16010, "harassment": 16011, "bio": 16012, "treaties": 16013, "predict": 16014, "instrumentation": 16015, "pulp": 16016, "troupe": 16017, "boiling": 16018, "mantle": 16019, "##ffe": 16020, "ins": 16021, "##vn": 16022, "dividing": 16023, "handles": 16024, "verbs": 16025, "##onal": 16026, "coconut": 16027, "senegal": 16028, "340": 16029, "thorough": 16030, "gum": 16031, "momentarily": 16032, "##sto": 16033, "cocaine": 16034, "panicked": 16035, "destined": 16036, "##turing": 16037, "teatro": 16038, "denying": 16039, "weary": 16040, "captained": 16041, "mans": 16042, "##hawks": 16043, "##code": 16044, "wakefield": 16045, "bollywood": 16046, "thankfully": 16047, "##16": 16048, "cyril": 16049, "##wu": 16050, "amendments": 16051, "##bahn": 16052, "consultation": 16053, "stud": 16054, "reflections": 16055, "kindness": 16056, "1787": 16057, "internally": 16058, "##ovo": 16059, "tex": 16060, "mosaic": 16061, "distribute": 16062, "paddy": 16063, "seeming": 16064, "143": 16065, "##hic": 16066, "piers": 16067, "##15": 16068, "##mura": 16069, "##verse": 16070, "popularly": 16071, "winger": 16072, "kang": 16073, "sentinel": 16074, "mccoy": 16075, "##anza": 16076, "covenant": 16077, "##bag": 16078, "verge": 16079, "fireworks": 16080, "suppress": 16081, "thrilled": 16082, "dominate": 16083, "##jar": 16084, "swansea": 16085, "##60": 16086, "142": 16087, "reconciliation": 16088, "##ndi": 16089, "stiffened": 16090, "cue": 16091, "dorian": 16092, "##uf": 16093, "damascus": 16094, "amor": 16095, "ida": 16096, "foremost": 16097, "##aga": 16098, "porsche": 16099, "unseen": 16100, "dir": 16101, "##had": 16102, "##azi": 16103, "stony": 16104, "lexi": 16105, "melodies": 16106, "##nko": 16107, "angular": 16108, "integer": 16109, "podcast": 16110, "ants": 16111, "inherent": 16112, "jaws": 16113, "justify": 16114, "persona": 16115, "##olved": 16116, "josephine": 16117, "##nr": 16118, "##ressed": 16119, "customary": 16120, "flashes": 16121, "gala": 16122, "cyrus": 16123, "glaring": 16124, "backyard": 16125, "ariel": 16126, "physiology": 16127, "greenland": 16128, "html": 16129, "stir": 16130, "avon": 16131, "atletico": 16132, "finch": 16133, "methodology": 16134, "ked": 16135, "##lent": 16136, "mas": 16137, "catholicism": 16138, "townsend": 16139, "branding": 16140, "quincy": 16141, "fits": 16142, "containers": 16143, "1777": 16144, "ashore": 16145, "aragon": 16146, "##19": 16147, "forearm": 16148, "poisoning": 16149, "##sd": 16150, "adopting": 16151, "conquer": 16152, "grinding": 16153, "amnesty": 16154, "keller": 16155, "finances": 16156, "evaluate": 16157, "forged": 16158, "lankan": 16159, "instincts": 16160, "##uto": 16161, "guam": 16162, "bosnian": 16163, "photographed": 16164, "workplace": 16165, "desirable": 16166, "protector": 16167, "##dog": 16168, "allocation": 16169, "intently": 16170, "encourages": 16171, "willy": 16172, "##sten": 16173, "bodyguard": 16174, "electro": 16175, "brighter": 16176, "##ν": 16177, "bihar": 16178, "##chev": 16179, "lasts": 16180, "opener": 16181, "amphibious": 16182, "sal": 16183, "verde": 16184, "arte": 16185, "##cope": 16186, "captivity": 16187, "vocabulary": 16188, "yields": 16189, "##tted": 16190, "agreeing": 16191, "desmond": 16192, "pioneered": 16193, "##chus": 16194, "strap": 16195, "campaigned": 16196, "railroads": 16197, "##ович": 16198, "emblem": 16199, "##dre": 16200, "stormed": 16201, "501": 16202, "##ulous": 16203, "marijuana": 16204, "northumberland": 16205, "##gn": 16206, "##nath": 16207, "bowen": 16208, "landmarks": 16209, "beaumont": 16210, "##qua": 16211, "danube": 16212, "##bler": 16213, "attorneys": 16214, "th": 16215, "ge": 16216, "flyers": 16217, "critique": 16218, "villains": 16219, "cass": 16220, "mutation": 16221, "acc": 16222, "##0s": 16223, "colombo": 16224, "mckay": 16225, "motif": 16226, "sampling": 16227, "concluding": 16228, "syndicate": 16229, "##rell": 16230, "neon": 16231, "stables": 16232, "ds": 16233, "warnings": 16234, "clint": 16235, "mourning": 16236, "wilkinson": 16237, "##tated": 16238, "merrill": 16239, "leopard": 16240, "evenings": 16241, "exhaled": 16242, "emil": 16243, "sonia": 16244, "ezra": 16245, "discrete": 16246, "stove": 16247, "farrell": 16248, "fifteenth": 16249, "prescribed": 16250, "superhero": 16251, "##rier": 16252, "worms": 16253, "helm": 16254, "wren": 16255, "##duction": 16256, "##hc": 16257, "expo": 16258, "##rator": 16259, "hq": 16260, "unfamiliar": 16261, "antony": 16262, "prevents": 16263, "acceleration": 16264, "fiercely": 16265, "mari": 16266, "painfully": 16267, "calculations": 16268, "cheaper": 16269, "ign": 16270, "clifton": 16271, "irvine": 16272, "davenport": 16273, "mozambique": 16274, "##np": 16275, "pierced": 16276, "##evich": 16277, "wonders": 16278, "##wig": 16279, "##cate": 16280, "##iling": 16281, "crusade": 16282, "ware": 16283, "##uel": 16284, "enzymes": 16285, "reasonably": 16286, "mls": 16287, "##coe": 16288, "mater": 16289, "ambition": 16290, "bunny": 16291, "eliot": 16292, "kernel": 16293, "##fin": 16294, "asphalt": 16295, "headmaster": 16296, "torah": 16297, "aden": 16298, "lush": 16299, "pins": 16300, "waived": 16301, "##care": 16302, "##yas": 16303, "joao": 16304, "substrate": 16305, "enforce": 16306, "##grad": 16307, "##ules": 16308, "alvarez": 16309, "selections": 16310, "epidemic": 16311, "tempted": 16312, "##bit": 16313, "bremen": 16314, "translates": 16315, "ensured": 16316, "waterfront": 16317, "29th": 16318, "forrest": 16319, "manny": 16320, "malone": 16321, "kramer": 16322, "reigning": 16323, "cookies": 16324, "simpler": 16325, "absorption": 16326, "205": 16327, "engraved": 16328, "##ffy": 16329, "evaluated": 16330, "1778": 16331, "haze": 16332, "146": 16333, "comforting": 16334, "crossover": 16335, "##abe": 16336, "thorn": 16337, "##rift": 16338, "##imo": 16339, "##pop": 16340, "suppression": 16341, "fatigue": 16342, "cutter": 16343, "##tr": 16344, "201": 16345, "wurttemberg": 16346, "##orf": 16347, "enforced": 16348, "hovering": 16349, "proprietary": 16350, "gb": 16351, "samurai": 16352, "syllable": 16353, "ascent": 16354, "lacey": 16355, "tick": 16356, "lars": 16357, "tractor": 16358, "merchandise": 16359, "rep": 16360, "bouncing": 16361, "defendants": 16362, "##yre": 16363, "huntington": 16364, "##ground": 16365, "##oko": 16366, "standardized": 16367, "##hor": 16368, "##hima": 16369, "assassinated": 16370, "nu": 16371, "predecessors": 16372, "rainy": 16373, "liar": 16374, "assurance": 16375, "lyrical": 16376, "##uga": 16377, "secondly": 16378, "flattened": 16379, "ios": 16380, "parameter": 16381, "undercover": 16382, "##mity": 16383, "bordeaux": 16384, "punish": 16385, "ridges": 16386, "markers": 16387, "exodus": 16388, "inactive": 16389, "hesitate": 16390, "debbie": 16391, "nyc": 16392, "pledge": 16393, "savoy": 16394, "nagar": 16395, "offset": 16396, "organist": 16397, "##tium": 16398, "hesse": 16399, "marin": 16400, "converting": 16401, "##iver": 16402, "diagram": 16403, "propulsion": 16404, "pu": 16405, "validity": 16406, "reverted": 16407, "supportive": 16408, "##dc": 16409, "ministries": 16410, "clans": 16411, "responds": 16412, "proclamation": 16413, "##inae": 16414, "##ø": 16415, "##rea": 16416, "ein": 16417, "pleading": 16418, "patriot": 16419, "sf": 16420, "birch": 16421, "islanders": 16422, "strauss": 16423, "hates": 16424, "##dh": 16425, "brandenburg": 16426, "concession": 16427, "rd": 16428, "##ob": 16429, "1900s": 16430, "killings": 16431, "textbook": 16432, "antiquity": 16433, "cinematography": 16434, "wharf": 16435, "embarrassing": 16436, "setup": 16437, "creed": 16438, "farmland": 16439, "inequality": 16440, "centred": 16441, "signatures": 16442, "fallon": 16443, "370": 16444, "##ingham": 16445, "##uts": 16446, "ceylon": 16447, "gazing": 16448, "directive": 16449, "laurie": 16450, "##tern": 16451, "globally": 16452, "##uated": 16453, "##dent": 16454, "allah": 16455, "excavation": 16456, "threads": 16457, "##cross": 16458, "148": 16459, "frantically": 16460, "icc": 16461, "utilize": 16462, "determines": 16463, "respiratory": 16464, "thoughtful": 16465, "receptions": 16466, "##dicate": 16467, "merging": 16468, "chandra": 16469, "seine": 16470, "147": 16471, "builders": 16472, "builds": 16473, "diagnostic": 16474, "dev": 16475, "visibility": 16476, "goddamn": 16477, "analyses": 16478, "dhaka": 16479, "cho": 16480, "proves": 16481, "chancel": 16482, "concurrent": 16483, "curiously": 16484, "canadians": 16485, "pumped": 16486, "restoring": 16487, "1850s": 16488, "turtles": 16489, "jaguar": 16490, "sinister": 16491, "spinal": 16492, "traction": 16493, "declan": 16494, "vows": 16495, "1784": 16496, "glowed": 16497, "capitalism": 16498, "swirling": 16499, "install": 16500, "universidad": 16501, "##lder": 16502, "##oat": 16503, "soloist": 16504, "##genic": 16505, "##oor": 16506, "coincidence": 16507, "beginnings": 16508, "nissan": 16509, "dip": 16510, "resorts": 16511, "caucasus": 16512, "combustion": 16513, "infectious": 16514, "##eno": 16515, "pigeon": 16516, "serpent": 16517, "##itating": 16518, "conclude": 16519, "masked": 16520, "salad": 16521, "jew": 16522, "##gr": 16523, "surreal": 16524, "toni": 16525, "##wc": 16526, "harmonica": 16527, "151": 16528, "##gins": 16529, "##etic": 16530, "##coat": 16531, "fishermen": 16532, "intending": 16533, "bravery": 16534, "##wave": 16535, "klaus": 16536, "titan": 16537, "wembley": 16538, "taiwanese": 16539, "ransom": 16540, "40th": 16541, "incorrect": 16542, "hussein": 16543, "eyelids": 16544, "jp": 16545, "cooke": 16546, "dramas": 16547, "utilities": 16548, "##etta": 16549, "##print": 16550, "eisenhower": 16551, "principally": 16552, "granada": 16553, "lana": 16554, "##rak": 16555, "openings": 16556, "concord": 16557, "##bl": 16558, "bethany": 16559, "connie": 16560, "morality": 16561, "sega": 16562, "##mons": 16563, "##nard": 16564, "earnings": 16565, "##kara": 16566, "##cine": 16567, "wii": 16568, "communes": 16569, "##rel": 16570, "coma": 16571, "composing": 16572, "softened": 16573, "severed": 16574, "grapes": 16575, "##17": 16576, "nguyen": 16577, "analyzed": 16578, "warlord": 16579, "hubbard": 16580, "heavenly": 16581, "behave": 16582, "slovenian": 16583, "##hit": 16584, "##ony": 16585, "hailed": 16586, "filmmakers": 16587, "trance": 16588, "caldwell": 16589, "skye": 16590, "unrest": 16591, "coward": 16592, "likelihood": 16593, "##aging": 16594, "bern": 16595, "sci": 16596, "taliban": 16597, "honolulu": 16598, "propose": 16599, "##wang": 16600, "1700": 16601, "browser": 16602, "imagining": 16603, "cobra": 16604, "contributes": 16605, "dukes": 16606, "instinctively": 16607, "conan": 16608, "violinist": 16609, "##ores": 16610, "accessories": 16611, "gradual": 16612, "##amp": 16613, "quotes": 16614, "sioux": 16615, "##dating": 16616, "undertake": 16617, "intercepted": 16618, "sparkling": 16619, "compressed": 16620, "139": 16621, "fungus": 16622, "tombs": 16623, "haley": 16624, "imposing": 16625, "rests": 16626, "degradation": 16627, "lincolnshire": 16628, "retailers": 16629, "wetlands": 16630, "tulsa": 16631, "distributor": 16632, "dungeon": 16633, "nun": 16634, "greenhouse": 16635, "convey": 16636, "atlantis": 16637, "aft": 16638, "exits": 16639, "oman": 16640, "dresser": 16641, "lyons": 16642, "##sti": 16643, "joking": 16644, "eddy": 16645, "judgement": 16646, "omitted": 16647, "digits": 16648, "##cts": 16649, "##game": 16650, "juniors": 16651, "##rae": 16652, "cents": 16653, "stricken": 16654, "une": 16655, "##ngo": 16656, "wizards": 16657, "weir": 16658, "breton": 16659, "nan": 16660, "technician": 16661, "fibers": 16662, "liking": 16663, "royalty": 16664, "##cca": 16665, "154": 16666, "persia": 16667, "terribly": 16668, "magician": 16669, "##rable": 16670, "##unt": 16671, "vance": 16672, "cafeteria": 16673, "booker": 16674, "camille": 16675, "warmer": 16676, "##static": 16677, "consume": 16678, "cavern": 16679, "gaps": 16680, "compass": 16681, "contemporaries": 16682, "foyer": 16683, "soothing": 16684, "graveyard": 16685, "maj": 16686, "plunged": 16687, "blush": 16688, "##wear": 16689, "cascade": 16690, "demonstrates": 16691, "ordinance": 16692, "##nov": 16693, "boyle": 16694, "##lana": 16695, "rockefeller": 16696, "shaken": 16697, "banjo": 16698, "izzy": 16699, "##ense": 16700, "breathless": 16701, "vines": 16702, "##32": 16703, "##eman": 16704, "alterations": 16705, "chromosome": 16706, "dwellings": 16707, "feudal": 16708, "mole": 16709, "153": 16710, "catalonia": 16711, "relics": 16712, "tenant": 16713, "mandated": 16714, "##fm": 16715, "fridge": 16716, "hats": 16717, "honesty": 16718, "patented": 16719, "raul": 16720, "heap": 16721, "cruisers": 16722, "accusing": 16723, "enlightenment": 16724, "infants": 16725, "wherein": 16726, "chatham": 16727, "contractors": 16728, "zen": 16729, "affinity": 16730, "hc": 16731, "osborne": 16732, "piston": 16733, "156": 16734, "traps": 16735, "maturity": 16736, "##rana": 16737, "lagos": 16738, "##zal": 16739, "peering": 16740, "##nay": 16741, "attendant": 16742, "dealers": 16743, "protocols": 16744, "subset": 16745, "prospects": 16746, "biographical": 16747, "##cre": 16748, "artery": 16749, "##zers": 16750, "insignia": 16751, "nuns": 16752, "endured": 16753, "##eration": 16754, "recommend": 16755, "schwartz": 16756, "serbs": 16757, "berger": 16758, "cromwell": 16759, "crossroads": 16760, "##ctor": 16761, "enduring": 16762, "clasped": 16763, "grounded": 16764, "##bine": 16765, "marseille": 16766, "twitched": 16767, "abel": 16768, "choke": 16769, "https": 16770, "catalyst": 16771, "moldova": 16772, "italians": 16773, "##tist": 16774, "disastrous": 16775, "wee": 16776, "##oured": 16777, "##nti": 16778, "wwf": 16779, "nope": 16780, "##piration": 16781, "##asa": 16782, "expresses": 16783, "thumbs": 16784, "167": 16785, "##nza": 16786, "coca": 16787, "1781": 16788, "cheating": 16789, "##ption": 16790, "skipped": 16791, "sensory": 16792, "heidelberg": 16793, "spies": 16794, "satan": 16795, "dangers": 16796, "semifinal": 16797, "202": 16798, "bohemia": 16799, "whitish": 16800, "confusing": 16801, "shipbuilding": 16802, "relies": 16803, "surgeons": 16804, "landings": 16805, "ravi": 16806, "baku": 16807, "moor": 16808, "suffix": 16809, "alejandro": 16810, "##yana": 16811, "litre": 16812, "upheld": 16813, "##unk": 16814, "rajasthan": 16815, "##rek": 16816, "coaster": 16817, "insists": 16818, "posture": 16819, "scenarios": 16820, "etienne": 16821, "favoured": 16822, "appoint": 16823, "transgender": 16824, "elephants": 16825, "poked": 16826, "greenwood": 16827, "defences": 16828, "fulfilled": 16829, "militant": 16830, "somali": 16831, "1758": 16832, "chalk": 16833, "potent": 16834, "##ucci": 16835, "migrants": 16836, "wink": 16837, "assistants": 16838, "nos": 16839, "restriction": 16840, "activism": 16841, "niger": 16842, "##ario": 16843, "colon": 16844, "shaun": 16845, "##sat": 16846, "daphne": 16847, "##erated": 16848, "swam": 16849, "congregations": 16850, "reprise": 16851, "considerations": 16852, "magnet": 16853, "playable": 16854, "xvi": 16855, "##р": 16856, "overthrow": 16857, "tobias": 16858, "knob": 16859, "chavez": 16860, "coding": 16861, "##mers": 16862, "propped": 16863, "katrina": 16864, "orient": 16865, "newcomer": 16866, "##suke": 16867, "temperate": 16868, "##pool": 16869, "farmhouse": 16870, "interrogation": 16871, "##vd": 16872, "committing": 16873, "##vert": 16874, "forthcoming": 16875, "strawberry": 16876, "joaquin": 16877, "macau": 16878, "ponds": 16879, "shocking": 16880, "siberia": 16881, "##cellular": 16882, "chant": 16883, "contributors": 16884, "##nant": 16885, "##ologists": 16886, "sped": 16887, "absorb": 16888, "hail": 16889, "1782": 16890, "spared": 16891, "##hore": 16892, "barbados": 16893, "karate": 16894, "opus": 16895, "originates": 16896, "saul": 16897, "##xie": 16898, "evergreen": 16899, "leaped": 16900, "##rock": 16901, "correlation": 16902, "exaggerated": 16903, "weekday": 16904, "unification": 16905, "bump": 16906, "tracing": 16907, "brig": 16908, "afb": 16909, "pathways": 16910, "utilizing": 16911, "##ners": 16912, "mod": 16913, "mb": 16914, "disturbance": 16915, "kneeling": 16916, "##stad": 16917, "##guchi": 16918, "100th": 16919, "pune": 16920, "##thy": 16921, "decreasing": 16922, "168": 16923, "manipulation": 16924, "miriam": 16925, "academia": 16926, "ecosystem": 16927, "occupational": 16928, "rbi": 16929, "##lem": 16930, "rift": 16931, "##14": 16932, "rotary": 16933, "stacked": 16934, "incorporation": 16935, "awakening": 16936, "generators": 16937, "guerrero": 16938, "racist": 16939, "##omy": 16940, "cyber": 16941, "derivatives": 16942, "culminated": 16943, "allie": 16944, "annals": 16945, "panzer": 16946, "sainte": 16947, "wikipedia": 16948, "pops": 16949, "zu": 16950, "austro": 16951, "##vate": 16952, "algerian": 16953, "politely": 16954, "nicholson": 16955, "mornings": 16956, "educate": 16957, "tastes": 16958, "thrill": 16959, "dartmouth": 16960, "##gating": 16961, "db": 16962, "##jee": 16963, "regan": 16964, "differing": 16965, "concentrating": 16966, "choreography": 16967, "divinity": 16968, "##media": 16969, "pledged": 16970, "alexandre": 16971, "routing": 16972, "gregor": 16973, "madeline": 16974, "##idal": 16975, "apocalypse": 16976, "##hora": 16977, "gunfire": 16978, "culminating": 16979, "elves": 16980, "fined": 16981, "liang": 16982, "lam": 16983, "programmed": 16984, "tar": 16985, "guessing": 16986, "transparency": 16987, "gabrielle": 16988, "##gna": 16989, "cancellation": 16990, "flexibility": 16991, "##lining": 16992, "accession": 16993, "shea": 16994, "stronghold": 16995, "nets": 16996, "specializes": 16997, "##rgan": 16998, "abused": 16999, "hasan": 17000, "sgt": 17001, "ling": 17002, "exceeding": 17003, "##₄": 17004, "admiration": 17005, "supermarket": 17006, "##ark": 17007, "photographers": 17008, "specialised": 17009, "tilt": 17010, "resonance": 17011, "hmm": 17012, "perfume": 17013, "380": 17014, "sami": 17015, "threatens": 17016, "garland": 17017, "botany": 17018, "guarding": 17019, "boiled": 17020, "greet": 17021, "puppy": 17022, "russo": 17023, "supplier": 17024, "wilmington": 17025, "vibrant": 17026, "vijay": 17027, "##bius": 17028, "paralympic": 17029, "grumbled": 17030, "paige": 17031, "faa": 17032, "licking": 17033, "margins": 17034, "hurricanes": 17035, "##gong": 17036, "fest": 17037, "grenade": 17038, "ripping": 17039, "##uz": 17040, "counseling": 17041, "weigh": 17042, "##sian": 17043, "needles": 17044, "wiltshire": 17045, "edison": 17046, "costly": 17047, "##not": 17048, "fulton": 17049, "tramway": 17050, "redesigned": 17051, "staffordshire": 17052, "cache": 17053, "gasping": 17054, "watkins": 17055, "sleepy": 17056, "candidacy": 17057, "##group": 17058, "monkeys": 17059, "timeline": 17060, "throbbing": 17061, "##bid": 17062, "##sos": 17063, "berth": 17064, "uzbekistan": 17065, "vanderbilt": 17066, "bothering": 17067, "overturned": 17068, "ballots": 17069, "gem": 17070, "##iger": 17071, "sunglasses": 17072, "subscribers": 17073, "hooker": 17074, "compelling": 17075, "ang": 17076, "exceptionally": 17077, "saloon": 17078, "stab": 17079, "##rdi": 17080, "carla": 17081, "terrifying": 17082, "rom": 17083, "##vision": 17084, "coil": 17085, "##oids": 17086, "satisfying": 17087, "vendors": 17088, "31st": 17089, "mackay": 17090, "deities": 17091, "overlooked": 17092, "ambient": 17093, "bahamas": 17094, "felipe": 17095, "olympia": 17096, "whirled": 17097, "botanist": 17098, "advertised": 17099, "tugging": 17100, "##dden": 17101, "disciples": 17102, "morales": 17103, "unionist": 17104, "rites": 17105, "foley": 17106, "morse": 17107, "motives": 17108, "creepy": 17109, "##₀": 17110, "soo": 17111, "##sz": 17112, "bargain": 17113, "highness": 17114, "frightening": 17115, "turnpike": 17116, "tory": 17117, "reorganization": 17118, "##cer": 17119, "depict": 17120, "biographer": 17121, "##walk": 17122, "unopposed": 17123, "manifesto": 17124, "##gles": 17125, "institut": 17126, "emile": 17127, "accidental": 17128, "kapoor": 17129, "##dam": 17130, "kilkenny": 17131, "cortex": 17132, "lively": 17133, "##13": 17134, "romanesque": 17135, "jain": 17136, "shan": 17137, "cannons": 17138, "##ood": 17139, "##ske": 17140, "petrol": 17141, "echoing": 17142, "amalgamated": 17143, "disappears": 17144, "cautious": 17145, "proposes": 17146, "sanctions": 17147, "trenton": 17148, "##ر": 17149, "flotilla": 17150, "aus": 17151, "contempt": 17152, "tor": 17153, "canary": 17154, "cote": 17155, "theirs": 17156, "##hun": 17157, "conceptual": 17158, "deleted": 17159, "fascinating": 17160, "paso": 17161, "blazing": 17162, "elf": 17163, "honourable": 17164, "hutchinson": 17165, "##eiro": 17166, "##outh": 17167, "##zin": 17168, "surveyor": 17169, "tee": 17170, "amidst": 17171, "wooded": 17172, "reissue": 17173, "intro": 17174, "##ono": 17175, "cobb": 17176, "shelters": 17177, "newsletter": 17178, "hanson": 17179, "brace": 17180, "encoding": 17181, "confiscated": 17182, "dem": 17183, "caravan": 17184, "marino": 17185, "scroll": 17186, "melodic": 17187, "cows": 17188, "imam": 17189, "##adi": 17190, "##aneous": 17191, "northward": 17192, "searches": 17193, "biodiversity": 17194, "cora": 17195, "310": 17196, "roaring": 17197, "##bers": 17198, "connell": 17199, "theologian": 17200, "halo": 17201, "compose": 17202, "pathetic": 17203, "unmarried": 17204, "dynamo": 17205, "##oot": 17206, "az": 17207, "calculation": 17208, "toulouse": 17209, "deserves": 17210, "humour": 17211, "nr": 17212, "forgiveness": 17213, "tam": 17214, "undergone": 17215, "martyr": 17216, "pamela": 17217, "myths": 17218, "whore": 17219, "counselor": 17220, "hicks": 17221, "290": 17222, "heavens": 17223, "battleship": 17224, "electromagnetic": 17225, "##bbs": 17226, "stellar": 17227, "establishments": 17228, "presley": 17229, "hopped": 17230, "##chin": 17231, "temptation": 17232, "90s": 17233, "wills": 17234, "nas": 17235, "##yuan": 17236, "nhs": 17237, "##nya": 17238, "seminars": 17239, "##yev": 17240, "adaptations": 17241, "gong": 17242, "asher": 17243, "lex": 17244, "indicator": 17245, "sikh": 17246, "tobago": 17247, "cites": 17248, "goin": 17249, "##yte": 17250, "satirical": 17251, "##gies": 17252, "characterised": 17253, "correspond": 17254, "bubbles": 17255, "lure": 17256, "participates": 17257, "##vid": 17258, "eruption": 17259, "skate": 17260, "therapeutic": 17261, "1785": 17262, "canals": 17263, "wholesale": 17264, "defaulted": 17265, "sac": 17266, "460": 17267, "petit": 17268, "##zzled": 17269, "virgil": 17270, "leak": 17271, "ravens": 17272, "256": 17273, "portraying": 17274, "##yx": 17275, "ghetto": 17276, "creators": 17277, "dams": 17278, "portray": 17279, "vicente": 17280, "##rington": 17281, "fae": 17282, "namesake": 17283, "bounty": 17284, "##arium": 17285, "joachim": 17286, "##ota": 17287, "##iser": 17288, "aforementioned": 17289, "axle": 17290, "snout": 17291, "depended": 17292, "dismantled": 17293, "reuben": 17294, "480": 17295, "##ibly": 17296, "gallagher": 17297, "##lau": 17298, "##pd": 17299, "earnest": 17300, "##ieu": 17301, "##iary": 17302, "inflicted": 17303, "objections": 17304, "##llar": 17305, "asa": 17306, "gritted": 17307, "##athy": 17308, "jericho": 17309, "##sea": 17310, "##was": 17311, "flick": 17312, "underside": 17313, "ceramics": 17314, "undead": 17315, "substituted": 17316, "195": 17317, "eastward": 17318, "undoubtedly": 17319, "wheeled": 17320, "chimney": 17321, "##iche": 17322, "guinness": 17323, "cb": 17324, "##ager": 17325, "siding": 17326, "##bell": 17327, "traitor": 17328, "baptiste": 17329, "disguised": 17330, "inauguration": 17331, "149": 17332, "tipperary": 17333, "choreographer": 17334, "perched": 17335, "warmed": 17336, "stationary": 17337, "eco": 17338, "##ike": 17339, "##ntes": 17340, "bacterial": 17341, "##aurus": 17342, "flores": 17343, "phosphate": 17344, "##core": 17345, "attacker": 17346, "invaders": 17347, "alvin": 17348, "intersects": 17349, "a1": 17350, "indirectly": 17351, "immigrated": 17352, "businessmen": 17353, "cornelius": 17354, "valves": 17355, "narrated": 17356, "pill": 17357, "sober": 17358, "ul": 17359, "nationale": 17360, "monastic": 17361, "applicants": 17362, "scenery": 17363, "##jack": 17364, "161": 17365, "motifs": 17366, "constitutes": 17367, "cpu": 17368, "##osh": 17369, "jurisdictions": 17370, "sd": 17371, "tuning": 17372, "irritation": 17373, "woven": 17374, "##uddin": 17375, "fertility": 17376, "gao": 17377, "##erie": 17378, "antagonist": 17379, "impatient": 17380, "glacial": 17381, "hides": 17382, "boarded": 17383, "denominations": 17384, "interception": 17385, "##jas": 17386, "cookie": 17387, "nicola": 17388, "##tee": 17389, "algebraic": 17390, "marquess": 17391, "bahn": 17392, "parole": 17393, "buyers": 17394, "bait": 17395, "turbines": 17396, "paperwork": 17397, "bestowed": 17398, "natasha": 17399, "renee": 17400, "oceans": 17401, "purchases": 17402, "157": 17403, "vaccine": 17404, "215": 17405, "##tock": 17406, "fixtures": 17407, "playhouse": 17408, "integrate": 17409, "jai": 17410, "oswald": 17411, "intellectuals": 17412, "##cky": 17413, "booked": 17414, "nests": 17415, "mortimer": 17416, "##isi": 17417, "obsession": 17418, "sept": 17419, "##gler": 17420, "##sum": 17421, "440": 17422, "scrutiny": 17423, "simultaneous": 17424, "squinted": 17425, "##shin": 17426, "collects": 17427, "oven": 17428, "shankar": 17429, "penned": 17430, "remarkably": 17431, "##я": 17432, "slips": 17433, "luggage": 17434, "spectral": 17435, "1786": 17436, "collaborations": 17437, "louie": 17438, "consolidation": 17439, "##ailed": 17440, "##ivating": 17441, "420": 17442, "hoover": 17443, "blackpool": 17444, "harness": 17445, "ignition": 17446, "vest": 17447, "tails": 17448, "belmont": 17449, "mongol": 17450, "skinner": 17451, "##nae": 17452, "visually": 17453, "mage": 17454, "derry": 17455, "##tism": 17456, "##unce": 17457, "stevie": 17458, "transitional": 17459, "##rdy": 17460, "redskins": 17461, "drying": 17462, "prep": 17463, "prospective": 17464, "##21": 17465, "annoyance": 17466, "oversee": 17467, "##loaded": 17468, "fills": 17469, "##books": 17470, "##iki": 17471, "announces": 17472, "fda": 17473, "scowled": 17474, "respects": 17475, "prasad": 17476, "mystic": 17477, "tucson": 17478, "##vale": 17479, "revue": 17480, "springer": 17481, "bankrupt": 17482, "1772": 17483, "aristotle": 17484, "salvatore": 17485, "habsburg": 17486, "##geny": 17487, "dal": 17488, "natal": 17489, "nut": 17490, "pod": 17491, "chewing": 17492, "darts": 17493, "moroccan": 17494, "walkover": 17495, "rosario": 17496, "lenin": 17497, "punjabi": 17498, "##ße": 17499, "grossed": 17500, "scattering": 17501, "wired": 17502, "invasive": 17503, "hui": 17504, "polynomial": 17505, "corridors": 17506, "wakes": 17507, "gina": 17508, "portrays": 17509, "##cratic": 17510, "arid": 17511, "retreating": 17512, "erich": 17513, "irwin": 17514, "sniper": 17515, "##dha": 17516, "linen": 17517, "lindsey": 17518, "maneuver": 17519, "butch": 17520, "shutting": 17521, "socio": 17522, "bounce": 17523, "commemorative": 17524, "postseason": 17525, "jeremiah": 17526, "pines": 17527, "275": 17528, "mystical": 17529, "beads": 17530, "bp": 17531, "abbas": 17532, "furnace": 17533, "bidding": 17534, "consulted": 17535, "assaulted": 17536, "empirical": 17537, "rubble": 17538, "enclosure": 17539, "sob": 17540, "weakly": 17541, "cancel": 17542, "polly": 17543, "yielded": 17544, "##emann": 17545, "curly": 17546, "prediction": 17547, "battered": 17548, "70s": 17549, "vhs": 17550, "jacqueline": 17551, "render": 17552, "sails": 17553, "barked": 17554, "detailing": 17555, "grayson": 17556, "riga": 17557, "sloane": 17558, "raging": 17559, "##yah": 17560, "herbs": 17561, "bravo": 17562, "##athlon": 17563, "alloy": 17564, "giggle": 17565, "imminent": 17566, "suffers": 17567, "assumptions": 17568, "waltz": 17569, "##itate": 17570, "accomplishments": 17571, "##ited": 17572, "bathing": 17573, "remixed": 17574, "deception": 17575, "prefix": 17576, "##emia": 17577, "deepest": 17578, "##tier": 17579, "##eis": 17580, "balkan": 17581, "frogs": 17582, "##rong": 17583, "slab": 17584, "##pate": 17585, "philosophers": 17586, "peterborough": 17587, "grains": 17588, "imports": 17589, "dickinson": 17590, "rwanda": 17591, "##atics": 17592, "1774": 17593, "dirk": 17594, "lan": 17595, "tablets": 17596, "##rove": 17597, "clone": 17598, "##rice": 17599, "caretaker": 17600, "hostilities": 17601, "mclean": 17602, "##gre": 17603, "regimental": 17604, "treasures": 17605, "norms": 17606, "impose": 17607, "tsar": 17608, "tango": 17609, "diplomacy": 17610, "variously": 17611, "complain": 17612, "192": 17613, "recognise": 17614, "arrests": 17615, "1779": 17616, "celestial": 17617, "pulitzer": 17618, "##dus": 17619, "bing": 17620, "libretto": 17621, "##moor": 17622, "adele": 17623, "splash": 17624, "##rite": 17625, "expectation": 17626, "lds": 17627, "confronts": 17628, "##izer": 17629, "spontaneous": 17630, "harmful": 17631, "wedge": 17632, "entrepreneurs": 17633, "buyer": 17634, "##ope": 17635, "bilingual": 17636, "translate": 17637, "rugged": 17638, "conner": 17639, "circulated": 17640, "uae": 17641, "eaton": 17642, "##gra": 17643, "##zzle": 17644, "lingered": 17645, "lockheed": 17646, "vishnu": 17647, "reelection": 17648, "alonso": 17649, "##oom": 17650, "joints": 17651, "yankee": 17652, "headline": 17653, "cooperate": 17654, "heinz": 17655, "laureate": 17656, "invading": 17657, "##sford": 17658, "echoes": 17659, "scandinavian": 17660, "##dham": 17661, "hugging": 17662, "vitamin": 17663, "salute": 17664, "micah": 17665, "hind": 17666, "trader": 17667, "##sper": 17668, "radioactive": 17669, "##ndra": 17670, "militants": 17671, "poisoned": 17672, "ratified": 17673, "remark": 17674, "campeonato": 17675, "deprived": 17676, "wander": 17677, "prop": 17678, "##dong": 17679, "outlook": 17680, "##tani": 17681, "##rix": 17682, "##eye": 17683, "chiang": 17684, "darcy": 17685, "##oping": 17686, "mandolin": 17687, "spice": 17688, "statesman": 17689, "babylon": 17690, "182": 17691, "walled": 17692, "forgetting": 17693, "afro": 17694, "##cap": 17695, "158": 17696, "giorgio": 17697, "buffer": 17698, "##polis": 17699, "planetary": 17700, "##gis": 17701, "overlap": 17702, "terminals": 17703, "kinda": 17704, "centenary": 17705, "##bir": 17706, "arising": 17707, "manipulate": 17708, "elm": 17709, "ke": 17710, "1770": 17711, "ak": 17712, "##tad": 17713, "chrysler": 17714, "mapped": 17715, "moose": 17716, "pomeranian": 17717, "quad": 17718, "macarthur": 17719, "assemblies": 17720, "shoreline": 17721, "recalls": 17722, "stratford": 17723, "##rted": 17724, "noticeable": 17725, "##evic": 17726, "imp": 17727, "##rita": 17728, "##sque": 17729, "accustomed": 17730, "supplying": 17731, "tents": 17732, "disgusted": 17733, "vogue": 17734, "sipped": 17735, "filters": 17736, "khz": 17737, "reno": 17738, "selecting": 17739, "luftwaffe": 17740, "mcmahon": 17741, "tyne": 17742, "masterpiece": 17743, "carriages": 17744, "collided": 17745, "dunes": 17746, "exercised": 17747, "flare": 17748, "remembers": 17749, "muzzle": 17750, "##mobile": 17751, "heck": 17752, "##rson": 17753, "burgess": 17754, "lunged": 17755, "middleton": 17756, "boycott": 17757, "bilateral": 17758, "##sity": 17759, "hazardous": 17760, "lumpur": 17761, "multiplayer": 17762, "spotlight": 17763, "jackets": 17764, "goldman": 17765, "liege": 17766, "porcelain": 17767, "rag": 17768, "waterford": 17769, "benz": 17770, "attracts": 17771, "hopeful": 17772, "battling": 17773, "ottomans": 17774, "kensington": 17775, "baked": 17776, "hymns": 17777, "cheyenne": 17778, "lattice": 17779, "levine": 17780, "borrow": 17781, "polymer": 17782, "clashes": 17783, "michaels": 17784, "monitored": 17785, "commitments": 17786, "denounced": 17787, "##25": 17788, "##von": 17789, "cavity": 17790, "##oney": 17791, "hobby": 17792, "akin": 17793, "##holders": 17794, "futures": 17795, "intricate": 17796, "cornish": 17797, "patty": 17798, "##oned": 17799, "illegally": 17800, "dolphin": 17801, "##lag": 17802, "barlow": 17803, "yellowish": 17804, "maddie": 17805, "apologized": 17806, "luton": 17807, "plagued": 17808, "##puram": 17809, "nana": 17810, "##rds": 17811, "sway": 17812, "fanny": 17813, "łodz": 17814, "##rino": 17815, "psi": 17816, "suspicions": 17817, "hanged": 17818, "##eding": 17819, "initiate": 17820, "charlton": 17821, "##por": 17822, "nak": 17823, "competent": 17824, "235": 17825, "analytical": 17826, "annex": 17827, "wardrobe": 17828, "reservations": 17829, "##rma": 17830, "sect": 17831, "162": 17832, "fairfax": 17833, "hedge": 17834, "piled": 17835, "buckingham": 17836, "uneven": 17837, "bauer": 17838, "simplicity": 17839, "snyder": 17840, "interpret": 17841, "accountability": 17842, "donors": 17843, "moderately": 17844, "byrd": 17845, "continents": 17846, "##cite": 17847, "##max": 17848, "disciple": 17849, "hr": 17850, "jamaican": 17851, "ping": 17852, "nominees": 17853, "##uss": 17854, "mongolian": 17855, "diver": 17856, "attackers": 17857, "eagerly": 17858, "ideological": 17859, "pillows": 17860, "miracles": 17861, "apartheid": 17862, "revolver": 17863, "sulfur": 17864, "clinics": 17865, "moran": 17866, "163": 17867, "##enko": 17868, "ile": 17869, "katy": 17870, "rhetoric": 17871, "##icated": 17872, "chronology": 17873, "recycling": 17874, "##hrer": 17875, "elongated": 17876, "mughal": 17877, "pascal": 17878, "profiles": 17879, "vibration": 17880, "databases": 17881, "domination": 17882, "##fare": 17883, "##rant": 17884, "matthias": 17885, "digest": 17886, "rehearsal": 17887, "polling": 17888, "weiss": 17889, "initiation": 17890, "reeves": 17891, "clinging": 17892, "flourished": 17893, "impress": 17894, "ngo": 17895, "##hoff": 17896, "##ume": 17897, "buckley": 17898, "symposium": 17899, "rhythms": 17900, "weed": 17901, "emphasize": 17902, "transforming": 17903, "##taking": 17904, "##gence": 17905, "##yman": 17906, "accountant": 17907, "analyze": 17908, "flicker": 17909, "foil": 17910, "priesthood": 17911, "voluntarily": 17912, "decreases": 17913, "##80": 17914, "##hya": 17915, "slater": 17916, "sv": 17917, "charting": 17918, "mcgill": 17919, "##lde": 17920, "moreno": 17921, "##iu": 17922, "besieged": 17923, "zur": 17924, "robes": 17925, "##phic": 17926, "admitting": 17927, "api": 17928, "deported": 17929, "turmoil": 17930, "peyton": 17931, "earthquakes": 17932, "##ares": 17933, "nationalists": 17934, "beau": 17935, "clair": 17936, "brethren": 17937, "interrupt": 17938, "welch": 17939, "curated": 17940, "galerie": 17941, "requesting": 17942, "164": 17943, "##ested": 17944, "impending": 17945, "steward": 17946, "viper": 17947, "##vina": 17948, "complaining": 17949, "beautifully": 17950, "brandy": 17951, "foam": 17952, "nl": 17953, "1660": 17954, "##cake": 17955, "alessandro": 17956, "punches": 17957, "laced": 17958, "explanations": 17959, "##lim": 17960, "attribute": 17961, "clit": 17962, "reggie": 17963, "discomfort": 17964, "##cards": 17965, "smoothed": 17966, "whales": 17967, "##cene": 17968, "adler": 17969, "countered": 17970, "duffy": 17971, "disciplinary": 17972, "widening": 17973, "recipe": 17974, "reliance": 17975, "conducts": 17976, "goats": 17977, "gradient": 17978, "preaching": 17979, "##shaw": 17980, "matilda": 17981, "quasi": 17982, "striped": 17983, "meridian": 17984, "cannabis": 17985, "cordoba": 17986, "certificates": 17987, "##agh": 17988, "##tering": 17989, "graffiti": 17990, "hangs": 17991, "pilgrims": 17992, "repeats": 17993, "##ych": 17994, "revive": 17995, "urine": 17996, "etat": 17997, "##hawk": 17998, "fueled": 17999, "belts": 18000, "fuzzy": 18001, "susceptible": 18002, "##hang": 18003, "mauritius": 18004, "salle": 18005, "sincere": 18006, "beers": 18007, "hooks": 18008, "##cki": 18009, "arbitration": 18010, "entrusted": 18011, "advise": 18012, "sniffed": 18013, "seminar": 18014, "junk": 18015, "donnell": 18016, "processors": 18017, "principality": 18018, "strapped": 18019, "celia": 18020, "mendoza": 18021, "everton": 18022, "fortunes": 18023, "prejudice": 18024, "starving": 18025, "reassigned": 18026, "steamer": 18027, "##lund": 18028, "tuck": 18029, "evenly": 18030, "foreman": 18031, "##ffen": 18032, "dans": 18033, "375": 18034, "envisioned": 18035, "slit": 18036, "##xy": 18037, "baseman": 18038, "liberia": 18039, "rosemary": 18040, "##weed": 18041, "electrified": 18042, "periodically": 18043, "potassium": 18044, "stride": 18045, "contexts": 18046, "sperm": 18047, "slade": 18048, "mariners": 18049, "influx": 18050, "bianca": 18051, "subcommittee": 18052, "##rane": 18053, "spilling": 18054, "icao": 18055, "estuary": 18056, "##nock": 18057, "delivers": 18058, "iphone": 18059, "##ulata": 18060, "isa": 18061, "mira": 18062, "bohemian": 18063, "dessert": 18064, "##sbury": 18065, "welcoming": 18066, "proudly": 18067, "slowing": 18068, "##chs": 18069, "musee": 18070, "ascension": 18071, "russ": 18072, "##vian": 18073, "waits": 18074, "##psy": 18075, "africans": 18076, "exploit": 18077, "##morphic": 18078, "gov": 18079, "eccentric": 18080, "crab": 18081, "peck": 18082, "##ull": 18083, "entrances": 18084, "formidable": 18085, "marketplace": 18086, "groom": 18087, "bolted": 18088, "metabolism": 18089, "patton": 18090, "robbins": 18091, "courier": 18092, "payload": 18093, "endure": 18094, "##ifier": 18095, "andes": 18096, "refrigerator": 18097, "##pr": 18098, "ornate": 18099, "##uca": 18100, "ruthless": 18101, "illegitimate": 18102, "masonry": 18103, "strasbourg": 18104, "bikes": 18105, "adobe": 18106, "##³": 18107, "apples": 18108, "quintet": 18109, "willingly": 18110, "niche": 18111, "bakery": 18112, "corpses": 18113, "energetic": 18114, "##cliffe": 18115, "##sser": 18116, "##ards": 18117, "177": 18118, "centimeters": 18119, "centro": 18120, "fuscous": 18121, "cretaceous": 18122, "rancho": 18123, "##yde": 18124, "andrei": 18125, "telecom": 18126, "tottenham": 18127, "oasis": 18128, "ordination": 18129, "vulnerability": 18130, "presiding": 18131, "corey": 18132, "cp": 18133, "penguins": 18134, "sims": 18135, "##pis": 18136, "malawi": 18137, "piss": 18138, "##48": 18139, "correction": 18140, "##cked": 18141, "##ffle": 18142, "##ryn": 18143, "countdown": 18144, "detectives": 18145, "psychiatrist": 18146, "psychedelic": 18147, "dinosaurs": 18148, "blouse": 18149, "##get": 18150, "choi": 18151, "vowed": 18152, "##oz": 18153, "randomly": 18154, "##pol": 18155, "49ers": 18156, "scrub": 18157, "blanche": 18158, "bruins": 18159, "dusseldorf": 18160, "##using": 18161, "unwanted": 18162, "##ums": 18163, "212": 18164, "dominique": 18165, "elevations": 18166, "headlights": 18167, "om": 18168, "laguna": 18169, "##oga": 18170, "1750": 18171, "famously": 18172, "ignorance": 18173, "shrewsbury": 18174, "##aine": 18175, "ajax": 18176, "breuning": 18177, "che": 18178, "confederacy": 18179, "greco": 18180, "overhaul": 18181, "##screen": 18182, "paz": 18183, "skirts": 18184, "disagreement": 18185, "cruelty": 18186, "jagged": 18187, "phoebe": 18188, "shifter": 18189, "hovered": 18190, "viruses": 18191, "##wes": 18192, "mandy": 18193, "##lined": 18194, "##gc": 18195, "landlord": 18196, "squirrel": 18197, "dashed": 18198, "##ι": 18199, "ornamental": 18200, "gag": 18201, "wally": 18202, "grange": 18203, "literal": 18204, "spurs": 18205, "undisclosed": 18206, "proceeding": 18207, "yin": 18208, "##text": 18209, "billie": 18210, "orphan": 18211, "spanned": 18212, "humidity": 18213, "indy": 18214, "weighted": 18215, "presentations": 18216, "explosions": 18217, "lucian": 18218, "##tary": 18219, "vaughn": 18220, "hindus": 18221, "##anga": 18222, "##hell": 18223, "psycho": 18224, "171": 18225, "daytona": 18226, "protects": 18227, "efficiently": 18228, "rematch": 18229, "sly": 18230, "tandem": 18231, "##oya": 18232, "rebranded": 18233, "impaired": 18234, "hee": 18235, "metropolis": 18236, "peach": 18237, "godfrey": 18238, "diaspora": 18239, "ethnicity": 18240, "prosperous": 18241, "gleaming": 18242, "dar": 18243, "grossing": 18244, "playback": 18245, "##rden": 18246, "stripe": 18247, "pistols": 18248, "##tain": 18249, "births": 18250, "labelled": 18251, "##cating": 18252, "172": 18253, "rudy": 18254, "alba": 18255, "##onne": 18256, "aquarium": 18257, "hostility": 18258, "##gb": 18259, "##tase": 18260, "shudder": 18261, "sumatra": 18262, "hardest": 18263, "lakers": 18264, "consonant": 18265, "creeping": 18266, "demos": 18267, "homicide": 18268, "capsule": 18269, "zeke": 18270, "liberties": 18271, "expulsion": 18272, "pueblo": 18273, "##comb": 18274, "trait": 18275, "transporting": 18276, "##ddin": 18277, "##neck": 18278, "##yna": 18279, "depart": 18280, "gregg": 18281, "mold": 18282, "ledge": 18283, "hangar": 18284, "oldham": 18285, "playboy": 18286, "termination": 18287, "analysts": 18288, "gmbh": 18289, "romero": 18290, "##itic": 18291, "insist": 18292, "cradle": 18293, "filthy": 18294, "brightness": 18295, "slash": 18296, "shootout": 18297, "deposed": 18298, "bordering": 18299, "##truct": 18300, "isis": 18301, "microwave": 18302, "tumbled": 18303, "sheltered": 18304, "cathy": 18305, "werewolves": 18306, "messy": 18307, "andersen": 18308, "convex": 18309, "clapped": 18310, "clinched": 18311, "satire": 18312, "wasting": 18313, "edo": 18314, "vc": 18315, "rufus": 18316, "##jak": 18317, "mont": 18318, "##etti": 18319, "poznan": 18320, "##keeping": 18321, "restructuring": 18322, "transverse": 18323, "##rland": 18324, "azerbaijani": 18325, "slovene": 18326, "gestures": 18327, "roommate": 18328, "choking": 18329, "shear": 18330, "##quist": 18331, "vanguard": 18332, "oblivious": 18333, "##hiro": 18334, "disagreed": 18335, "baptism": 18336, "##lich": 18337, "coliseum": 18338, "##aceae": 18339, "salvage": 18340, "societe": 18341, "cory": 18342, "locke": 18343, "relocation": 18344, "relying": 18345, "versailles": 18346, "ahl": 18347, "swelling": 18348, "##elo": 18349, "cheerful": 18350, "##word": 18351, "##edes": 18352, "gin": 18353, "sarajevo": 18354, "obstacle": 18355, "diverted": 18356, "##nac": 18357, "messed": 18358, "thoroughbred": 18359, "fluttered": 18360, "utrecht": 18361, "chewed": 18362, "acquaintance": 18363, "assassins": 18364, "dispatch": 18365, "mirza": 18366, "##wart": 18367, "nike": 18368, "salzburg": 18369, "swell": 18370, "yen": 18371, "##gee": 18372, "idle": 18373, "ligue": 18374, "samson": 18375, "##nds": 18376, "##igh": 18377, "playful": 18378, "spawned": 18379, "##cise": 18380, "tease": 18381, "##case": 18382, "burgundy": 18383, "##bot": 18384, "stirring": 18385, "skeptical": 18386, "interceptions": 18387, "marathi": 18388, "##dies": 18389, "bedrooms": 18390, "aroused": 18391, "pinch": 18392, "##lik": 18393, "preferences": 18394, "tattoos": 18395, "buster": 18396, "digitally": 18397, "projecting": 18398, "rust": 18399, "##ital": 18400, "kitten": 18401, "priorities": 18402, "addison": 18403, "pseudo": 18404, "##guard": 18405, "dusk": 18406, "icons": 18407, "sermon": 18408, "##psis": 18409, "##iba": 18410, "bt": 18411, "##lift": 18412, "##xt": 18413, "ju": 18414, "truce": 18415, "rink": 18416, "##dah": 18417, "##wy": 18418, "defects": 18419, "psychiatry": 18420, "offences": 18421, "calculate": 18422, "glucose": 18423, "##iful": 18424, "##rized": 18425, "##unda": 18426, "francaise": 18427, "##hari": 18428, "richest": 18429, "warwickshire": 18430, "carly": 18431, "1763": 18432, "purity": 18433, "redemption": 18434, "lending": 18435, "##cious": 18436, "muse": 18437, "bruises": 18438, "cerebral": 18439, "aero": 18440, "carving": 18441, "##name": 18442, "preface": 18443, "terminology": 18444, "invade": 18445, "monty": 18446, "##int": 18447, "anarchist": 18448, "blurred": 18449, "##iled": 18450, "rossi": 18451, "treats": 18452, "guts": 18453, "shu": 18454, "foothills": 18455, "ballads": 18456, "undertaking": 18457, "premise": 18458, "cecilia": 18459, "affiliates": 18460, "blasted": 18461, "conditional": 18462, "wilder": 18463, "minors": 18464, "drone": 18465, "rudolph": 18466, "buffy": 18467, "swallowing": 18468, "horton": 18469, "attested": 18470, "##hop": 18471, "rutherford": 18472, "howell": 18473, "primetime": 18474, "livery": 18475, "penal": 18476, "##bis": 18477, "minimize": 18478, "hydro": 18479, "wrecked": 18480, "wrought": 18481, "palazzo": 18482, "##gling": 18483, "cans": 18484, "vernacular": 18485, "friedman": 18486, "nobleman": 18487, "shale": 18488, "walnut": 18489, "danielle": 18490, "##ection": 18491, "##tley": 18492, "sears": 18493, "##kumar": 18494, "chords": 18495, "lend": 18496, "flipping": 18497, "streamed": 18498, "por": 18499, "dracula": 18500, "gallons": 18501, "sacrifices": 18502, "gamble": 18503, "orphanage": 18504, "##iman": 18505, "mckenzie": 18506, "##gible": 18507, "boxers": 18508, "daly": 18509, "##balls": 18510, "##ان": 18511, "208": 18512, "##ific": 18513, "##rative": 18514, "##iq": 18515, "exploited": 18516, "slated": 18517, "##uity": 18518, "circling": 18519, "hillary": 18520, "pinched": 18521, "goldberg": 18522, "provost": 18523, "campaigning": 18524, "lim": 18525, "piles": 18526, "ironically": 18527, "jong": 18528, "mohan": 18529, "successors": 18530, "usaf": 18531, "##tem": 18532, "##ught": 18533, "autobiographical": 18534, "haute": 18535, "preserves": 18536, "##ending": 18537, "acquitted": 18538, "comparisons": 18539, "203": 18540, "hydroelectric": 18541, "gangs": 18542, "cypriot": 18543, "torpedoes": 18544, "rushes": 18545, "chrome": 18546, "derive": 18547, "bumps": 18548, "instability": 18549, "fiat": 18550, "pets": 18551, "##mbe": 18552, "silas": 18553, "dye": 18554, "reckless": 18555, "settler": 18556, "##itation": 18557, "info": 18558, "heats": 18559, "##writing": 18560, "176": 18561, "canonical": 18562, "maltese": 18563, "fins": 18564, "mushroom": 18565, "stacy": 18566, "aspen": 18567, "avid": 18568, "##kur": 18569, "##loading": 18570, "vickers": 18571, "gaston": 18572, "hillside": 18573, "statutes": 18574, "wilde": 18575, "gail": 18576, "kung": 18577, "sabine": 18578, "comfortably": 18579, "motorcycles": 18580, "##rgo": 18581, "169": 18582, "pneumonia": 18583, "fetch": 18584, "##sonic": 18585, "axel": 18586, "faintly": 18587, "parallels": 18588, "##oop": 18589, "mclaren": 18590, "spouse": 18591, "compton": 18592, "interdisciplinary": 18593, "miner": 18594, "##eni": 18595, "181": 18596, "clamped": 18597, "##chal": 18598, "##llah": 18599, "separates": 18600, "versa": 18601, "##mler": 18602, "scarborough": 18603, "labrador": 18604, "##lity": 18605, "##osing": 18606, "rutgers": 18607, "hurdles": 18608, "como": 18609, "166": 18610, "burt": 18611, "divers": 18612, "##100": 18613, "wichita": 18614, "cade": 18615, "coincided": 18616, "##erson": 18617, "bruised": 18618, "mla": 18619, "##pper": 18620, "vineyard": 18621, "##ili": 18622, "##brush": 18623, "notch": 18624, "mentioning": 18625, "jase": 18626, "hearted": 18627, "kits": 18628, "doe": 18629, "##acle": 18630, "pomerania": 18631, "##ady": 18632, "ronan": 18633, "seizure": 18634, "pavel": 18635, "problematic": 18636, "##zaki": 18637, "domenico": 18638, "##ulin": 18639, "catering": 18640, "penelope": 18641, "dependence": 18642, "parental": 18643, "emilio": 18644, "ministerial": 18645, "atkinson": 18646, "##bolic": 18647, "clarkson": 18648, "chargers": 18649, "colby": 18650, "grill": 18651, "peeked": 18652, "arises": 18653, "summon": 18654, "##aged": 18655, "fools": 18656, "##grapher": 18657, "faculties": 18658, "qaeda": 18659, "##vial": 18660, "garner": 18661, "refurbished": 18662, "##hwa": 18663, "geelong": 18664, "disasters": 18665, "nudged": 18666, "bs": 18667, "shareholder": 18668, "lori": 18669, "algae": 18670, "reinstated": 18671, "rot": 18672, "##ades": 18673, "##nous": 18674, "invites": 18675, "stainless": 18676, "183": 18677, "inclusive": 18678, "##itude": 18679, "diocesan": 18680, "til": 18681, "##icz": 18682, "denomination": 18683, "##xa": 18684, "benton": 18685, "floral": 18686, "registers": 18687, "##ider": 18688, "##erman": 18689, "##kell": 18690, "absurd": 18691, "brunei": 18692, "guangzhou": 18693, "hitter": 18694, "retaliation": 18695, "##uled": 18696, "##eve": 18697, "blanc": 18698, "nh": 18699, "consistency": 18700, "contamination": 18701, "##eres": 18702, "##rner": 18703, "dire": 18704, "palermo": 18705, "broadcasters": 18706, "diaries": 18707, "inspire": 18708, "vols": 18709, "brewer": 18710, "tightening": 18711, "ky": 18712, "mixtape": 18713, "hormone": 18714, "##tok": 18715, "stokes": 18716, "##color": 18717, "##dly": 18718, "##ssi": 18719, "pg": 18720, "##ometer": 18721, "##lington": 18722, "sanitation": 18723, "##tility": 18724, "intercontinental": 18725, "apps": 18726, "##adt": 18727, "¹⁄₂": 18728, "cylinders": 18729, "economies": 18730, "favourable": 18731, "unison": 18732, "croix": 18733, "gertrude": 18734, "odyssey": 18735, "vanity": 18736, "dangling": 18737, "##logists": 18738, "upgrades": 18739, "dice": 18740, "middleweight": 18741, "practitioner": 18742, "##ight": 18743, "206": 18744, "henrik": 18745, "parlor": 18746, "orion": 18747, "angered": 18748, "lac": 18749, "python": 18750, "blurted": 18751, "##rri": 18752, "sensual": 18753, "intends": 18754, "swings": 18755, "angled": 18756, "##phs": 18757, "husky": 18758, "attain": 18759, "peerage": 18760, "precinct": 18761, "textiles": 18762, "cheltenham": 18763, "shuffled": 18764, "dai": 18765, "confess": 18766, "tasting": 18767, "bhutan": 18768, "##riation": 18769, "tyrone": 18770, "segregation": 18771, "abrupt": 18772, "ruiz": 18773, "##rish": 18774, "smirked": 18775, "blackwell": 18776, "confidential": 18777, "browning": 18778, "amounted": 18779, "##put": 18780, "vase": 18781, "scarce": 18782, "fabulous": 18783, "raided": 18784, "staple": 18785, "guyana": 18786, "unemployed": 18787, "glider": 18788, "shay": 18789, "##tow": 18790, "carmine": 18791, "troll": 18792, "intervene": 18793, "squash": 18794, "superstar": 18795, "##uce": 18796, "cylindrical": 18797, "len": 18798, "roadway": 18799, "researched": 18800, "handy": 18801, "##rium": 18802, "##jana": 18803, "meta": 18804, "lao": 18805, "declares": 18806, "##rring": 18807, "##tadt": 18808, "##elin": 18809, "##kova": 18810, "willem": 18811, "shrubs": 18812, "napoleonic": 18813, "realms": 18814, "skater": 18815, "qi": 18816, "volkswagen": 18817, "##ł": 18818, "tad": 18819, "hara": 18820, "archaeologist": 18821, "awkwardly": 18822, "eerie": 18823, "##kind": 18824, "wiley": 18825, "##heimer": 18826, "##24": 18827, "titus": 18828, "organizers": 18829, "cfl": 18830, "crusaders": 18831, "lama": 18832, "usb": 18833, "vent": 18834, "enraged": 18835, "thankful": 18836, "occupants": 18837, "maximilian": 18838, "##gaard": 18839, "possessing": 18840, "textbooks": 18841, "##oran": 18842, "collaborator": 18843, "quaker": 18844, "##ulo": 18845, "avalanche": 18846, "mono": 18847, "silky": 18848, "straits": 18849, "isaiah": 18850, "mustang": 18851, "surged": 18852, "resolutions": 18853, "potomac": 18854, "descend": 18855, "cl": 18856, "kilograms": 18857, "plato": 18858, "strains": 18859, "saturdays": 18860, "##olin": 18861, "bernstein": 18862, "##ype": 18863, "holstein": 18864, "ponytail": 18865, "##watch": 18866, "belize": 18867, "conversely": 18868, "heroine": 18869, "perpetual": 18870, "##ylus": 18871, "charcoal": 18872, "piedmont": 18873, "glee": 18874, "negotiating": 18875, "backdrop": 18876, "prologue": 18877, "##jah": 18878, "##mmy": 18879, "pasadena": 18880, "climbs": 18881, "ramos": 18882, "sunni": 18883, "##holm": 18884, "##tner": 18885, "##tri": 18886, "anand": 18887, "deficiency": 18888, "hertfordshire": 18889, "stout": 18890, "##avi": 18891, "aperture": 18892, "orioles": 18893, "##irs": 18894, "doncaster": 18895, "intrigued": 18896, "bombed": 18897, "coating": 18898, "otis": 18899, "##mat": 18900, "cocktail": 18901, "##jit": 18902, "##eto": 18903, "amir": 18904, "arousal": 18905, "sar": 18906, "##proof": 18907, "##act": 18908, "##ories": 18909, "dixie": 18910, "pots": 18911, "##bow": 18912, "whereabouts": 18913, "159": 18914, "##fted": 18915, "drains": 18916, "bullying": 18917, "cottages": 18918, "scripture": 18919, "coherent": 18920, "fore": 18921, "poe": 18922, "appetite": 18923, "##uration": 18924, "sampled": 18925, "##ators": 18926, "##dp": 18927, "derrick": 18928, "rotor": 18929, "jays": 18930, "peacock": 18931, "installment": 18932, "##rro": 18933, "advisors": 18934, "##coming": 18935, "rodeo": 18936, "scotch": 18937, "##mot": 18938, "##db": 18939, "##fen": 18940, "##vant": 18941, "ensued": 18942, "rodrigo": 18943, "dictatorship": 18944, "martyrs": 18945, "twenties": 18946, "##н": 18947, "towed": 18948, "incidence": 18949, "marta": 18950, "rainforest": 18951, "sai": 18952, "scaled": 18953, "##cles": 18954, "oceanic": 18955, "qualifiers": 18956, "symphonic": 18957, "mcbride": 18958, "dislike": 18959, "generalized": 18960, "aubrey": 18961, "colonization": 18962, "##iation": 18963, "##lion": 18964, "##ssing": 18965, "disliked": 18966, "lublin": 18967, "salesman": 18968, "##ulates": 18969, "spherical": 18970, "whatsoever": 18971, "sweating": 18972, "avalon": 18973, "contention": 18974, "punt": 18975, "severity": 18976, "alderman": 18977, "atari": 18978, "##dina": 18979, "##grant": 18980, "##rop": 18981, "scarf": 18982, "seville": 18983, "vertices": 18984, "annexation": 18985, "fairfield": 18986, "fascination": 18987, "inspiring": 18988, "launches": 18989, "palatinate": 18990, "regretted": 18991, "##rca": 18992, "feral": 18993, "##iom": 18994, "elk": 18995, "nap": 18996, "olsen": 18997, "reddy": 18998, "yong": 18999, "##leader": 19000, "##iae": 19001, "garment": 19002, "transports": 19003, "feng": 19004, "gracie": 19005, "outrage": 19006, "viceroy": 19007, "insides": 19008, "##esis": 19009, "breakup": 19010, "grady": 19011, "organizer": 19012, "softer": 19013, "grimaced": 19014, "222": 19015, "murals": 19016, "galicia": 19017, "arranging": 19018, "vectors": 19019, "##rsten": 19020, "bas": 19021, "##sb": 19022, "##cens": 19023, "sloan": 19024, "##eka": 19025, "bitten": 19026, "ara": 19027, "fender": 19028, "nausea": 19029, "bumped": 19030, "kris": 19031, "banquet": 19032, "comrades": 19033, "detector": 19034, "persisted": 19035, "##llan": 19036, "adjustment": 19037, "endowed": 19038, "cinemas": 19039, "##shot": 19040, "sellers": 19041, "##uman": 19042, "peek": 19043, "epa": 19044, "kindly": 19045, "neglect": 19046, "simpsons": 19047, "talon": 19048, "mausoleum": 19049, "runaway": 19050, "hangul": 19051, "lookout": 19052, "##cic": 19053, "rewards": 19054, "coughed": 19055, "acquainted": 19056, "chloride": 19057, "##ald": 19058, "quicker": 19059, "accordion": 19060, "neolithic": 19061, "##qa": 19062, "artemis": 19063, "coefficient": 19064, "lenny": 19065, "pandora": 19066, "tx": 19067, "##xed": 19068, "ecstasy": 19069, "litter": 19070, "segunda": 19071, "chairperson": 19072, "gemma": 19073, "hiss": 19074, "rumor": 19075, "vow": 19076, "nasal": 19077, "antioch": 19078, "compensate": 19079, "patiently": 19080, "transformers": 19081, "##eded": 19082, "judo": 19083, "morrow": 19084, "penis": 19085, "posthumous": 19086, "philips": 19087, "bandits": 19088, "husbands": 19089, "denote": 19090, "flaming": 19091, "##any": 19092, "##phones": 19093, "langley": 19094, "yorker": 19095, "1760": 19096, "walters": 19097, "##uo": 19098, "##kle": 19099, "gubernatorial": 19100, "fatty": 19101, "samsung": 19102, "leroy": 19103, "outlaw": 19104, "##nine": 19105, "unpublished": 19106, "poole": 19107, "jakob": 19108, "##ᵢ": 19109, "##ₙ": 19110, "crete": 19111, "distorted": 19112, "superiority": 19113, "##dhi": 19114, "intercept": 19115, "crust": 19116, "mig": 19117, "claus": 19118, "crashes": 19119, "positioning": 19120, "188": 19121, "stallion": 19122, "301": 19123, "frontal": 19124, "armistice": 19125, "##estinal": 19126, "elton": 19127, "aj": 19128, "encompassing": 19129, "camel": 19130, "commemorated": 19131, "malaria": 19132, "woodward": 19133, "calf": 19134, "cigar": 19135, "penetrate": 19136, "##oso": 19137, "willard": 19138, "##rno": 19139, "##uche": 19140, "illustrate": 19141, "amusing": 19142, "convergence": 19143, "noteworthy": 19144, "##lma": 19145, "##rva": 19146, "journeys": 19147, "realise": 19148, "manfred": 19149, "##sable": 19150, "410": 19151, "##vocation": 19152, "hearings": 19153, "fiance": 19154, "##posed": 19155, "educators": 19156, "provoked": 19157, "adjusting": 19158, "##cturing": 19159, "modular": 19160, "stockton": 19161, "paterson": 19162, "vlad": 19163, "rejects": 19164, "electors": 19165, "selena": 19166, "maureen": 19167, "##tres": 19168, "uber": 19169, "##rce": 19170, "swirled": 19171, "##num": 19172, "proportions": 19173, "nanny": 19174, "pawn": 19175, "naturalist": 19176, "parma": 19177, "apostles": 19178, "awoke": 19179, "ethel": 19180, "wen": 19181, "##bey": 19182, "monsoon": 19183, "overview": 19184, "##inating": 19185, "mccain": 19186, "rendition": 19187, "risky": 19188, "adorned": 19189, "##ih": 19190, "equestrian": 19191, "germain": 19192, "nj": 19193, "conspicuous": 19194, "confirming": 19195, "##yoshi": 19196, "shivering": 19197, "##imeter": 19198, "milestone": 19199, "rumours": 19200, "flinched": 19201, "bounds": 19202, "smacked": 19203, "token": 19204, "##bei": 19205, "lectured": 19206, "automobiles": 19207, "##shore": 19208, "impacted": 19209, "##iable": 19210, "nouns": 19211, "nero": 19212, "##leaf": 19213, "ismail": 19214, "prostitute": 19215, "trams": 19216, "##lace": 19217, "bridget": 19218, "sud": 19219, "stimulus": 19220, "impressions": 19221, "reins": 19222, "revolves": 19223, "##oud": 19224, "##gned": 19225, "giro": 19226, "honeymoon": 19227, "##swell": 19228, "criterion": 19229, "##sms": 19230, "##uil": 19231, "libyan": 19232, "prefers": 19233, "##osition": 19234, "211": 19235, "preview": 19236, "sucks": 19237, "accusation": 19238, "bursts": 19239, "metaphor": 19240, "diffusion": 19241, "tolerate": 19242, "faye": 19243, "betting": 19244, "cinematographer": 19245, "liturgical": 19246, "specials": 19247, "bitterly": 19248, "humboldt": 19249, "##ckle": 19250, "flux": 19251, "rattled": 19252, "##itzer": 19253, "archaeologists": 19254, "odor": 19255, "authorised": 19256, "marshes": 19257, "discretion": 19258, "##ов": 19259, "alarmed": 19260, "archaic": 19261, "inverse": 19262, "##leton": 19263, "explorers": 19264, "##pine": 19265, "drummond": 19266, "tsunami": 19267, "woodlands": 19268, "##minate": 19269, "##tland": 19270, "booklet": 19271, "insanity": 19272, "owning": 19273, "insert": 19274, "crafted": 19275, "calculus": 19276, "##tore": 19277, "receivers": 19278, "##bt": 19279, "stung": 19280, "##eca": 19281, "##nched": 19282, "prevailing": 19283, "travellers": 19284, "eyeing": 19285, "lila": 19286, "graphs": 19287, "##borne": 19288, "178": 19289, "julien": 19290, "##won": 19291, "morale": 19292, "adaptive": 19293, "therapist": 19294, "erica": 19295, "cw": 19296, "libertarian": 19297, "bowman": 19298, "pitches": 19299, "vita": 19300, "##ional": 19301, "crook": 19302, "##ads": 19303, "##entation": 19304, "caledonia": 19305, "mutiny": 19306, "##sible": 19307, "1840s": 19308, "automation": 19309, "##ß": 19310, "flock": 19311, "##pia": 19312, "ironic": 19313, "pathology": 19314, "##imus": 19315, "remarried": 19316, "##22": 19317, "joker": 19318, "withstand": 19319, "energies": 19320, "##att": 19321, "shropshire": 19322, "hostages": 19323, "madeleine": 19324, "tentatively": 19325, "conflicting": 19326, "mateo": 19327, "recipes": 19328, "euros": 19329, "ol": 19330, "mercenaries": 19331, "nico": 19332, "##ndon": 19333, "albuquerque": 19334, "augmented": 19335, "mythical": 19336, "bel": 19337, "freud": 19338, "##child": 19339, "cough": 19340, "##lica": 19341, "365": 19342, "freddy": 19343, "lillian": 19344, "genetically": 19345, "nuremberg": 19346, "calder": 19347, "209": 19348, "bonn": 19349, "outdoors": 19350, "paste": 19351, "suns": 19352, "urgency": 19353, "vin": 19354, "restraint": 19355, "tyson": 19356, "##cera": 19357, "##selle": 19358, "barrage": 19359, "bethlehem": 19360, "kahn": 19361, "##par": 19362, "mounts": 19363, "nippon": 19364, "barony": 19365, "happier": 19366, "ryu": 19367, "makeshift": 19368, "sheldon": 19369, "blushed": 19370, "castillo": 19371, "barking": 19372, "listener": 19373, "taped": 19374, "bethel": 19375, "fluent": 19376, "headlines": 19377, "pornography": 19378, "rum": 19379, "disclosure": 19380, "sighing": 19381, "mace": 19382, "doubling": 19383, "gunther": 19384, "manly": 19385, "##plex": 19386, "rt": 19387, "interventions": 19388, "physiological": 19389, "forwards": 19390, "emerges": 19391, "##tooth": 19392, "##gny": 19393, "compliment": 19394, "rib": 19395, "recession": 19396, "visibly": 19397, "barge": 19398, "faults": 19399, "connector": 19400, "exquisite": 19401, "prefect": 19402, "##rlin": 19403, "patio": 19404, "##cured": 19405, "elevators": 19406, "brandt": 19407, "italics": 19408, "pena": 19409, "173": 19410, "wasp": 19411, "satin": 19412, "ea": 19413, "botswana": 19414, "graceful": 19415, "respectable": 19416, "##jima": 19417, "##rter": 19418, "##oic": 19419, "franciscan": 19420, "generates": 19421, "##dl": 19422, "alfredo": 19423, "disgusting": 19424, "##olate": 19425, "##iously": 19426, "sherwood": 19427, "warns": 19428, "cod": 19429, "promo": 19430, "cheryl": 19431, "sino": 19432, "##ة": 19433, "##escu": 19434, "twitch": 19435, "##zhi": 19436, "brownish": 19437, "thom": 19438, "ortiz": 19439, "##dron": 19440, "densely": 19441, "##beat": 19442, "carmel": 19443, "reinforce": 19444, "##bana": 19445, "187": 19446, "anastasia": 19447, "downhill": 19448, "vertex": 19449, "contaminated": 19450, "remembrance": 19451, "harmonic": 19452, "homework": 19453, "##sol": 19454, "fiancee": 19455, "gears": 19456, "olds": 19457, "angelica": 19458, "loft": 19459, "ramsay": 19460, "quiz": 19461, "colliery": 19462, "sevens": 19463, "##cape": 19464, "autism": 19465, "##hil": 19466, "walkway": 19467, "##boats": 19468, "ruben": 19469, "abnormal": 19470, "ounce": 19471, "khmer": 19472, "##bbe": 19473, "zachary": 19474, "bedside": 19475, "morphology": 19476, "punching": 19477, "##olar": 19478, "sparrow": 19479, "convinces": 19480, "##35": 19481, "hewitt": 19482, "queer": 19483, "remastered": 19484, "rods": 19485, "mabel": 19486, "solemn": 19487, "notified": 19488, "lyricist": 19489, "symmetric": 19490, "##xide": 19491, "174": 19492, "encore": 19493, "passports": 19494, "wildcats": 19495, "##uni": 19496, "baja": 19497, "##pac": 19498, "mildly": 19499, "##ease": 19500, "bleed": 19501, "commodity": 19502, "mounds": 19503, "glossy": 19504, "orchestras": 19505, "##omo": 19506, "damian": 19507, "prelude": 19508, "ambitions": 19509, "##vet": 19510, "awhile": 19511, "remotely": 19512, "##aud": 19513, "asserts": 19514, "imply": 19515, "##iques": 19516, "distinctly": 19517, "modelling": 19518, "remedy": 19519, "##dded": 19520, "windshield": 19521, "dani": 19522, "xiao": 19523, "##endra": 19524, "audible": 19525, "powerplant": 19526, "1300": 19527, "invalid": 19528, "elemental": 19529, "acquisitions": 19530, "##hala": 19531, "immaculate": 19532, "libby": 19533, "plata": 19534, "smuggling": 19535, "ventilation": 19536, "denoted": 19537, "minh": 19538, "##morphism": 19539, "430": 19540, "differed": 19541, "dion": 19542, "kelley": 19543, "lore": 19544, "mocking": 19545, "sabbath": 19546, "spikes": 19547, "hygiene": 19548, "drown": 19549, "runoff": 19550, "stylized": 19551, "tally": 19552, "liberated": 19553, "aux": 19554, "interpreter": 19555, "righteous": 19556, "aba": 19557, "siren": 19558, "reaper": 19559, "pearce": 19560, "millie": 19561, "##cier": 19562, "##yra": 19563, "gaius": 19564, "##iso": 19565, "captures": 19566, "##ttering": 19567, "dorm": 19568, "claudio": 19569, "##sic": 19570, "benches": 19571, "knighted": 19572, "blackness": 19573, "##ored": 19574, "discount": 19575, "fumble": 19576, "oxidation": 19577, "routed": 19578, "##ς": 19579, "novak": 19580, "perpendicular": 19581, "spoiled": 19582, "fracture": 19583, "splits": 19584, "##urt": 19585, "pads": 19586, "topology": 19587, "##cats": 19588, "axes": 19589, "fortunate": 19590, "offenders": 19591, "protestants": 19592, "esteem": 19593, "221": 19594, "broadband": 19595, "convened": 19596, "frankly": 19597, "hound": 19598, "prototypes": 19599, "isil": 19600, "facilitated": 19601, "keel": 19602, "##sher": 19603, "sahara": 19604, "awaited": 19605, "bubba": 19606, "orb": 19607, "prosecutors": 19608, "186": 19609, "hem": 19610, "520": 19611, "##xing": 19612, "relaxing": 19613, "remnant": 19614, "romney": 19615, "sorted": 19616, "slalom": 19617, "stefano": 19618, "ulrich": 19619, "##active": 19620, "exemption": 19621, "folder": 19622, "pauses": 19623, "foliage": 19624, "hitchcock": 19625, "epithet": 19626, "204": 19627, "criticisms": 19628, "##aca": 19629, "ballistic": 19630, "brody": 19631, "hinduism": 19632, "chaotic": 19633, "youths": 19634, "equals": 19635, "##pala": 19636, "pts": 19637, "thicker": 19638, "analogous": 19639, "capitalist": 19640, "improvised": 19641, "overseeing": 19642, "sinatra": 19643, "ascended": 19644, "beverage": 19645, "##tl": 19646, "straightforward": 19647, "##kon": 19648, "curran": 19649, "##west": 19650, "bois": 19651, "325": 19652, "induce": 19653, "surveying": 19654, "emperors": 19655, "sax": 19656, "unpopular": 19657, "##kk": 19658, "cartoonist": 19659, "fused": 19660, "##mble": 19661, "unto": 19662, "##yuki": 19663, "localities": 19664, "##cko": 19665, "##ln": 19666, "darlington": 19667, "slain": 19668, "academie": 19669, "lobbying": 19670, "sediment": 19671, "puzzles": 19672, "##grass": 19673, "defiance": 19674, "dickens": 19675, "manifest": 19676, "tongues": 19677, "alumnus": 19678, "arbor": 19679, "coincide": 19680, "184": 19681, "appalachian": 19682, "mustafa": 19683, "examiner": 19684, "cabaret": 19685, "traumatic": 19686, "yves": 19687, "bracelet": 19688, "draining": 19689, "heroin": 19690, "magnum": 19691, "baths": 19692, "odessa": 19693, "consonants": 19694, "mitsubishi": 19695, "##gua": 19696, "kellan": 19697, "vaudeville": 19698, "##fr": 19699, "joked": 19700, "null": 19701, "straps": 19702, "probation": 19703, "##ław": 19704, "ceded": 19705, "interfaces": 19706, "##pas": 19707, "##zawa": 19708, "blinding": 19709, "viet": 19710, "224": 19711, "rothschild": 19712, "museo": 19713, "640": 19714, "huddersfield": 19715, "##vr": 19716, "tactic": 19717, "##storm": 19718, "brackets": 19719, "dazed": 19720, "incorrectly": 19721, "##vu": 19722, "reg": 19723, "glazed": 19724, "fearful": 19725, "manifold": 19726, "benefited": 19727, "irony": 19728, "##sun": 19729, "stumbling": 19730, "##rte": 19731, "willingness": 19732, "balkans": 19733, "mei": 19734, "wraps": 19735, "##aba": 19736, "injected": 19737, "##lea": 19738, "gu": 19739, "syed": 19740, "harmless": 19741, "##hammer": 19742, "bray": 19743, "takeoff": 19744, "poppy": 19745, "timor": 19746, "cardboard": 19747, "astronaut": 19748, "purdue": 19749, "weeping": 19750, "southbound": 19751, "cursing": 19752, "stalls": 19753, "diagonal": 19754, "##neer": 19755, "lamar": 19756, "bryce": 19757, "comte": 19758, "weekdays": 19759, "harrington": 19760, "##uba": 19761, "negatively": 19762, "##see": 19763, "lays": 19764, "grouping": 19765, "##cken": 19766, "##henko": 19767, "affirmed": 19768, "halle": 19769, "modernist": 19770, "##lai": 19771, "hodges": 19772, "smelling": 19773, "aristocratic": 19774, "baptized": 19775, "dismiss": 19776, "justification": 19777, "oilers": 19778, "##now": 19779, "coupling": 19780, "qin": 19781, "snack": 19782, "healer": 19783, "##qing": 19784, "gardener": 19785, "layla": 19786, "battled": 19787, "formulated": 19788, "stephenson": 19789, "gravitational": 19790, "##gill": 19791, "##jun": 19792, "1768": 19793, "granny": 19794, "coordinating": 19795, "suites": 19796, "##cd": 19797, "##ioned": 19798, "monarchs": 19799, "##cote": 19800, "##hips": 19801, "sep": 19802, "blended": 19803, "apr": 19804, "barrister": 19805, "deposition": 19806, "fia": 19807, "mina": 19808, "policemen": 19809, "paranoid": 19810, "##pressed": 19811, "churchyard": 19812, "covert": 19813, "crumpled": 19814, "creep": 19815, "abandoning": 19816, "tr": 19817, "transmit": 19818, "conceal": 19819, "barr": 19820, "understands": 19821, "readiness": 19822, "spire": 19823, "##cology": 19824, "##enia": 19825, "##erry": 19826, "610": 19827, "startling": 19828, "unlock": 19829, "vida": 19830, "bowled": 19831, "slots": 19832, "##nat": 19833, "##islav": 19834, "spaced": 19835, "trusting": 19836, "admire": 19837, "rig": 19838, "##ink": 19839, "slack": 19840, "##70": 19841, "mv": 19842, "207": 19843, "casualty": 19844, "##wei": 19845, "classmates": 19846, "##odes": 19847, "##rar": 19848, "##rked": 19849, "amherst": 19850, "furnished": 19851, "evolve": 19852, "foundry": 19853, "menace": 19854, "mead": 19855, "##lein": 19856, "flu": 19857, "wesleyan": 19858, "##kled": 19859, "monterey": 19860, "webber": 19861, "##vos": 19862, "wil": 19863, "##mith": 19864, "##на": 19865, "bartholomew": 19866, "justices": 19867, "restrained": 19868, "##cke": 19869, "amenities": 19870, "191": 19871, "mediated": 19872, "sewage": 19873, "trenches": 19874, "ml": 19875, "mainz": 19876, "##thus": 19877, "1800s": 19878, "##cula": 19879, "##inski": 19880, "caine": 19881, "bonding": 19882, "213": 19883, "converts": 19884, "spheres": 19885, "superseded": 19886, "marianne": 19887, "crypt": 19888, "sweaty": 19889, "ensign": 19890, "historia": 19891, "##br": 19892, "spruce": 19893, "##post": 19894, "##ask": 19895, "forks": 19896, "thoughtfully": 19897, "yukon": 19898, "pamphlet": 19899, "ames": 19900, "##uter": 19901, "karma": 19902, "##yya": 19903, "bryn": 19904, "negotiation": 19905, "sighs": 19906, "incapable": 19907, "##mbre": 19908, "##ntial": 19909, "actresses": 19910, "taft": 19911, "##mill": 19912, "luce": 19913, "prevailed": 19914, "##amine": 19915, "1773": 19916, "motionless": 19917, "envoy": 19918, "testify": 19919, "investing": 19920, "sculpted": 19921, "instructors": 19922, "provence": 19923, "kali": 19924, "cullen": 19925, "horseback": 19926, "##while": 19927, "goodwin": 19928, "##jos": 19929, "gaa": 19930, "norte": 19931, "##ldon": 19932, "modify": 19933, "wavelength": 19934, "abd": 19935, "214": 19936, "skinned": 19937, "sprinter": 19938, "forecast": 19939, "scheduling": 19940, "marries": 19941, "squared": 19942, "tentative": 19943, "##chman": 19944, "boer": 19945, "##isch": 19946, "bolts": 19947, "swap": 19948, "fisherman": 19949, "assyrian": 19950, "impatiently": 19951, "guthrie": 19952, "martins": 19953, "murdoch": 19954, "194": 19955, "tanya": 19956, "nicely": 19957, "dolly": 19958, "lacy": 19959, "med": 19960, "##45": 19961, "syn": 19962, "decks": 19963, "fashionable": 19964, "millionaire": 19965, "##ust": 19966, "surfing": 19967, "##ml": 19968, "##ision": 19969, "heaved": 19970, "tammy": 19971, "consulate": 19972, "attendees": 19973, "routinely": 19974, "197": 19975, "fuse": 19976, "saxophonist": 19977, "backseat": 19978, "malaya": 19979, "##lord": 19980, "scowl": 19981, "tau": 19982, "##ishly": 19983, "193": 19984, "sighted": 19985, "steaming": 19986, "##rks": 19987, "303": 19988, "911": 19989, "##holes": 19990, "##hong": 19991, "ching": 19992, "##wife": 19993, "bless": 19994, "conserved": 19995, "jurassic": 19996, "stacey": 19997, "unix": 19998, "zion": 19999, "chunk": 20000, "rigorous": 20001, "blaine": 20002, "198": 20003, "peabody": 20004, "slayer": 20005, "dismay": 20006, "brewers": 20007, "nz": 20008, "##jer": 20009, "det": 20010, "##glia": 20011, "glover": 20012, "postwar": 20013, "int": 20014, "penetration": 20015, "sylvester": 20016, "imitation": 20017, "vertically": 20018, "airlift": 20019, "heiress": 20020, "knoxville": 20021, "viva": 20022, "##uin": 20023, "390": 20024, "macon": 20025, "##rim": 20026, "##fighter": 20027, "##gonal": 20028, "janice": 20029, "##orescence": 20030, "##wari": 20031, "marius": 20032, "belongings": 20033, "leicestershire": 20034, "196": 20035, "blanco": 20036, "inverted": 20037, "preseason": 20038, "sanity": 20039, "sobbing": 20040, "##due": 20041, "##elt": 20042, "##dled": 20043, "collingwood": 20044, "regeneration": 20045, "flickering": 20046, "shortest": 20047, "##mount": 20048, "##osi": 20049, "feminism": 20050, "##lat": 20051, "sherlock": 20052, "cabinets": 20053, "fumbled": 20054, "northbound": 20055, "precedent": 20056, "snaps": 20057, "##mme": 20058, "researching": 20059, "##akes": 20060, "guillaume": 20061, "insights": 20062, "manipulated": 20063, "vapor": 20064, "neighbour": 20065, "sap": 20066, "gangster": 20067, "frey": 20068, "f1": 20069, "stalking": 20070, "scarcely": 20071, "callie": 20072, "barnett": 20073, "tendencies": 20074, "audi": 20075, "doomed": 20076, "assessing": 20077, "slung": 20078, "panchayat": 20079, "ambiguous": 20080, "bartlett": 20081, "##etto": 20082, "distributing": 20083, "violating": 20084, "wolverhampton": 20085, "##hetic": 20086, "swami": 20087, "histoire": 20088, "##urus": 20089, "liable": 20090, "pounder": 20091, "groin": 20092, "hussain": 20093, "larsen": 20094, "popping": 20095, "surprises": 20096, "##atter": 20097, "vie": 20098, "curt": 20099, "##station": 20100, "mute": 20101, "relocate": 20102, "musicals": 20103, "authorization": 20104, "richter": 20105, "##sef": 20106, "immortality": 20107, "tna": 20108, "bombings": 20109, "##press": 20110, "deteriorated": 20111, "yiddish": 20112, "##acious": 20113, "robbed": 20114, "colchester": 20115, "cs": 20116, "pmid": 20117, "ao": 20118, "verified": 20119, "balancing": 20120, "apostle": 20121, "swayed": 20122, "recognizable": 20123, "oxfordshire": 20124, "retention": 20125, "nottinghamshire": 20126, "contender": 20127, "judd": 20128, "invitational": 20129, "shrimp": 20130, "uhf": 20131, "##icient": 20132, "cleaner": 20133, "longitudinal": 20134, "tanker": 20135, "##mur": 20136, "acronym": 20137, "broker": 20138, "koppen": 20139, "sundance": 20140, "suppliers": 20141, "##gil": 20142, "4000": 20143, "clipped": 20144, "fuels": 20145, "petite": 20146, "##anne": 20147, "landslide": 20148, "helene": 20149, "diversion": 20150, "populous": 20151, "landowners": 20152, "auspices": 20153, "melville": 20154, "quantitative": 20155, "##xes": 20156, "ferries": 20157, "nicky": 20158, "##llus": 20159, "doo": 20160, "haunting": 20161, "roche": 20162, "carver": 20163, "downed": 20164, "unavailable": 20165, "##pathy": 20166, "approximation": 20167, "hiroshima": 20168, "##hue": 20169, "garfield": 20170, "valle": 20171, "comparatively": 20172, "keyboardist": 20173, "traveler": 20174, "##eit": 20175, "congestion": 20176, "calculating": 20177, "subsidiaries": 20178, "##bate": 20179, "serb": 20180, "modernization": 20181, "fairies": 20182, "deepened": 20183, "ville": 20184, "averages": 20185, "##lore": 20186, "inflammatory": 20187, "tonga": 20188, "##itch": 20189, "co₂": 20190, "squads": 20191, "##hea": 20192, "gigantic": 20193, "serum": 20194, "enjoyment": 20195, "retailer": 20196, "verona": 20197, "35th": 20198, "cis": 20199, "##phobic": 20200, "magna": 20201, "technicians": 20202, "##vati": 20203, "arithmetic": 20204, "##sport": 20205, "levin": 20206, "##dation": 20207, "amtrak": 20208, "chow": 20209, "sienna": 20210, "##eyer": 20211, "backstage": 20212, "entrepreneurship": 20213, "##otic": 20214, "learnt": 20215, "tao": 20216, "##udy": 20217, "worcestershire": 20218, "formulation": 20219, "baggage": 20220, "hesitant": 20221, "bali": 20222, "sabotage": 20223, "##kari": 20224, "barren": 20225, "enhancing": 20226, "murmur": 20227, "pl": 20228, "freshly": 20229, "putnam": 20230, "syntax": 20231, "aces": 20232, "medicines": 20233, "resentment": 20234, "bandwidth": 20235, "##sier": 20236, "grins": 20237, "chili": 20238, "guido": 20239, "##sei": 20240, "framing": 20241, "implying": 20242, "gareth": 20243, "lissa": 20244, "genevieve": 20245, "pertaining": 20246, "admissions": 20247, "geo": 20248, "thorpe": 20249, "proliferation": 20250, "sato": 20251, "bela": 20252, "analyzing": 20253, "parting": 20254, "##gor": 20255, "awakened": 20256, "##isman": 20257, "huddled": 20258, "secrecy": 20259, "##kling": 20260, "hush": 20261, "gentry": 20262, "540": 20263, "dungeons": 20264, "##ego": 20265, "coasts": 20266, "##utz": 20267, "sacrificed": 20268, "##chule": 20269, "landowner": 20270, "mutually": 20271, "prevalence": 20272, "programmer": 20273, "adolescent": 20274, "disrupted": 20275, "seaside": 20276, "gee": 20277, "trusts": 20278, "vamp": 20279, "georgie": 20280, "##nesian": 20281, "##iol": 20282, "schedules": 20283, "sindh": 20284, "##market": 20285, "etched": 20286, "hm": 20287, "sparse": 20288, "bey": 20289, "beaux": 20290, "scratching": 20291, "gliding": 20292, "unidentified": 20293, "216": 20294, "collaborating": 20295, "gems": 20296, "jesuits": 20297, "oro": 20298, "accumulation": 20299, "shaping": 20300, "mbe": 20301, "anal": 20302, "##xin": 20303, "231": 20304, "enthusiasts": 20305, "newscast": 20306, "##egan": 20307, "janata": 20308, "dewey": 20309, "parkinson": 20310, "179": 20311, "ankara": 20312, "biennial": 20313, "towering": 20314, "dd": 20315, "inconsistent": 20316, "950": 20317, "##chet": 20318, "thriving": 20319, "terminate": 20320, "cabins": 20321, "furiously": 20322, "eats": 20323, "advocating": 20324, "donkey": 20325, "marley": 20326, "muster": 20327, "phyllis": 20328, "leiden": 20329, "##user": 20330, "grassland": 20331, "glittering": 20332, "iucn": 20333, "loneliness": 20334, "217": 20335, "memorandum": 20336, "armenians": 20337, "##ddle": 20338, "popularized": 20339, "rhodesia": 20340, "60s": 20341, "lame": 20342, "##illon": 20343, "sans": 20344, "bikini": 20345, "header": 20346, "orbits": 20347, "##xx": 20348, "##finger": 20349, "##ulator": 20350, "sharif": 20351, "spines": 20352, "biotechnology": 20353, "strolled": 20354, "naughty": 20355, "yates": 20356, "##wire": 20357, "fremantle": 20358, "milo": 20359, "##mour": 20360, "abducted": 20361, "removes": 20362, "##atin": 20363, "humming": 20364, "wonderland": 20365, "##chrome": 20366, "##ester": 20367, "hume": 20368, "pivotal": 20369, "##rates": 20370, "armand": 20371, "grams": 20372, "believers": 20373, "elector": 20374, "rte": 20375, "apron": 20376, "bis": 20377, "scraped": 20378, "##yria": 20379, "endorsement": 20380, "initials": 20381, "##llation": 20382, "eps": 20383, "dotted": 20384, "hints": 20385, "buzzing": 20386, "emigration": 20387, "nearer": 20388, "##tom": 20389, "indicators": 20390, "##ulu": 20391, "coarse": 20392, "neutron": 20393, "protectorate": 20394, "##uze": 20395, "directional": 20396, "exploits": 20397, "pains": 20398, "loire": 20399, "1830s": 20400, "proponents": 20401, "guggenheim": 20402, "rabbits": 20403, "ritchie": 20404, "305": 20405, "hectare": 20406, "inputs": 20407, "hutton": 20408, "##raz": 20409, "verify": 20410, "##ako": 20411, "boilers": 20412, "longitude": 20413, "##lev": 20414, "skeletal": 20415, "yer": 20416, "emilia": 20417, "citrus": 20418, "compromised": 20419, "##gau": 20420, "pokemon": 20421, "prescription": 20422, "paragraph": 20423, "eduard": 20424, "cadillac": 20425, "attire": 20426, "categorized": 20427, "kenyan": 20428, "weddings": 20429, "charley": 20430, "##bourg": 20431, "entertain": 20432, "monmouth": 20433, "##lles": 20434, "nutrients": 20435, "davey": 20436, "mesh": 20437, "incentive": 20438, "practised": 20439, "ecosystems": 20440, "kemp": 20441, "subdued": 20442, "overheard": 20443, "##rya": 20444, "bodily": 20445, "maxim": 20446, "##nius": 20447, "apprenticeship": 20448, "ursula": 20449, "##fight": 20450, "lodged": 20451, "rug": 20452, "silesian": 20453, "unconstitutional": 20454, "patel": 20455, "inspected": 20456, "coyote": 20457, "unbeaten": 20458, "##hak": 20459, "34th": 20460, "disruption": 20461, "convict": 20462, "parcel": 20463, "##cl": 20464, "##nham": 20465, "collier": 20466, "implicated": 20467, "mallory": 20468, "##iac": 20469, "##lab": 20470, "susannah": 20471, "winkler": 20472, "##rber": 20473, "shia": 20474, "phelps": 20475, "sediments": 20476, "graphical": 20477, "robotic": 20478, "##sner": 20479, "adulthood": 20480, "mart": 20481, "smoked": 20482, "##isto": 20483, "kathryn": 20484, "clarified": 20485, "##aran": 20486, "divides": 20487, "convictions": 20488, "oppression": 20489, "pausing": 20490, "burying": 20491, "##mt": 20492, "federico": 20493, "mathias": 20494, "eileen": 20495, "##tana": 20496, "kite": 20497, "hunched": 20498, "##acies": 20499, "189": 20500, "##atz": 20501, "disadvantage": 20502, "liza": 20503, "kinetic": 20504, "greedy": 20505, "paradox": 20506, "yokohama": 20507, "dowager": 20508, "trunks": 20509, "ventured": 20510, "##gement": 20511, "gupta": 20512, "vilnius": 20513, "olaf": 20514, "##thest": 20515, "crimean": 20516, "hopper": 20517, "##ej": 20518, "progressively": 20519, "arturo": 20520, "mouthed": 20521, "arrondissement": 20522, "##fusion": 20523, "rubin": 20524, "simulcast": 20525, "oceania": 20526, "##orum": 20527, "##stra": 20528, "##rred": 20529, "busiest": 20530, "intensely": 20531, "navigator": 20532, "cary": 20533, "##vine": 20534, "##hini": 20535, "##bies": 20536, "fife": 20537, "rowe": 20538, "rowland": 20539, "posing": 20540, "insurgents": 20541, "shafts": 20542, "lawsuits": 20543, "activate": 20544, "conor": 20545, "inward": 20546, "culturally": 20547, "garlic": 20548, "265": 20549, "##eering": 20550, "eclectic": 20551, "##hui": 20552, "##kee": 20553, "##nl": 20554, "furrowed": 20555, "vargas": 20556, "meteorological": 20557, "rendezvous": 20558, "##aus": 20559, "culinary": 20560, "commencement": 20561, "##dition": 20562, "quota": 20563, "##notes": 20564, "mommy": 20565, "salaries": 20566, "overlapping": 20567, "mule": 20568, "##iology": 20569, "##mology": 20570, "sums": 20571, "wentworth": 20572, "##isk": 20573, "##zione": 20574, "mainline": 20575, "subgroup": 20576, "##illy": 20577, "hack": 20578, "plaintiff": 20579, "verdi": 20580, "bulb": 20581, "differentiation": 20582, "engagements": 20583, "multinational": 20584, "supplemented": 20585, "bertrand": 20586, "caller": 20587, "regis": 20588, "##naire": 20589, "##sler": 20590, "##arts": 20591, "##imated": 20592, "blossom": 20593, "propagation": 20594, "kilometer": 20595, "viaduct": 20596, "vineyards": 20597, "##uate": 20598, "beckett": 20599, "optimization": 20600, "golfer": 20601, "songwriters": 20602, "seminal": 20603, "semitic": 20604, "thud": 20605, "volatile": 20606, "evolving": 20607, "ridley": 20608, "##wley": 20609, "trivial": 20610, "distributions": 20611, "scandinavia": 20612, "jiang": 20613, "##ject": 20614, "wrestled": 20615, "insistence": 20616, "##dio": 20617, "emphasizes": 20618, "napkin": 20619, "##ods": 20620, "adjunct": 20621, "rhyme": 20622, "##ricted": 20623, "##eti": 20624, "hopeless": 20625, "surrounds": 20626, "tremble": 20627, "32nd": 20628, "smoky": 20629, "##ntly": 20630, "oils": 20631, "medicinal": 20632, "padded": 20633, "steer": 20634, "wilkes": 20635, "219": 20636, "255": 20637, "concessions": 20638, "hue": 20639, "uniquely": 20640, "blinded": 20641, "landon": 20642, "yahoo": 20643, "##lane": 20644, "hendrix": 20645, "commemorating": 20646, "dex": 20647, "specify": 20648, "chicks": 20649, "##ggio": 20650, "intercity": 20651, "1400": 20652, "morley": 20653, "##torm": 20654, "highlighting": 20655, "##oting": 20656, "pang": 20657, "oblique": 20658, "stalled": 20659, "##liner": 20660, "flirting": 20661, "newborn": 20662, "1769": 20663, "bishopric": 20664, "shaved": 20665, "232": 20666, "currie": 20667, "##ush": 20668, "dharma": 20669, "spartan": 20670, "##ooped": 20671, "favorites": 20672, "smug": 20673, "novella": 20674, "sirens": 20675, "abusive": 20676, "creations": 20677, "espana": 20678, "##lage": 20679, "paradigm": 20680, "semiconductor": 20681, "sheen": 20682, "##rdo": 20683, "##yen": 20684, "##zak": 20685, "nrl": 20686, "renew": 20687, "##pose": 20688, "##tur": 20689, "adjutant": 20690, "marches": 20691, "norma": 20692, "##enity": 20693, "ineffective": 20694, "weimar": 20695, "grunt": 20696, "##gat": 20697, "lordship": 20698, "plotting": 20699, "expenditure": 20700, "infringement": 20701, "lbs": 20702, "refrain": 20703, "av": 20704, "mimi": 20705, "mistakenly": 20706, "postmaster": 20707, "1771": 20708, "##bara": 20709, "ras": 20710, "motorsports": 20711, "tito": 20712, "199": 20713, "subjective": 20714, "##zza": 20715, "bully": 20716, "stew": 20717, "##kaya": 20718, "prescott": 20719, "1a": 20720, "##raphic": 20721, "##zam": 20722, "bids": 20723, "styling": 20724, "paranormal": 20725, "reeve": 20726, "sneaking": 20727, "exploding": 20728, "katz": 20729, "akbar": 20730, "migrant": 20731, "syllables": 20732, "indefinitely": 20733, "##ogical": 20734, "destroys": 20735, "replaces": 20736, "applause": 20737, "##phine": 20738, "pest": 20739, "##fide": 20740, "218": 20741, "articulated": 20742, "bertie": 20743, "##thing": 20744, "##cars": 20745, "##ptic": 20746, "courtroom": 20747, "crowley": 20748, "aesthetics": 20749, "cummings": 20750, "tehsil": 20751, "hormones": 20752, "titanic": 20753, "dangerously": 20754, "##ibe": 20755, "stadion": 20756, "jaenelle": 20757, "auguste": 20758, "ciudad": 20759, "##chu": 20760, "mysore": 20761, "partisans": 20762, "##sio": 20763, "lucan": 20764, "philipp": 20765, "##aly": 20766, "debating": 20767, "henley": 20768, "interiors": 20769, "##rano": 20770, "##tious": 20771, "homecoming": 20772, "beyonce": 20773, "usher": 20774, "henrietta": 20775, "prepares": 20776, "weeds": 20777, "##oman": 20778, "ely": 20779, "plucked": 20780, "##pire": 20781, "##dable": 20782, "luxurious": 20783, "##aq": 20784, "artifact": 20785, "password": 20786, "pasture": 20787, "juno": 20788, "maddy": 20789, "minsk": 20790, "##dder": 20791, "##ologies": 20792, "##rone": 20793, "assessments": 20794, "martian": 20795, "royalist": 20796, "1765": 20797, "examines": 20798, "##mani": 20799, "##rge": 20800, "nino": 20801, "223": 20802, "parry": 20803, "scooped": 20804, "relativity": 20805, "##eli": 20806, "##uting": 20807, "##cao": 20808, "congregational": 20809, "noisy": 20810, "traverse": 20811, "##agawa": 20812, "strikeouts": 20813, "nickelodeon": 20814, "obituary": 20815, "transylvania": 20816, "binds": 20817, "depictions": 20818, "polk": 20819, "trolley": 20820, "##yed": 20821, "##lard": 20822, "breeders": 20823, "##under": 20824, "dryly": 20825, "hokkaido": 20826, "1762": 20827, "strengths": 20828, "stacks": 20829, "bonaparte": 20830, "connectivity": 20831, "neared": 20832, "prostitutes": 20833, "stamped": 20834, "anaheim": 20835, "gutierrez": 20836, "sinai": 20837, "##zzling": 20838, "bram": 20839, "fresno": 20840, "madhya": 20841, "##86": 20842, "proton": 20843, "##lena": 20844, "##llum": 20845, "##phon": 20846, "reelected": 20847, "wanda": 20848, "##anus": 20849, "##lb": 20850, "ample": 20851, "distinguishing": 20852, "##yler": 20853, "grasping": 20854, "sermons": 20855, "tomato": 20856, "bland": 20857, "stimulation": 20858, "avenues": 20859, "##eux": 20860, "spreads": 20861, "scarlett": 20862, "fern": 20863, "pentagon": 20864, "assert": 20865, "baird": 20866, "chesapeake": 20867, "ir": 20868, "calmed": 20869, "distortion": 20870, "fatalities": 20871, "##olis": 20872, "correctional": 20873, "pricing": 20874, "##astic": 20875, "##gina": 20876, "prom": 20877, "dammit": 20878, "ying": 20879, "collaborate": 20880, "##chia": 20881, "welterweight": 20882, "33rd": 20883, "pointer": 20884, "substitution": 20885, "bonded": 20886, "umpire": 20887, "communicating": 20888, "multitude": 20889, "paddle": 20890, "##obe": 20891, "federally": 20892, "intimacy": 20893, "##insky": 20894, "betray": 20895, "ssr": 20896, "##lett": 20897, "##lean": 20898, "##lves": 20899, "##therapy": 20900, "airbus": 20901, "##tery": 20902, "functioned": 20903, "ud": 20904, "bearer": 20905, "biomedical": 20906, "netflix": 20907, "##hire": 20908, "##nca": 20909, "condom": 20910, "brink": 20911, "ik": 20912, "##nical": 20913, "macy": 20914, "##bet": 20915, "flap": 20916, "gma": 20917, "experimented": 20918, "jelly": 20919, "lavender": 20920, "##icles": 20921, "##ulia": 20922, "munro": 20923, "##mian": 20924, "##tial": 20925, "rye": 20926, "##rle": 20927, "60th": 20928, "gigs": 20929, "hottest": 20930, "rotated": 20931, "predictions": 20932, "fuji": 20933, "bu": 20934, "##erence": 20935, "##omi": 20936, "barangay": 20937, "##fulness": 20938, "##sas": 20939, "clocks": 20940, "##rwood": 20941, "##liness": 20942, "cereal": 20943, "roe": 20944, "wight": 20945, "decker": 20946, "uttered": 20947, "babu": 20948, "onion": 20949, "xml": 20950, "forcibly": 20951, "##df": 20952, "petra": 20953, "sarcasm": 20954, "hartley": 20955, "peeled": 20956, "storytelling": 20957, "##42": 20958, "##xley": 20959, "##ysis": 20960, "##ffa": 20961, "fibre": 20962, "kiel": 20963, "auditor": 20964, "fig": 20965, "harald": 20966, "greenville": 20967, "##berries": 20968, "geographically": 20969, "nell": 20970, "quartz": 20971, "##athic": 20972, "cemeteries": 20973, "##lr": 20974, "crossings": 20975, "nah": 20976, "holloway": 20977, "reptiles": 20978, "chun": 20979, "sichuan": 20980, "snowy": 20981, "660": 20982, "corrections": 20983, "##ivo": 20984, "zheng": 20985, "ambassadors": 20986, "blacksmith": 20987, "fielded": 20988, "fluids": 20989, "hardcover": 20990, "turnover": 20991, "medications": 20992, "melvin": 20993, "academies": 20994, "##erton": 20995, "ro": 20996, "roach": 20997, "absorbing": 20998, "spaniards": 20999, "colton": 21000, "##founded": 21001, "outsider": 21002, "espionage": 21003, "kelsey": 21004, "245": 21005, "edible": 21006, "##ulf": 21007, "dora": 21008, "establishes": 21009, "##sham": 21010, "##tries": 21011, "contracting": 21012, "##tania": 21013, "cinematic": 21014, "costello": 21015, "nesting": 21016, "##uron": 21017, "connolly": 21018, "duff": 21019, "##nology": 21020, "mma": 21021, "##mata": 21022, "fergus": 21023, "sexes": 21024, "gi": 21025, "optics": 21026, "spectator": 21027, "woodstock": 21028, "banning": 21029, "##hee": 21030, "##fle": 21031, "differentiate": 21032, "outfielder": 21033, "refinery": 21034, "226": 21035, "312": 21036, "gerhard": 21037, "horde": 21038, "lair": 21039, "drastically": 21040, "##udi": 21041, "landfall": 21042, "##cheng": 21043, "motorsport": 21044, "odi": 21045, "##achi": 21046, "predominant": 21047, "quay": 21048, "skins": 21049, "##ental": 21050, "edna": 21051, "harshly": 21052, "complementary": 21053, "murdering": 21054, "##aves": 21055, "wreckage": 21056, "##90": 21057, "ono": 21058, "outstretched": 21059, "lennox": 21060, "munitions": 21061, "galen": 21062, "reconcile": 21063, "470": 21064, "scalp": 21065, "bicycles": 21066, "gillespie": 21067, "questionable": 21068, "rosenberg": 21069, "guillermo": 21070, "hostel": 21071, "jarvis": 21072, "kabul": 21073, "volvo": 21074, "opium": 21075, "yd": 21076, "##twined": 21077, "abuses": 21078, "decca": 21079, "outpost": 21080, "##cino": 21081, "sensible": 21082, "neutrality": 21083, "##64": 21084, "ponce": 21085, "anchorage": 21086, "atkins": 21087, "turrets": 21088, "inadvertently": 21089, "disagree": 21090, "libre": 21091, "vodka": 21092, "reassuring": 21093, "weighs": 21094, "##yal": 21095, "glide": 21096, "jumper": 21097, "ceilings": 21098, "repertory": 21099, "outs": 21100, "stain": 21101, "##bial": 21102, "envy": 21103, "##ucible": 21104, "smashing": 21105, "heightened": 21106, "policing": 21107, "hyun": 21108, "mixes": 21109, "lai": 21110, "prima": 21111, "##ples": 21112, "celeste": 21113, "##bina": 21114, "lucrative": 21115, "intervened": 21116, "kc": 21117, "manually": 21118, "##rned": 21119, "stature": 21120, "staffed": 21121, "bun": 21122, "bastards": 21123, "nairobi": 21124, "priced": 21125, "##auer": 21126, "thatcher": 21127, "##kia": 21128, "tripped": 21129, "comune": 21130, "##ogan": 21131, "##pled": 21132, "brasil": 21133, "incentives": 21134, "emanuel": 21135, "hereford": 21136, "musica": 21137, "##kim": 21138, "benedictine": 21139, "biennale": 21140, "##lani": 21141, "eureka": 21142, "gardiner": 21143, "rb": 21144, "knocks": 21145, "sha": 21146, "##ael": 21147, "##elled": 21148, "##onate": 21149, "efficacy": 21150, "ventura": 21151, "masonic": 21152, "sanford": 21153, "maize": 21154, "leverage": 21155, "##feit": 21156, "capacities": 21157, "santana": 21158, "##aur": 21159, "novelty": 21160, "vanilla": 21161, "##cter": 21162, "##tour": 21163, "benin": 21164, "##oir": 21165, "##rain": 21166, "neptune": 21167, "drafting": 21168, "tallinn": 21169, "##cable": 21170, "humiliation": 21171, "##boarding": 21172, "schleswig": 21173, "fabian": 21174, "bernardo": 21175, "liturgy": 21176, "spectacle": 21177, "sweeney": 21178, "pont": 21179, "routledge": 21180, "##tment": 21181, "cosmos": 21182, "ut": 21183, "hilt": 21184, "sleek": 21185, "universally": 21186, "##eville": 21187, "##gawa": 21188, "typed": 21189, "##dry": 21190, "favors": 21191, "allegheny": 21192, "glaciers": 21193, "##rly": 21194, "recalling": 21195, "aziz": 21196, "##log": 21197, "parasite": 21198, "requiem": 21199, "auf": 21200, "##berto": 21201, "##llin": 21202, "illumination": 21203, "##breaker": 21204, "##issa": 21205, "festivities": 21206, "bows": 21207, "govern": 21208, "vibe": 21209, "vp": 21210, "333": 21211, "sprawled": 21212, "larson": 21213, "pilgrim": 21214, "bwf": 21215, "leaping": 21216, "##rts": 21217, "##ssel": 21218, "alexei": 21219, "greyhound": 21220, "hoarse": 21221, "##dler": 21222, "##oration": 21223, "seneca": 21224, "##cule": 21225, "gaping": 21226, "##ulously": 21227, "##pura": 21228, "cinnamon": 21229, "##gens": 21230, "##rricular": 21231, "craven": 21232, "fantasies": 21233, "houghton": 21234, "engined": 21235, "reigned": 21236, "dictator": 21237, "supervising": 21238, "##oris": 21239, "bogota": 21240, "commentaries": 21241, "unnatural": 21242, "fingernails": 21243, "spirituality": 21244, "tighten": 21245, "##tm": 21246, "canadiens": 21247, "protesting": 21248, "intentional": 21249, "cheers": 21250, "sparta": 21251, "##ytic": 21252, "##iere": 21253, "##zine": 21254, "widen": 21255, "belgarath": 21256, "controllers": 21257, "dodd": 21258, "iaaf": 21259, "navarre": 21260, "##ication": 21261, "defect": 21262, "squire": 21263, "steiner": 21264, "whisky": 21265, "##mins": 21266, "560": 21267, "inevitably": 21268, "tome": 21269, "##gold": 21270, "chew": 21271, "##uid": 21272, "##lid": 21273, "elastic": 21274, "##aby": 21275, "streaked": 21276, "alliances": 21277, "jailed": 21278, "regal": 21279, "##ined": 21280, "##phy": 21281, "czechoslovak": 21282, "narration": 21283, "absently": 21284, "##uld": 21285, "bluegrass": 21286, "guangdong": 21287, "quran": 21288, "criticizing": 21289, "hose": 21290, "hari": 21291, "##liest": 21292, "##owa": 21293, "skier": 21294, "streaks": 21295, "deploy": 21296, "##lom": 21297, "raft": 21298, "bose": 21299, "dialed": 21300, "huff": 21301, "##eira": 21302, "haifa": 21303, "simplest": 21304, "bursting": 21305, "endings": 21306, "ib": 21307, "sultanate": 21308, "##titled": 21309, "franks": 21310, "whitman": 21311, "ensures": 21312, "sven": 21313, "##ggs": 21314, "collaborators": 21315, "forster": 21316, "organising": 21317, "ui": 21318, "banished": 21319, "napier": 21320, "injustice": 21321, "teller": 21322, "layered": 21323, "thump": 21324, "##otti": 21325, "roc": 21326, "battleships": 21327, "evidenced": 21328, "fugitive": 21329, "sadie": 21330, "robotics": 21331, "##roud": 21332, "equatorial": 21333, "geologist": 21334, "##iza": 21335, "yielding": 21336, "##bron": 21337, "##sr": 21338, "internationale": 21339, "mecca": 21340, "##diment": 21341, "sbs": 21342, "skyline": 21343, "toad": 21344, "uploaded": 21345, "reflective": 21346, "undrafted": 21347, "lal": 21348, "leafs": 21349, "bayern": 21350, "##dai": 21351, "lakshmi": 21352, "shortlisted": 21353, "##stick": 21354, "##wicz": 21355, "camouflage": 21356, "donate": 21357, "af": 21358, "christi": 21359, "lau": 21360, "##acio": 21361, "disclosed": 21362, "nemesis": 21363, "1761": 21364, "assemble": 21365, "straining": 21366, "northamptonshire": 21367, "tal": 21368, "##asi": 21369, "bernardino": 21370, "premature": 21371, "heidi": 21372, "42nd": 21373, "coefficients": 21374, "galactic": 21375, "reproduce": 21376, "buzzed": 21377, "sensations": 21378, "zionist": 21379, "monsieur": 21380, "myrtle": 21381, "##eme": 21382, "archery": 21383, "strangled": 21384, "musically": 21385, "viewpoint": 21386, "antiquities": 21387, "bei": 21388, "trailers": 21389, "seahawks": 21390, "cured": 21391, "pee": 21392, "preferring": 21393, "tasmanian": 21394, "lange": 21395, "sul": 21396, "##mail": 21397, "##working": 21398, "colder": 21399, "overland": 21400, "lucivar": 21401, "massey": 21402, "gatherings": 21403, "haitian": 21404, "##smith": 21405, "disapproval": 21406, "flaws": 21407, "##cco": 21408, "##enbach": 21409, "1766": 21410, "npr": 21411, "##icular": 21412, "boroughs": 21413, "creole": 21414, "forums": 21415, "techno": 21416, "1755": 21417, "dent": 21418, "abdominal": 21419, "streetcar": 21420, "##eson": 21421, "##stream": 21422, "procurement": 21423, "gemini": 21424, "predictable": 21425, "##tya": 21426, "acheron": 21427, "christoph": 21428, "feeder": 21429, "fronts": 21430, "vendor": 21431, "bernhard": 21432, "jammu": 21433, "tumors": 21434, "slang": 21435, "##uber": 21436, "goaltender": 21437, "twists": 21438, "curving": 21439, "manson": 21440, "vuelta": 21441, "mer": 21442, "peanut": 21443, "confessions": 21444, "pouch": 21445, "unpredictable": 21446, "allowance": 21447, "theodor": 21448, "vascular": 21449, "##factory": 21450, "bala": 21451, "authenticity": 21452, "metabolic": 21453, "coughing": 21454, "nanjing": 21455, "##cea": 21456, "pembroke": 21457, "##bard": 21458, "splendid": 21459, "36th": 21460, "ff": 21461, "hourly": 21462, "##ahu": 21463, "elmer": 21464, "handel": 21465, "##ivate": 21466, "awarding": 21467, "thrusting": 21468, "dl": 21469, "experimentation": 21470, "##hesion": 21471, "##46": 21472, "caressed": 21473, "entertained": 21474, "steak": 21475, "##rangle": 21476, "biologist": 21477, "orphans": 21478, "baroness": 21479, "oyster": 21480, "stepfather": 21481, "##dridge": 21482, "mirage": 21483, "reefs": 21484, "speeding": 21485, "##31": 21486, "barons": 21487, "1764": 21488, "227": 21489, "inhabit": 21490, "preached": 21491, "repealed": 21492, "##tral": 21493, "honoring": 21494, "boogie": 21495, "captives": 21496, "administer": 21497, "johanna": 21498, "##imate": 21499, "gel": 21500, "suspiciously": 21501, "1767": 21502, "sobs": 21503, "##dington": 21504, "backbone": 21505, "hayward": 21506, "garry": 21507, "##folding": 21508, "##nesia": 21509, "maxi": 21510, "##oof": 21511, "##ppe": 21512, "ellison": 21513, "galileo": 21514, "##stand": 21515, "crimea": 21516, "frenzy": 21517, "amour": 21518, "bumper": 21519, "matrices": 21520, "natalia": 21521, "baking": 21522, "garth": 21523, "palestinians": 21524, "##grove": 21525, "smack": 21526, "conveyed": 21527, "ensembles": 21528, "gardening": 21529, "##manship": 21530, "##rup": 21531, "##stituting": 21532, "1640": 21533, "harvesting": 21534, "topography": 21535, "jing": 21536, "shifters": 21537, "dormitory": 21538, "##carriage": 21539, "##lston": 21540, "ist": 21541, "skulls": 21542, "##stadt": 21543, "dolores": 21544, "jewellery": 21545, "sarawak": 21546, "##wai": 21547, "##zier": 21548, "fences": 21549, "christy": 21550, "confinement": 21551, "tumbling": 21552, "credibility": 21553, "fir": 21554, "stench": 21555, "##bria": 21556, "##plication": 21557, "##nged": 21558, "##sam": 21559, "virtues": 21560, "##belt": 21561, "marjorie": 21562, "pba": 21563, "##eem": 21564, "##made": 21565, "celebrates": 21566, "schooner": 21567, "agitated": 21568, "barley": 21569, "fulfilling": 21570, "anthropologist": 21571, "##pro": 21572, "restrict": 21573, "novi": 21574, "regulating": 21575, "##nent": 21576, "padres": 21577, "##rani": 21578, "##hesive": 21579, "loyola": 21580, "tabitha": 21581, "milky": 21582, "olson": 21583, "proprietor": 21584, "crambidae": 21585, "guarantees": 21586, "intercollegiate": 21587, "ljubljana": 21588, "hilda": 21589, "##sko": 21590, "ignorant": 21591, "hooded": 21592, "##lts": 21593, "sardinia": 21594, "##lidae": 21595, "##vation": 21596, "frontman": 21597, "privileged": 21598, "witchcraft": 21599, "##gp": 21600, "jammed": 21601, "laude": 21602, "poking": 21603, "##than": 21604, "bracket": 21605, "amazement": 21606, "yunnan": 21607, "##erus": 21608, "maharaja": 21609, "linnaeus": 21610, "264": 21611, "commissioning": 21612, "milano": 21613, "peacefully": 21614, "##logies": 21615, "akira": 21616, "rani": 21617, "regulator": 21618, "##36": 21619, "grasses": 21620, "##rance": 21621, "luzon": 21622, "crows": 21623, "compiler": 21624, "gretchen": 21625, "seaman": 21626, "edouard": 21627, "tab": 21628, "buccaneers": 21629, "ellington": 21630, "hamlets": 21631, "whig": 21632, "socialists": 21633, "##anto": 21634, "directorial": 21635, "easton": 21636, "mythological": 21637, "##kr": 21638, "##vary": 21639, "rhineland": 21640, "semantic": 21641, "taut": 21642, "dune": 21643, "inventions": 21644, "succeeds": 21645, "##iter": 21646, "replication": 21647, "branched": 21648, "##pired": 21649, "jul": 21650, "prosecuted": 21651, "kangaroo": 21652, "penetrated": 21653, "##avian": 21654, "middlesbrough": 21655, "doses": 21656, "bleak": 21657, "madam": 21658, "predatory": 21659, "relentless": 21660, "##vili": 21661, "reluctance": 21662, "##vir": 21663, "hailey": 21664, "crore": 21665, "silvery": 21666, "1759": 21667, "monstrous": 21668, "swimmers": 21669, "transmissions": 21670, "hawthorn": 21671, "informing": 21672, "##eral": 21673, "toilets": 21674, "caracas": 21675, "crouch": 21676, "kb": 21677, "##sett": 21678, "295": 21679, "cartel": 21680, "hadley": 21681, "##aling": 21682, "alexia": 21683, "yvonne": 21684, "##biology": 21685, "cinderella": 21686, "eton": 21687, "superb": 21688, "blizzard": 21689, "stabbing": 21690, "industrialist": 21691, "maximus": 21692, "##gm": 21693, "##orus": 21694, "groves": 21695, "maud": 21696, "clade": 21697, "oversized": 21698, "comedic": 21699, "##bella": 21700, "rosen": 21701, "nomadic": 21702, "fulham": 21703, "montane": 21704, "beverages": 21705, "galaxies": 21706, "redundant": 21707, "swarm": 21708, "##rot": 21709, "##folia": 21710, "##llis": 21711, "buckinghamshire": 21712, "fen": 21713, "bearings": 21714, "bahadur": 21715, "##rom": 21716, "gilles": 21717, "phased": 21718, "dynamite": 21719, "faber": 21720, "benoit": 21721, "vip": 21722, "##ount": 21723, "##wd": 21724, "booking": 21725, "fractured": 21726, "tailored": 21727, "anya": 21728, "spices": 21729, "westwood": 21730, "cairns": 21731, "auditions": 21732, "inflammation": 21733, "steamed": 21734, "##rocity": 21735, "##acion": 21736, "##urne": 21737, "skyla": 21738, "thereof": 21739, "watford": 21740, "torment": 21741, "archdeacon": 21742, "transforms": 21743, "lulu": 21744, "demeanor": 21745, "fucked": 21746, "serge": 21747, "##sor": 21748, "mckenna": 21749, "minas": 21750, "entertainer": 21751, "##icide": 21752, "caress": 21753, "originate": 21754, "residue": 21755, "##sty": 21756, "1740": 21757, "##ilised": 21758, "##org": 21759, "beech": 21760, "##wana": 21761, "subsidies": 21762, "##ghton": 21763, "emptied": 21764, "gladstone": 21765, "ru": 21766, "firefighters": 21767, "voodoo": 21768, "##rcle": 21769, "het": 21770, "nightingale": 21771, "tamara": 21772, "edmond": 21773, "ingredient": 21774, "weaknesses": 21775, "silhouette": 21776, "285": 21777, "compatibility": 21778, "withdrawing": 21779, "hampson": 21780, "##mona": 21781, "anguish": 21782, "giggling": 21783, "##mber": 21784, "bookstore": 21785, "##jiang": 21786, "southernmost": 21787, "tilting": 21788, "##vance": 21789, "bai": 21790, "economical": 21791, "rf": 21792, "briefcase": 21793, "dreadful": 21794, "hinted": 21795, "projections": 21796, "shattering": 21797, "totaling": 21798, "##rogate": 21799, "analogue": 21800, "indicted": 21801, "periodical": 21802, "fullback": 21803, "##dman": 21804, "haynes": 21805, "##tenberg": 21806, "##ffs": 21807, "##ishment": 21808, "1745": 21809, "thirst": 21810, "stumble": 21811, "penang": 21812, "vigorous": 21813, "##ddling": 21814, "##kor": 21815, "##lium": 21816, "octave": 21817, "##ove": 21818, "##enstein": 21819, "##inen": 21820, "##ones": 21821, "siberian": 21822, "##uti": 21823, "cbn": 21824, "repeal": 21825, "swaying": 21826, "##vington": 21827, "khalid": 21828, "tanaka": 21829, "unicorn": 21830, "otago": 21831, "plastered": 21832, "lobe": 21833, "riddle": 21834, "##rella": 21835, "perch": 21836, "##ishing": 21837, "croydon": 21838, "filtered": 21839, "graeme": 21840, "tripoli": 21841, "##ossa": 21842, "crocodile": 21843, "##chers": 21844, "sufi": 21845, "mined": 21846, "##tung": 21847, "inferno": 21848, "lsu": 21849, "##phi": 21850, "swelled": 21851, "utilizes": 21852, "£2": 21853, "cale": 21854, "periodicals": 21855, "styx": 21856, "hike": 21857, "informally": 21858, "coop": 21859, "lund": 21860, "##tidae": 21861, "ala": 21862, "hen": 21863, "qui": 21864, "transformations": 21865, "disposed": 21866, "sheath": 21867, "chickens": 21868, "##cade": 21869, "fitzroy": 21870, "sas": 21871, "silesia": 21872, "unacceptable": 21873, "odisha": 21874, "1650": 21875, "sabrina": 21876, "pe": 21877, "spokane": 21878, "ratios": 21879, "athena": 21880, "massage": 21881, "shen": 21882, "dilemma": 21883, "##drum": 21884, "##riz": 21885, "##hul": 21886, "corona": 21887, "doubtful": 21888, "niall": 21889, "##pha": 21890, "##bino": 21891, "fines": 21892, "cite": 21893, "acknowledging": 21894, "bangor": 21895, "ballard": 21896, "bathurst": 21897, "##resh": 21898, "huron": 21899, "mustered": 21900, "alzheimer": 21901, "garments": 21902, "kinase": 21903, "tyre": 21904, "warship": 21905, "##cp": 21906, "flashback": 21907, "pulmonary": 21908, "braun": 21909, "cheat": 21910, "kamal": 21911, "cyclists": 21912, "constructions": 21913, "grenades": 21914, "ndp": 21915, "traveller": 21916, "excuses": 21917, "stomped": 21918, "signalling": 21919, "trimmed": 21920, "futsal": 21921, "mosques": 21922, "relevance": 21923, "##wine": 21924, "wta": 21925, "##23": 21926, "##vah": 21927, "##lter": 21928, "hoc": 21929, "##riding": 21930, "optimistic": 21931, "##´s": 21932, "deco": 21933, "sim": 21934, "interacting": 21935, "rejecting": 21936, "moniker": 21937, "waterways": 21938, "##ieri": 21939, "##oku": 21940, "mayors": 21941, "gdansk": 21942, "outnumbered": 21943, "pearls": 21944, "##ended": 21945, "##hampton": 21946, "fairs": 21947, "totals": 21948, "dominating": 21949, "262": 21950, "notions": 21951, "stairway": 21952, "compiling": 21953, "pursed": 21954, "commodities": 21955, "grease": 21956, "yeast": 21957, "##jong": 21958, "carthage": 21959, "griffiths": 21960, "residual": 21961, "amc": 21962, "contraction": 21963, "laird": 21964, "sapphire": 21965, "##marine": 21966, "##ivated": 21967, "amalgamation": 21968, "dissolve": 21969, "inclination": 21970, "lyle": 21971, "packaged": 21972, "altitudes": 21973, "suez": 21974, "canons": 21975, "graded": 21976, "lurched": 21977, "narrowing": 21978, "boasts": 21979, "guise": 21980, "wed": 21981, "enrico": 21982, "##ovsky": 21983, "rower": 21984, "scarred": 21985, "bree": 21986, "cub": 21987, "iberian": 21988, "protagonists": 21989, "bargaining": 21990, "proposing": 21991, "trainers": 21992, "voyages": 21993, "vans": 21994, "fishes": 21995, "##aea": 21996, "##ivist": 21997, "##verance": 21998, "encryption": 21999, "artworks": 22000, "kazan": 22001, "sabre": 22002, "cleopatra": 22003, "hepburn": 22004, "rotting": 22005, "supremacy": 22006, "mecklenburg": 22007, "##brate": 22008, "burrows": 22009, "hazards": 22010, "outgoing": 22011, "flair": 22012, "organizes": 22013, "##ctions": 22014, "scorpion": 22015, "##usions": 22016, "boo": 22017, "234": 22018, "chevalier": 22019, "dunedin": 22020, "slapping": 22021, "##34": 22022, "ineligible": 22023, "pensions": 22024, "##38": 22025, "##omic": 22026, "manufactures": 22027, "emails": 22028, "bismarck": 22029, "238": 22030, "weakening": 22031, "blackish": 22032, "ding": 22033, "mcgee": 22034, "quo": 22035, "##rling": 22036, "northernmost": 22037, "xx": 22038, "manpower": 22039, "greed": 22040, "sampson": 22041, "clicking": 22042, "##ange": 22043, "##horpe": 22044, "##inations": 22045, "##roving": 22046, "torre": 22047, "##eptive": 22048, "##moral": 22049, "symbolism": 22050, "38th": 22051, "asshole": 22052, "meritorious": 22053, "outfits": 22054, "splashed": 22055, "biographies": 22056, "sprung": 22057, "astros": 22058, "##tale": 22059, "302": 22060, "737": 22061, "filly": 22062, "raoul": 22063, "nw": 22064, "tokugawa": 22065, "linden": 22066, "clubhouse": 22067, "##apa": 22068, "tracts": 22069, "romano": 22070, "##pio": 22071, "putin": 22072, "tags": 22073, "##note": 22074, "chained": 22075, "dickson": 22076, "gunshot": 22077, "moe": 22078, "gunn": 22079, "rashid": 22080, "##tails": 22081, "zipper": 22082, "##bas": 22083, "##nea": 22084, "contrasted": 22085, "##ply": 22086, "##udes": 22087, "plum": 22088, "pharaoh": 22089, "##pile": 22090, "aw": 22091, "comedies": 22092, "ingrid": 22093, "sandwiches": 22094, "subdivisions": 22095, "1100": 22096, "mariana": 22097, "nokia": 22098, "kamen": 22099, "hz": 22100, "delaney": 22101, "veto": 22102, "herring": 22103, "##words": 22104, "possessive": 22105, "outlines": 22106, "##roup": 22107, "siemens": 22108, "stairwell": 22109, "rc": 22110, "gallantry": 22111, "messiah": 22112, "palais": 22113, "yells": 22114, "233": 22115, "zeppelin": 22116, "##dm": 22117, "bolivar": 22118, "##cede": 22119, "smackdown": 22120, "mckinley": 22121, "##mora": 22122, "##yt": 22123, "muted": 22124, "geologic": 22125, "finely": 22126, "unitary": 22127, "avatar": 22128, "hamas": 22129, "maynard": 22130, "rees": 22131, "bog": 22132, "contrasting": 22133, "##rut": 22134, "liv": 22135, "chico": 22136, "disposition": 22137, "pixel": 22138, "##erate": 22139, "becca": 22140, "dmitry": 22141, "yeshiva": 22142, "narratives": 22143, "##lva": 22144, "##ulton": 22145, "mercenary": 22146, "sharpe": 22147, "tempered": 22148, "navigate": 22149, "stealth": 22150, "amassed": 22151, "keynes": 22152, "##lini": 22153, "untouched": 22154, "##rrie": 22155, "havoc": 22156, "lithium": 22157, "##fighting": 22158, "abyss": 22159, "graf": 22160, "southward": 22161, "wolverine": 22162, "balloons": 22163, "implements": 22164, "ngos": 22165, "transitions": 22166, "##icum": 22167, "ambushed": 22168, "concacaf": 22169, "dormant": 22170, "economists": 22171, "##dim": 22172, "costing": 22173, "csi": 22174, "rana": 22175, "universite": 22176, "boulders": 22177, "verity": 22178, "##llon": 22179, "collin": 22180, "mellon": 22181, "misses": 22182, "cypress": 22183, "fluorescent": 22184, "lifeless": 22185, "spence": 22186, "##ulla": 22187, "crewe": 22188, "shepard": 22189, "pak": 22190, "revelations": 22191, "##م": 22192, "jolly": 22193, "gibbons": 22194, "paw": 22195, "##dro": 22196, "##quel": 22197, "freeing": 22198, "##test": 22199, "shack": 22200, "fries": 22201, "palatine": 22202, "##51": 22203, "##hiko": 22204, "accompaniment": 22205, "cruising": 22206, "recycled": 22207, "##aver": 22208, "erwin": 22209, "sorting": 22210, "synthesizers": 22211, "dyke": 22212, "realities": 22213, "sg": 22214, "strides": 22215, "enslaved": 22216, "wetland": 22217, "##ghan": 22218, "competence": 22219, "gunpowder": 22220, "grassy": 22221, "maroon": 22222, "reactors": 22223, "objection": 22224, "##oms": 22225, "carlson": 22226, "gearbox": 22227, "macintosh": 22228, "radios": 22229, "shelton": 22230, "##sho": 22231, "clergyman": 22232, "prakash": 22233, "254": 22234, "mongols": 22235, "trophies": 22236, "oricon": 22237, "228": 22238, "stimuli": 22239, "twenty20": 22240, "cantonese": 22241, "cortes": 22242, "mirrored": 22243, "##saurus": 22244, "bhp": 22245, "cristina": 22246, "melancholy": 22247, "##lating": 22248, "enjoyable": 22249, "nuevo": 22250, "##wny": 22251, "downfall": 22252, "schumacher": 22253, "##ind": 22254, "banging": 22255, "lausanne": 22256, "rumbled": 22257, "paramilitary": 22258, "reflex": 22259, "ax": 22260, "amplitude": 22261, "migratory": 22262, "##gall": 22263, "##ups": 22264, "midi": 22265, "barnard": 22266, "lastly": 22267, "sherry": 22268, "##hp": 22269, "##nall": 22270, "keystone": 22271, "##kra": 22272, "carleton": 22273, "slippery": 22274, "##53": 22275, "coloring": 22276, "foe": 22277, "socket": 22278, "otter": 22279, "##rgos": 22280, "mats": 22281, "##tose": 22282, "consultants": 22283, "bafta": 22284, "bison": 22285, "topping": 22286, "##km": 22287, "490": 22288, "primal": 22289, "abandonment": 22290, "transplant": 22291, "atoll": 22292, "hideous": 22293, "mort": 22294, "pained": 22295, "reproduced": 22296, "tae": 22297, "howling": 22298, "##turn": 22299, "unlawful": 22300, "billionaire": 22301, "hotter": 22302, "poised": 22303, "lansing": 22304, "##chang": 22305, "dinamo": 22306, "retro": 22307, "messing": 22308, "nfc": 22309, "domesday": 22310, "##mina": 22311, "blitz": 22312, "timed": 22313, "##athing": 22314, "##kley": 22315, "ascending": 22316, "gesturing": 22317, "##izations": 22318, "signaled": 22319, "tis": 22320, "chinatown": 22321, "mermaid": 22322, "savanna": 22323, "jameson": 22324, "##aint": 22325, "catalina": 22326, "##pet": 22327, "##hers": 22328, "cochrane": 22329, "cy": 22330, "chatting": 22331, "##kus": 22332, "alerted": 22333, "computation": 22334, "mused": 22335, "noelle": 22336, "majestic": 22337, "mohawk": 22338, "campo": 22339, "octagonal": 22340, "##sant": 22341, "##hend": 22342, "241": 22343, "aspiring": 22344, "##mart": 22345, "comprehend": 22346, "iona": 22347, "paralyzed": 22348, "shimmering": 22349, "swindon": 22350, "rhone": 22351, "##eley": 22352, "reputed": 22353, "configurations": 22354, "pitchfork": 22355, "agitation": 22356, "francais": 22357, "gillian": 22358, "lipstick": 22359, "##ilo": 22360, "outsiders": 22361, "pontifical": 22362, "resisting": 22363, "bitterness": 22364, "sewer": 22365, "rockies": 22366, "##edd": 22367, "##ucher": 22368, "misleading": 22369, "1756": 22370, "exiting": 22371, "galloway": 22372, "##nging": 22373, "risked": 22374, "##heart": 22375, "246": 22376, "commemoration": 22377, "schultz": 22378, "##rka": 22379, "integrating": 22380, "##rsa": 22381, "poses": 22382, "shrieked": 22383, "##weiler": 22384, "guineas": 22385, "gladys": 22386, "jerking": 22387, "owls": 22388, "goldsmith": 22389, "nightly": 22390, "penetrating": 22391, "##unced": 22392, "lia": 22393, "##33": 22394, "ignited": 22395, "betsy": 22396, "##aring": 22397, "##thorpe": 22398, "follower": 22399, "vigorously": 22400, "##rave": 22401, "coded": 22402, "kiran": 22403, "knit": 22404, "zoology": 22405, "tbilisi": 22406, "##28": 22407, "##bered": 22408, "repository": 22409, "govt": 22410, "deciduous": 22411, "dino": 22412, "growling": 22413, "##bba": 22414, "enhancement": 22415, "unleashed": 22416, "chanting": 22417, "pussy": 22418, "biochemistry": 22419, "##eric": 22420, "kettle": 22421, "repression": 22422, "toxicity": 22423, "nrhp": 22424, "##arth": 22425, "##kko": 22426, "##bush": 22427, "ernesto": 22428, "commended": 22429, "outspoken": 22430, "242": 22431, "mca": 22432, "parchment": 22433, "sms": 22434, "kristen": 22435, "##aton": 22436, "bisexual": 22437, "raked": 22438, "glamour": 22439, "navajo": 22440, "a2": 22441, "conditioned": 22442, "showcased": 22443, "##hma": 22444, "spacious": 22445, "youthful": 22446, "##esa": 22447, "usl": 22448, "appliances": 22449, "junta": 22450, "brest": 22451, "layne": 22452, "conglomerate": 22453, "enchanted": 22454, "chao": 22455, "loosened": 22456, "picasso": 22457, "circulating": 22458, "inspect": 22459, "montevideo": 22460, "##centric": 22461, "##kti": 22462, "piazza": 22463, "spurred": 22464, "##aith": 22465, "bari": 22466, "freedoms": 22467, "poultry": 22468, "stamford": 22469, "lieu": 22470, "##ect": 22471, "indigo": 22472, "sarcastic": 22473, "bahia": 22474, "stump": 22475, "attach": 22476, "dvds": 22477, "frankenstein": 22478, "lille": 22479, "approx": 22480, "scriptures": 22481, "pollen": 22482, "##script": 22483, "nmi": 22484, "overseen": 22485, "##ivism": 22486, "tides": 22487, "proponent": 22488, "newmarket": 22489, "inherit": 22490, "milling": 22491, "##erland": 22492, "centralized": 22493, "##rou": 22494, "distributors": 22495, "credentials": 22496, "drawers": 22497, "abbreviation": 22498, "##lco": 22499, "##xon": 22500, "downing": 22501, "uncomfortably": 22502, "ripe": 22503, "##oes": 22504, "erase": 22505, "franchises": 22506, "##ever": 22507, "populace": 22508, "##bery": 22509, "##khar": 22510, "decomposition": 22511, "pleas": 22512, "##tet": 22513, "daryl": 22514, "sabah": 22515, "##stle": 22516, "##wide": 22517, "fearless": 22518, "genie": 22519, "lesions": 22520, "annette": 22521, "##ogist": 22522, "oboe": 22523, "appendix": 22524, "nair": 22525, "dripped": 22526, "petitioned": 22527, "maclean": 22528, "mosquito": 22529, "parrot": 22530, "rpg": 22531, "hampered": 22532, "1648": 22533, "operatic": 22534, "reservoirs": 22535, "##tham": 22536, "irrelevant": 22537, "jolt": 22538, "summarized": 22539, "##fp": 22540, "medallion": 22541, "##taff": 22542, "##−": 22543, "clawed": 22544, "harlow": 22545, "narrower": 22546, "goddard": 22547, "marcia": 22548, "bodied": 22549, "fremont": 22550, "suarez": 22551, "altering": 22552, "tempest": 22553, "mussolini": 22554, "porn": 22555, "##isms": 22556, "sweetly": 22557, "oversees": 22558, "walkers": 22559, "solitude": 22560, "grimly": 22561, "shrines": 22562, "hk": 22563, "ich": 22564, "supervisors": 22565, "hostess": 22566, "dietrich": 22567, "legitimacy": 22568, "brushes": 22569, "expressive": 22570, "##yp": 22571, "dissipated": 22572, "##rse": 22573, "localized": 22574, "systemic": 22575, "##nikov": 22576, "gettysburg": 22577, "##js": 22578, "##uaries": 22579, "dialogues": 22580, "muttering": 22581, "251": 22582, "housekeeper": 22583, "sicilian": 22584, "discouraged": 22585, "##frey": 22586, "beamed": 22587, "kaladin": 22588, "halftime": 22589, "kidnap": 22590, "##amo": 22591, "##llet": 22592, "1754": 22593, "synonymous": 22594, "depleted": 22595, "instituto": 22596, "insulin": 22597, "reprised": 22598, "##opsis": 22599, "clashed": 22600, "##ctric": 22601, "interrupting": 22602, "radcliffe": 22603, "insisting": 22604, "medici": 22605, "1715": 22606, "ejected": 22607, "playfully": 22608, "turbulent": 22609, "##47": 22610, "starvation": 22611, "##rini": 22612, "shipment": 22613, "rebellious": 22614, "petersen": 22615, "verification": 22616, "merits": 22617, "##rified": 22618, "cakes": 22619, "##charged": 22620, "1757": 22621, "milford": 22622, "shortages": 22623, "spying": 22624, "fidelity": 22625, "##aker": 22626, "emitted": 22627, "storylines": 22628, "harvested": 22629, "seismic": 22630, "##iform": 22631, "cheung": 22632, "kilda": 22633, "theoretically": 22634, "barbie": 22635, "lynx": 22636, "##rgy": 22637, "##tius": 22638, "goblin": 22639, "mata": 22640, "poisonous": 22641, "##nburg": 22642, "reactive": 22643, "residues": 22644, "obedience": 22645, "##евич": 22646, "conjecture": 22647, "##rac": 22648, "401": 22649, "hating": 22650, "sixties": 22651, "kicker": 22652, "moaning": 22653, "motown": 22654, "##bha": 22655, "emancipation": 22656, "neoclassical": 22657, "##hering": 22658, "consoles": 22659, "ebert": 22660, "professorship": 22661, "##tures": 22662, "sustaining": 22663, "assaults": 22664, "obeyed": 22665, "affluent": 22666, "incurred": 22667, "tornadoes": 22668, "##eber": 22669, "##zow": 22670, "emphasizing": 22671, "highlanders": 22672, "cheated": 22673, "helmets": 22674, "##ctus": 22675, "internship": 22676, "terence": 22677, "bony": 22678, "executions": 22679, "legislators": 22680, "berries": 22681, "peninsular": 22682, "tinged": 22683, "##aco": 22684, "1689": 22685, "amplifier": 22686, "corvette": 22687, "ribbons": 22688, "lavish": 22689, "pennant": 22690, "##lander": 22691, "worthless": 22692, "##chfield": 22693, "##forms": 22694, "mariano": 22695, "pyrenees": 22696, "expenditures": 22697, "##icides": 22698, "chesterfield": 22699, "mandir": 22700, "tailor": 22701, "39th": 22702, "sergey": 22703, "nestled": 22704, "willed": 22705, "aristocracy": 22706, "devotees": 22707, "goodnight": 22708, "raaf": 22709, "rumored": 22710, "weaponry": 22711, "remy": 22712, "appropriations": 22713, "harcourt": 22714, "burr": 22715, "riaa": 22716, "##lence": 22717, "limitation": 22718, "unnoticed": 22719, "guo": 22720, "soaking": 22721, "swamps": 22722, "##tica": 22723, "collapsing": 22724, "tatiana": 22725, "descriptive": 22726, "brigham": 22727, "psalm": 22728, "##chment": 22729, "maddox": 22730, "##lization": 22731, "patti": 22732, "caliph": 22733, "##aja": 22734, "akron": 22735, "injuring": 22736, "serra": 22737, "##ganj": 22738, "basins": 22739, "##sari": 22740, "astonished": 22741, "launcher": 22742, "##church": 22743, "hilary": 22744, "wilkins": 22745, "sewing": 22746, "##sf": 22747, "stinging": 22748, "##fia": 22749, "##ncia": 22750, "underwood": 22751, "startup": 22752, "##ition": 22753, "compilations": 22754, "vibrations": 22755, "embankment": 22756, "jurist": 22757, "##nity": 22758, "bard": 22759, "juventus": 22760, "groundwater": 22761, "kern": 22762, "palaces": 22763, "helium": 22764, "boca": 22765, "cramped": 22766, "marissa": 22767, "soto": 22768, "##worm": 22769, "jae": 22770, "princely": 22771, "##ggy": 22772, "faso": 22773, "bazaar": 22774, "warmly": 22775, "##voking": 22776, "229": 22777, "pairing": 22778, "##lite": 22779, "##grate": 22780, "##nets": 22781, "wien": 22782, "freaked": 22783, "ulysses": 22784, "rebirth": 22785, "##alia": 22786, "##rent": 22787, "mummy": 22788, "guzman": 22789, "jimenez": 22790, "stilled": 22791, "##nitz": 22792, "trajectory": 22793, "tha": 22794, "woken": 22795, "archival": 22796, "professions": 22797, "##pts": 22798, "##pta": 22799, "hilly": 22800, "shadowy": 22801, "shrink": 22802, "##bolt": 22803, "norwood": 22804, "glued": 22805, "migrate": 22806, "stereotypes": 22807, "devoid": 22808, "##pheus": 22809, "625": 22810, "evacuate": 22811, "horrors": 22812, "infancy": 22813, "gotham": 22814, "knowles": 22815, "optic": 22816, "downloaded": 22817, "sachs": 22818, "kingsley": 22819, "parramatta": 22820, "darryl": 22821, "mor": 22822, "##onale": 22823, "shady": 22824, "commence": 22825, "confesses": 22826, "kan": 22827, "##meter": 22828, "##placed": 22829, "marlborough": 22830, "roundabout": 22831, "regents": 22832, "frigates": 22833, "io": 22834, "##imating": 22835, "gothenburg": 22836, "revoked": 22837, "carvings": 22838, "clockwise": 22839, "convertible": 22840, "intruder": 22841, "##sche": 22842, "banged": 22843, "##ogo": 22844, "vicky": 22845, "bourgeois": 22846, "##mony": 22847, "dupont": 22848, "footing": 22849, "##gum": 22850, "pd": 22851, "##real": 22852, "buckle": 22853, "yun": 22854, "penthouse": 22855, "sane": 22856, "720": 22857, "serviced": 22858, "stakeholders": 22859, "neumann": 22860, "bb": 22861, "##eers": 22862, "comb": 22863, "##gam": 22864, "catchment": 22865, "pinning": 22866, "rallies": 22867, "typing": 22868, "##elles": 22869, "forefront": 22870, "freiburg": 22871, "sweetie": 22872, "giacomo": 22873, "widowed": 22874, "goodwill": 22875, "worshipped": 22876, "aspirations": 22877, "midday": 22878, "##vat": 22879, "fishery": 22880, "##trick": 22881, "bournemouth": 22882, "turk": 22883, "243": 22884, "hearth": 22885, "ethanol": 22886, "guadalajara": 22887, "murmurs": 22888, "sl": 22889, "##uge": 22890, "afforded": 22891, "scripted": 22892, "##hta": 22893, "wah": 22894, "##jn": 22895, "coroner": 22896, "translucent": 22897, "252": 22898, "memorials": 22899, "puck": 22900, "progresses": 22901, "clumsy": 22902, "##race": 22903, "315": 22904, "candace": 22905, "recounted": 22906, "##27": 22907, "##slin": 22908, "##uve": 22909, "filtering": 22910, "##mac": 22911, "howl": 22912, "strata": 22913, "heron": 22914, "leveled": 22915, "##ays": 22916, "dubious": 22917, "##oja": 22918, "##т": 22919, "##wheel": 22920, "citations": 22921, "exhibiting": 22922, "##laya": 22923, "##mics": 22924, "##pods": 22925, "turkic": 22926, "##lberg": 22927, "injunction": 22928, "##ennial": 22929, "##mit": 22930, "antibodies": 22931, "##44": 22932, "organise": 22933, "##rigues": 22934, "cardiovascular": 22935, "cushion": 22936, "inverness": 22937, "##zquez": 22938, "dia": 22939, "cocoa": 22940, "sibling": 22941, "##tman": 22942, "##roid": 22943, "expanse": 22944, "feasible": 22945, "tunisian": 22946, "algiers": 22947, "##relli": 22948, "rus": 22949, "bloomberg": 22950, "dso": 22951, "westphalia": 22952, "bro": 22953, "tacoma": 22954, "281": 22955, "downloads": 22956, "##ours": 22957, "konrad": 22958, "duran": 22959, "##hdi": 22960, "continuum": 22961, "jett": 22962, "compares": 22963, "legislator": 22964, "secession": 22965, "##nable": 22966, "##gues": 22967, "##zuka": 22968, "translating": 22969, "reacher": 22970, "##gley": 22971, "##ła": 22972, "aleppo": 22973, "##agi": 22974, "tc": 22975, "orchards": 22976, "trapping": 22977, "linguist": 22978, "versatile": 22979, "drumming": 22980, "postage": 22981, "calhoun": 22982, "superiors": 22983, "##mx": 22984, "barefoot": 22985, "leary": 22986, "##cis": 22987, "ignacio": 22988, "alfa": 22989, "kaplan": 22990, "##rogen": 22991, "bratislava": 22992, "mori": 22993, "##vot": 22994, "disturb": 22995, "haas": 22996, "313": 22997, "cartridges": 22998, "gilmore": 22999, "radiated": 23000, "salford": 23001, "tunic": 23002, "hades": 23003, "##ulsive": 23004, "archeological": 23005, "delilah": 23006, "magistrates": 23007, "auditioned": 23008, "brewster": 23009, "charters": 23010, "empowerment": 23011, "blogs": 23012, "cappella": 23013, "dynasties": 23014, "iroquois": 23015, "whipping": 23016, "##krishna": 23017, "raceway": 23018, "truths": 23019, "myra": 23020, "weaken": 23021, "judah": 23022, "mcgregor": 23023, "##horse": 23024, "mic": 23025, "refueling": 23026, "37th": 23027, "burnley": 23028, "bosses": 23029, "markus": 23030, "premio": 23031, "query": 23032, "##gga": 23033, "dunbar": 23034, "##economic": 23035, "darkest": 23036, "lyndon": 23037, "sealing": 23038, "commendation": 23039, "reappeared": 23040, "##mun": 23041, "addicted": 23042, "ezio": 23043, "slaughtered": 23044, "satisfactory": 23045, "shuffle": 23046, "##eves": 23047, "##thic": 23048, "##uj": 23049, "fortification": 23050, "warrington": 23051, "##otto": 23052, "resurrected": 23053, "fargo": 23054, "mane": 23055, "##utable": 23056, "##lei": 23057, "##space": 23058, "foreword": 23059, "ox": 23060, "##aris": 23061, "##vern": 23062, "abrams": 23063, "hua": 23064, "##mento": 23065, "sakura": 23066, "##alo": 23067, "uv": 23068, "sentimental": 23069, "##skaya": 23070, "midfield": 23071, "##eses": 23072, "sturdy": 23073, "scrolls": 23074, "macleod": 23075, "##kyu": 23076, "entropy": 23077, "##lance": 23078, "mitochondrial": 23079, "cicero": 23080, "excelled": 23081, "thinner": 23082, "convoys": 23083, "perceive": 23084, "##oslav": 23085, "##urable": 23086, "systematically": 23087, "grind": 23088, "burkina": 23089, "287": 23090, "##tagram": 23091, "ops": 23092, "##aman": 23093, "guantanamo": 23094, "##cloth": 23095, "##tite": 23096, "forcefully": 23097, "wavy": 23098, "##jou": 23099, "pointless": 23100, "##linger": 23101, "##tze": 23102, "layton": 23103, "portico": 23104, "superficial": 23105, "clerical": 23106, "outlaws": 23107, "##hism": 23108, "burials": 23109, "muir": 23110, "##inn": 23111, "creditors": 23112, "hauling": 23113, "rattle": 23114, "##leg": 23115, "calais": 23116, "monde": 23117, "archers": 23118, "reclaimed": 23119, "dwell": 23120, "wexford": 23121, "hellenic": 23122, "falsely": 23123, "remorse": 23124, "##tek": 23125, "dough": 23126, "furnishings": 23127, "##uttered": 23128, "gabon": 23129, "neurological": 23130, "novice": 23131, "##igraphy": 23132, "contemplated": 23133, "pulpit": 23134, "nightstand": 23135, "saratoga": 23136, "##istan": 23137, "documenting": 23138, "pulsing": 23139, "taluk": 23140, "##firmed": 23141, "busted": 23142, "marital": 23143, "##rien": 23144, "disagreements": 23145, "wasps": 23146, "##yes": 23147, "hodge": 23148, "mcdonnell": 23149, "mimic": 23150, "fran": 23151, "pendant": 23152, "dhabi": 23153, "musa": 23154, "##nington": 23155, "congratulations": 23156, "argent": 23157, "darrell": 23158, "concussion": 23159, "losers": 23160, "regrets": 23161, "thessaloniki": 23162, "reversal": 23163, "donaldson": 23164, "hardwood": 23165, "thence": 23166, "achilles": 23167, "ritter": 23168, "##eran": 23169, "demonic": 23170, "jurgen": 23171, "prophets": 23172, "goethe": 23173, "eki": 23174, "classmate": 23175, "buff": 23176, "##cking": 23177, "yank": 23178, "irrational": 23179, "##inging": 23180, "perished": 23181, "seductive": 23182, "qur": 23183, "sourced": 23184, "##crat": 23185, "##typic": 23186, "mustard": 23187, "ravine": 23188, "barre": 23189, "horizontally": 23190, "characterization": 23191, "phylogenetic": 23192, "boise": 23193, "##dit": 23194, "##runner": 23195, "##tower": 23196, "brutally": 23197, "intercourse": 23198, "seduce": 23199, "##bbing": 23200, "fay": 23201, "ferris": 23202, "ogden": 23203, "amar": 23204, "nik": 23205, "unarmed": 23206, "##inator": 23207, "evaluating": 23208, "kyrgyzstan": 23209, "sweetness": 23210, "##lford": 23211, "##oki": 23212, "mccormick": 23213, "meiji": 23214, "notoriety": 23215, "stimulate": 23216, "disrupt": 23217, "figuring": 23218, "instructional": 23219, "mcgrath": 23220, "##zoo": 23221, "groundbreaking": 23222, "##lto": 23223, "flinch": 23224, "khorasan": 23225, "agrarian": 23226, "bengals": 23227, "mixer": 23228, "radiating": 23229, "##sov": 23230, "ingram": 23231, "pitchers": 23232, "nad": 23233, "tariff": 23234, "##cript": 23235, "tata": 23236, "##codes": 23237, "##emi": 23238, "##ungen": 23239, "appellate": 23240, "lehigh": 23241, "##bled": 23242, "##giri": 23243, "brawl": 23244, "duct": 23245, "texans": 23246, "##ciation": 23247, "##ropolis": 23248, "skipper": 23249, "speculative": 23250, "vomit": 23251, "doctrines": 23252, "stresses": 23253, "253": 23254, "davy": 23255, "graders": 23256, "whitehead": 23257, "jozef": 23258, "timely": 23259, "cumulative": 23260, "haryana": 23261, "paints": 23262, "appropriately": 23263, "boon": 23264, "cactus": 23265, "##ales": 23266, "##pid": 23267, "dow": 23268, "legions": 23269, "##pit": 23270, "perceptions": 23271, "1730": 23272, "picturesque": 23273, "##yse": 23274, "periphery": 23275, "rune": 23276, "wr": 23277, "##aha": 23278, "celtics": 23279, "sentencing": 23280, "whoa": 23281, "##erin": 23282, "confirms": 23283, "variance": 23284, "425": 23285, "moines": 23286, "mathews": 23287, "spade": 23288, "rave": 23289, "m1": 23290, "fronted": 23291, "fx": 23292, "blending": 23293, "alleging": 23294, "reared": 23295, "##gl": 23296, "237": 23297, "##paper": 23298, "grassroots": 23299, "eroded": 23300, "##free": 23301, "##physical": 23302, "directs": 23303, "ordeal": 23304, "##sław": 23305, "accelerate": 23306, "hacker": 23307, "rooftop": 23308, "##inia": 23309, "lev": 23310, "buys": 23311, "cebu": 23312, "devote": 23313, "##lce": 23314, "specialising": 23315, "##ulsion": 23316, "choreographed": 23317, "repetition": 23318, "warehouses": 23319, "##ryl": 23320, "paisley": 23321, "tuscany": 23322, "analogy": 23323, "sorcerer": 23324, "hash": 23325, "huts": 23326, "shards": 23327, "descends": 23328, "exclude": 23329, "nix": 23330, "chaplin": 23331, "gaga": 23332, "ito": 23333, "vane": 23334, "##drich": 23335, "causeway": 23336, "misconduct": 23337, "limo": 23338, "orchestrated": 23339, "glands": 23340, "jana": 23341, "##kot": 23342, "u2": 23343, "##mple": 23344, "##sons": 23345, "branching": 23346, "contrasts": 23347, "scoop": 23348, "longed": 23349, "##virus": 23350, "chattanooga": 23351, "##75": 23352, "syrup": 23353, "cornerstone": 23354, "##tized": 23355, "##mind": 23356, "##iaceae": 23357, "careless": 23358, "precedence": 23359, "frescoes": 23360, "##uet": 23361, "chilled": 23362, "consult": 23363, "modelled": 23364, "snatch": 23365, "peat": 23366, "##thermal": 23367, "caucasian": 23368, "humane": 23369, "relaxation": 23370, "spins": 23371, "temperance": 23372, "##lbert": 23373, "occupations": 23374, "lambda": 23375, "hybrids": 23376, "moons": 23377, "mp3": 23378, "##oese": 23379, "247": 23380, "rolf": 23381, "societal": 23382, "yerevan": 23383, "ness": 23384, "##ssler": 23385, "befriended": 23386, "mechanized": 23387, "nominate": 23388, "trough": 23389, "boasted": 23390, "cues": 23391, "seater": 23392, "##hom": 23393, "bends": 23394, "##tangle": 23395, "conductors": 23396, "emptiness": 23397, "##lmer": 23398, "eurasian": 23399, "adriatic": 23400, "tian": 23401, "##cie": 23402, "anxiously": 23403, "lark": 23404, "propellers": 23405, "chichester": 23406, "jock": 23407, "ev": 23408, "2a": 23409, "##holding": 23410, "credible": 23411, "recounts": 23412, "tori": 23413, "loyalist": 23414, "abduction": 23415, "##hoot": 23416, "##redo": 23417, "nepali": 23418, "##mite": 23419, "ventral": 23420, "tempting": 23421, "##ango": 23422, "##crats": 23423, "steered": 23424, "##wice": 23425, "javelin": 23426, "dipping": 23427, "laborers": 23428, "prentice": 23429, "looming": 23430, "titanium": 23431, "##ː": 23432, "badges": 23433, "emir": 23434, "tensor": 23435, "##ntation": 23436, "egyptians": 23437, "rash": 23438, "denies": 23439, "hawthorne": 23440, "lombard": 23441, "showers": 23442, "wehrmacht": 23443, "dietary": 23444, "trojan": 23445, "##reus": 23446, "welles": 23447, "executing": 23448, "horseshoe": 23449, "lifeboat": 23450, "##lak": 23451, "elsa": 23452, "infirmary": 23453, "nearing": 23454, "roberta": 23455, "boyer": 23456, "mutter": 23457, "trillion": 23458, "joanne": 23459, "##fine": 23460, "##oked": 23461, "sinks": 23462, "vortex": 23463, "uruguayan": 23464, "clasp": 23465, "sirius": 23466, "##block": 23467, "accelerator": 23468, "prohibit": 23469, "sunken": 23470, "byu": 23471, "chronological": 23472, "diplomats": 23473, "ochreous": 23474, "510": 23475, "symmetrical": 23476, "1644": 23477, "maia": 23478, "##tology": 23479, "salts": 23480, "reigns": 23481, "atrocities": 23482, "##ия": 23483, "hess": 23484, "bared": 23485, "issn": 23486, "##vyn": 23487, "cater": 23488, "saturated": 23489, "##cycle": 23490, "##isse": 23491, "sable": 23492, "voyager": 23493, "dyer": 23494, "yusuf": 23495, "##inge": 23496, "fountains": 23497, "wolff": 23498, "##39": 23499, "##nni": 23500, "engraving": 23501, "rollins": 23502, "atheist": 23503, "ominous": 23504, "##ault": 23505, "herr": 23506, "chariot": 23507, "martina": 23508, "strung": 23509, "##fell": 23510, "##farlane": 23511, "horrific": 23512, "sahib": 23513, "gazes": 23514, "saetan": 23515, "erased": 23516, "ptolemy": 23517, "##olic": 23518, "flushing": 23519, "lauderdale": 23520, "analytic": 23521, "##ices": 23522, "530": 23523, "navarro": 23524, "beak": 23525, "gorilla": 23526, "herrera": 23527, "broom": 23528, "guadalupe": 23529, "raiding": 23530, "sykes": 23531, "311": 23532, "bsc": 23533, "deliveries": 23534, "1720": 23535, "invasions": 23536, "carmichael": 23537, "tajikistan": 23538, "thematic": 23539, "ecumenical": 23540, "sentiments": 23541, "onstage": 23542, "##rians": 23543, "##brand": 23544, "##sume": 23545, "catastrophic": 23546, "flanks": 23547, "molten": 23548, "##arns": 23549, "waller": 23550, "aimee": 23551, "terminating": 23552, "##icing": 23553, "alternately": 23554, "##oche": 23555, "nehru": 23556, "printers": 23557, "outraged": 23558, "##eving": 23559, "empires": 23560, "template": 23561, "banners": 23562, "repetitive": 23563, "za": 23564, "##oise": 23565, "vegetarian": 23566, "##tell": 23567, "guiana": 23568, "opt": 23569, "cavendish": 23570, "lucknow": 23571, "synthesized": 23572, "##hani": 23573, "##mada": 23574, "finalized": 23575, "##ctable": 23576, "fictitious": 23577, "mayoral": 23578, "unreliable": 23579, "##enham": 23580, "embracing": 23581, "peppers": 23582, "rbis": 23583, "##chio": 23584, "##neo": 23585, "inhibition": 23586, "slashed": 23587, "togo": 23588, "orderly": 23589, "embroidered": 23590, "safari": 23591, "salty": 23592, "236": 23593, "barron": 23594, "benito": 23595, "totaled": 23596, "##dak": 23597, "pubs": 23598, "simulated": 23599, "caden": 23600, "devin": 23601, "tolkien": 23602, "momma": 23603, "welding": 23604, "sesame": 23605, "##ept": 23606, "gottingen": 23607, "hardness": 23608, "630": 23609, "shaman": 23610, "temeraire": 23611, "620": 23612, "adequately": 23613, "pediatric": 23614, "##kit": 23615, "ck": 23616, "assertion": 23617, "radicals": 23618, "composure": 23619, "cadence": 23620, "seafood": 23621, "beaufort": 23622, "lazarus": 23623, "mani": 23624, "warily": 23625, "cunning": 23626, "kurdistan": 23627, "249": 23628, "cantata": 23629, "##kir": 23630, "ares": 23631, "##41": 23632, "##clusive": 23633, "nape": 23634, "townland": 23635, "geared": 23636, "insulted": 23637, "flutter": 23638, "boating": 23639, "violate": 23640, "draper": 23641, "dumping": 23642, "malmo": 23643, "##hh": 23644, "##romatic": 23645, "firearm": 23646, "alta": 23647, "bono": 23648, "obscured": 23649, "##clave": 23650, "exceeds": 23651, "panorama": 23652, "unbelievable": 23653, "##train": 23654, "preschool": 23655, "##essed": 23656, "disconnected": 23657, "installing": 23658, "rescuing": 23659, "secretaries": 23660, "accessibility": 23661, "##castle": 23662, "##drive": 23663, "##ifice": 23664, "##film": 23665, "bouts": 23666, "slug": 23667, "waterway": 23668, "mindanao": 23669, "##buro": 23670, "##ratic": 23671, "halves": 23672, "##ل": 23673, "calming": 23674, "liter": 23675, "maternity": 23676, "adorable": 23677, "bragg": 23678, "electrification": 23679, "mcc": 23680, "##dote": 23681, "roxy": 23682, "schizophrenia": 23683, "##body": 23684, "munoz": 23685, "kaye": 23686, "whaling": 23687, "239": 23688, "mil": 23689, "tingling": 23690, "tolerant": 23691, "##ago": 23692, "unconventional": 23693, "volcanoes": 23694, "##finder": 23695, "deportivo": 23696, "##llie": 23697, "robson": 23698, "kaufman": 23699, "neuroscience": 23700, "wai": 23701, "deportation": 23702, "masovian": 23703, "scraping": 23704, "converse": 23705, "##bh": 23706, "hacking": 23707, "bulge": 23708, "##oun": 23709, "administratively": 23710, "yao": 23711, "580": 23712, "amp": 23713, "mammoth": 23714, "booster": 23715, "claremont": 23716, "hooper": 23717, "nomenclature": 23718, "pursuits": 23719, "mclaughlin": 23720, "melinda": 23721, "##sul": 23722, "catfish": 23723, "barclay": 23724, "substrates": 23725, "taxa": 23726, "zee": 23727, "originals": 23728, "kimberly": 23729, "packets": 23730, "padma": 23731, "##ality": 23732, "borrowing": 23733, "ostensibly": 23734, "solvent": 23735, "##bri": 23736, "##genesis": 23737, "##mist": 23738, "lukas": 23739, "shreveport": 23740, "veracruz": 23741, "##ь": 23742, "##lou": 23743, "##wives": 23744, "cheney": 23745, "tt": 23746, "anatolia": 23747, "hobbs": 23748, "##zyn": 23749, "cyclic": 23750, "radiant": 23751, "alistair": 23752, "greenish": 23753, "siena": 23754, "dat": 23755, "independents": 23756, "##bation": 23757, "conform": 23758, "pieter": 23759, "hyper": 23760, "applicant": 23761, "bradshaw": 23762, "spores": 23763, "telangana": 23764, "vinci": 23765, "inexpensive": 23766, "nuclei": 23767, "322": 23768, "jang": 23769, "nme": 23770, "soho": 23771, "spd": 23772, "##ign": 23773, "cradled": 23774, "receptionist": 23775, "pow": 23776, "##43": 23777, "##rika": 23778, "fascism": 23779, "##ifer": 23780, "experimenting": 23781, "##ading": 23782, "##iec": 23783, "##region": 23784, "345": 23785, "jocelyn": 23786, "maris": 23787, "stair": 23788, "nocturnal": 23789, "toro": 23790, "constabulary": 23791, "elgin": 23792, "##kker": 23793, "msc": 23794, "##giving": 23795, "##schen": 23796, "##rase": 23797, "doherty": 23798, "doping": 23799, "sarcastically": 23800, "batter": 23801, "maneuvers": 23802, "##cano": 23803, "##apple": 23804, "##gai": 23805, "##git": 23806, "intrinsic": 23807, "##nst": 23808, "##stor": 23809, "1753": 23810, "showtime": 23811, "cafes": 23812, "gasps": 23813, "lviv": 23814, "ushered": 23815, "##thed": 23816, "fours": 23817, "restart": 23818, "astonishment": 23819, "transmitting": 23820, "flyer": 23821, "shrugs": 23822, "##sau": 23823, "intriguing": 23824, "cones": 23825, "dictated": 23826, "mushrooms": 23827, "medial": 23828, "##kovsky": 23829, "##elman": 23830, "escorting": 23831, "gaped": 23832, "##26": 23833, "godfather": 23834, "##door": 23835, "##sell": 23836, "djs": 23837, "recaptured": 23838, "timetable": 23839, "vila": 23840, "1710": 23841, "3a": 23842, "aerodrome": 23843, "mortals": 23844, "scientology": 23845, "##orne": 23846, "angelina": 23847, "mag": 23848, "convection": 23849, "unpaid": 23850, "insertion": 23851, "intermittent": 23852, "lego": 23853, "##nated": 23854, "endeavor": 23855, "kota": 23856, "pereira": 23857, "##lz": 23858, "304": 23859, "bwv": 23860, "glamorgan": 23861, "insults": 23862, "agatha": 23863, "fey": 23864, "##cend": 23865, "fleetwood": 23866, "mahogany": 23867, "protruding": 23868, "steamship": 23869, "zeta": 23870, "##arty": 23871, "mcguire": 23872, "suspense": 23873, "##sphere": 23874, "advising": 23875, "urges": 23876, "##wala": 23877, "hurriedly": 23878, "meteor": 23879, "gilded": 23880, "inline": 23881, "arroyo": 23882, "stalker": 23883, "##oge": 23884, "excitedly": 23885, "revered": 23886, "##cure": 23887, "earle": 23888, "introductory": 23889, "##break": 23890, "##ilde": 23891, "mutants": 23892, "puff": 23893, "pulses": 23894, "reinforcement": 23895, "##haling": 23896, "curses": 23897, "lizards": 23898, "stalk": 23899, "correlated": 23900, "##fixed": 23901, "fallout": 23902, "macquarie": 23903, "##unas": 23904, "bearded": 23905, "denton": 23906, "heaving": 23907, "802": 23908, "##ocation": 23909, "winery": 23910, "assign": 23911, "dortmund": 23912, "##lkirk": 23913, "everest": 23914, "invariant": 23915, "charismatic": 23916, "susie": 23917, "##elling": 23918, "bled": 23919, "lesley": 23920, "telegram": 23921, "sumner": 23922, "bk": 23923, "##ogen": 23924, "##к": 23925, "wilcox": 23926, "needy": 23927, "colbert": 23928, "duval": 23929, "##iferous": 23930, "##mbled": 23931, "allotted": 23932, "attends": 23933, "imperative": 23934, "##hita": 23935, "replacements": 23936, "hawker": 23937, "##inda": 23938, "insurgency": 23939, "##zee": 23940, "##eke": 23941, "casts": 23942, "##yla": 23943, "680": 23944, "ives": 23945, "transitioned": 23946, "##pack": 23947, "##powering": 23948, "authoritative": 23949, "baylor": 23950, "flex": 23951, "cringed": 23952, "plaintiffs": 23953, "woodrow": 23954, "##skie": 23955, "drastic": 23956, "ape": 23957, "aroma": 23958, "unfolded": 23959, "commotion": 23960, "nt": 23961, "preoccupied": 23962, "theta": 23963, "routines": 23964, "lasers": 23965, "privatization": 23966, "wand": 23967, "domino": 23968, "ek": 23969, "clenching": 23970, "nsa": 23971, "strategically": 23972, "showered": 23973, "bile": 23974, "handkerchief": 23975, "pere": 23976, "storing": 23977, "christophe": 23978, "insulting": 23979, "316": 23980, "nakamura": 23981, "romani": 23982, "asiatic": 23983, "magdalena": 23984, "palma": 23985, "cruises": 23986, "stripping": 23987, "405": 23988, "konstantin": 23989, "soaring": 23990, "##berman": 23991, "colloquially": 23992, "forerunner": 23993, "havilland": 23994, "incarcerated": 23995, "parasites": 23996, "sincerity": 23997, "##utus": 23998, "disks": 23999, "plank": 24000, "saigon": 24001, "##ining": 24002, "corbin": 24003, "homo": 24004, "ornaments": 24005, "powerhouse": 24006, "##tlement": 24007, "chong": 24008, "fastened": 24009, "feasibility": 24010, "idf": 24011, "morphological": 24012, "usable": 24013, "##nish": 24014, "##zuki": 24015, "aqueduct": 24016, "jaguars": 24017, "keepers": 24018, "##flies": 24019, "aleksandr": 24020, "faust": 24021, "assigns": 24022, "ewing": 24023, "bacterium": 24024, "hurled": 24025, "tricky": 24026, "hungarians": 24027, "integers": 24028, "wallis": 24029, "321": 24030, "yamaha": 24031, "##isha": 24032, "hushed": 24033, "oblivion": 24034, "aviator": 24035, "evangelist": 24036, "friars": 24037, "##eller": 24038, "monograph": 24039, "ode": 24040, "##nary": 24041, "airplanes": 24042, "labourers": 24043, "charms": 24044, "##nee": 24045, "1661": 24046, "hagen": 24047, "tnt": 24048, "rudder": 24049, "fiesta": 24050, "transcript": 24051, "dorothea": 24052, "ska": 24053, "inhibitor": 24054, "maccabi": 24055, "retorted": 24056, "raining": 24057, "encompassed": 24058, "clauses": 24059, "menacing": 24060, "1642": 24061, "lineman": 24062, "##gist": 24063, "vamps": 24064, "##ape": 24065, "##dick": 24066, "gloom": 24067, "##rera": 24068, "dealings": 24069, "easing": 24070, "seekers": 24071, "##nut": 24072, "##pment": 24073, "helens": 24074, "unmanned": 24075, "##anu": 24076, "##isson": 24077, "basics": 24078, "##amy": 24079, "##ckman": 24080, "adjustments": 24081, "1688": 24082, "brutality": 24083, "horne": 24084, "##zell": 24085, "sui": 24086, "##55": 24087, "##mable": 24088, "aggregator": 24089, "##thal": 24090, "rhino": 24091, "##drick": 24092, "##vira": 24093, "counters": 24094, "zoom": 24095, "##01": 24096, "##rting": 24097, "mn": 24098, "montenegrin": 24099, "packard": 24100, "##unciation": 24101, "##♭": 24102, "##kki": 24103, "reclaim": 24104, "scholastic": 24105, "thugs": 24106, "pulsed": 24107, "##icia": 24108, "syriac": 24109, "quan": 24110, "saddam": 24111, "banda": 24112, "kobe": 24113, "blaming": 24114, "buddies": 24115, "dissent": 24116, "##lusion": 24117, "##usia": 24118, "corbett": 24119, "jaya": 24120, "delle": 24121, "erratic": 24122, "lexie": 24123, "##hesis": 24124, "435": 24125, "amiga": 24126, "hermes": 24127, "##pressing": 24128, "##leen": 24129, "chapels": 24130, "gospels": 24131, "jamal": 24132, "##uating": 24133, "compute": 24134, "revolving": 24135, "warp": 24136, "##sso": 24137, "##thes": 24138, "armory": 24139, "##eras": 24140, "##gol": 24141, "antrim": 24142, "loki": 24143, "##kow": 24144, "##asian": 24145, "##good": 24146, "##zano": 24147, "braid": 24148, "handwriting": 24149, "subdistrict": 24150, "funky": 24151, "pantheon": 24152, "##iculate": 24153, "concurrency": 24154, "estimation": 24155, "improper": 24156, "juliana": 24157, "##his": 24158, "newcomers": 24159, "johnstone": 24160, "staten": 24161, "communicated": 24162, "##oco": 24163, "##alle": 24164, "sausage": 24165, "stormy": 24166, "##stered": 24167, "##tters": 24168, "superfamily": 24169, "##grade": 24170, "acidic": 24171, "collateral": 24172, "tabloid": 24173, "##oped": 24174, "##rza": 24175, "bladder": 24176, "austen": 24177, "##ellant": 24178, "mcgraw": 24179, "##hay": 24180, "hannibal": 24181, "mein": 24182, "aquino": 24183, "lucifer": 24184, "wo": 24185, "badger": 24186, "boar": 24187, "cher": 24188, "christensen": 24189, "greenberg": 24190, "interruption": 24191, "##kken": 24192, "jem": 24193, "244": 24194, "mocked": 24195, "bottoms": 24196, "cambridgeshire": 24197, "##lide": 24198, "sprawling": 24199, "##bbly": 24200, "eastwood": 24201, "ghent": 24202, "synth": 24203, "##buck": 24204, "advisers": 24205, "##bah": 24206, "nominally": 24207, "hapoel": 24208, "qu": 24209, "daggers": 24210, "estranged": 24211, "fabricated": 24212, "towels": 24213, "vinnie": 24214, "wcw": 24215, "misunderstanding": 24216, "anglia": 24217, "nothin": 24218, "unmistakable": 24219, "##dust": 24220, "##lova": 24221, "chilly": 24222, "marquette": 24223, "truss": 24224, "##edge": 24225, "##erine": 24226, "reece": 24227, "##lty": 24228, "##chemist": 24229, "##connected": 24230, "272": 24231, "308": 24232, "41st": 24233, "bash": 24234, "raion": 24235, "waterfalls": 24236, "##ump": 24237, "##main": 24238, "labyrinth": 24239, "queue": 24240, "theorist": 24241, "##istle": 24242, "bharatiya": 24243, "flexed": 24244, "soundtracks": 24245, "rooney": 24246, "leftist": 24247, "patrolling": 24248, "wharton": 24249, "plainly": 24250, "alleviate": 24251, "eastman": 24252, "schuster": 24253, "topographic": 24254, "engages": 24255, "immensely": 24256, "unbearable": 24257, "fairchild": 24258, "1620": 24259, "dona": 24260, "lurking": 24261, "parisian": 24262, "oliveira": 24263, "ia": 24264, "indictment": 24265, "hahn": 24266, "bangladeshi": 24267, "##aster": 24268, "vivo": 24269, "##uming": 24270, "##ential": 24271, "antonia": 24272, "expects": 24273, "indoors": 24274, "kildare": 24275, "harlan": 24276, "##logue": 24277, "##ogenic": 24278, "##sities": 24279, "forgiven": 24280, "##wat": 24281, "childish": 24282, "tavi": 24283, "##mide": 24284, "##orra": 24285, "plausible": 24286, "grimm": 24287, "successively": 24288, "scooted": 24289, "##bola": 24290, "##dget": 24291, "##rith": 24292, "spartans": 24293, "emery": 24294, "flatly": 24295, "azure": 24296, "epilogue": 24297, "##wark": 24298, "flourish": 24299, "##iny": 24300, "##tracted": 24301, "##overs": 24302, "##oshi": 24303, "bestseller": 24304, "distressed": 24305, "receipt": 24306, "spitting": 24307, "hermit": 24308, "topological": 24309, "##cot": 24310, "drilled": 24311, "subunit": 24312, "francs": 24313, "##layer": 24314, "eel": 24315, "##fk": 24316, "##itas": 24317, "octopus": 24318, "footprint": 24319, "petitions": 24320, "ufo": 24321, "##say": 24322, "##foil": 24323, "interfering": 24324, "leaking": 24325, "palo": 24326, "##metry": 24327, "thistle": 24328, "valiant": 24329, "##pic": 24330, "narayan": 24331, "mcpherson": 24332, "##fast": 24333, "gonzales": 24334, "##ym": 24335, "##enne": 24336, "dustin": 24337, "novgorod": 24338, "solos": 24339, "##zman": 24340, "doin": 24341, "##raph": 24342, "##patient": 24343, "##meyer": 24344, "soluble": 24345, "ashland": 24346, "cuffs": 24347, "carole": 24348, "pendleton": 24349, "whistling": 24350, "vassal": 24351, "##river": 24352, "deviation": 24353, "revisited": 24354, "constituents": 24355, "rallied": 24356, "rotate": 24357, "loomed": 24358, "##eil": 24359, "##nting": 24360, "amateurs": 24361, "augsburg": 24362, "auschwitz": 24363, "crowns": 24364, "skeletons": 24365, "##cona": 24366, "bonnet": 24367, "257": 24368, "dummy": 24369, "globalization": 24370, "simeon": 24371, "sleeper": 24372, "mandal": 24373, "differentiated": 24374, "##crow": 24375, "##mare": 24376, "milne": 24377, "bundled": 24378, "exasperated": 24379, "talmud": 24380, "owes": 24381, "segregated": 24382, "##feng": 24383, "##uary": 24384, "dentist": 24385, "piracy": 24386, "props": 24387, "##rang": 24388, "devlin": 24389, "##torium": 24390, "malicious": 24391, "paws": 24392, "##laid": 24393, "dependency": 24394, "##ergy": 24395, "##fers": 24396, "##enna": 24397, "258": 24398, "pistons": 24399, "rourke": 24400, "jed": 24401, "grammatical": 24402, "tres": 24403, "maha": 24404, "wig": 24405, "512": 24406, "ghostly": 24407, "jayne": 24408, "##achal": 24409, "##creen": 24410, "##ilis": 24411, "##lins": 24412, "##rence": 24413, "designate": 24414, "##with": 24415, "arrogance": 24416, "cambodian": 24417, "clones": 24418, "showdown": 24419, "throttle": 24420, "twain": 24421, "##ception": 24422, "lobes": 24423, "metz": 24424, "nagoya": 24425, "335": 24426, "braking": 24427, "##furt": 24428, "385": 24429, "roaming": 24430, "##minster": 24431, "amin": 24432, "crippled": 24433, "##37": 24434, "##llary": 24435, "indifferent": 24436, "hoffmann": 24437, "idols": 24438, "intimidating": 24439, "1751": 24440, "261": 24441, "influenza": 24442, "memo": 24443, "onions": 24444, "1748": 24445, "bandage": 24446, "consciously": 24447, "##landa": 24448, "##rage": 24449, "clandestine": 24450, "observes": 24451, "swiped": 24452, "tangle": 24453, "##ener": 24454, "##jected": 24455, "##trum": 24456, "##bill": 24457, "##lta": 24458, "hugs": 24459, "congresses": 24460, "josiah": 24461, "spirited": 24462, "##dek": 24463, "humanist": 24464, "managerial": 24465, "filmmaking": 24466, "inmate": 24467, "rhymes": 24468, "debuting": 24469, "grimsby": 24470, "ur": 24471, "##laze": 24472, "duplicate": 24473, "vigor": 24474, "##tf": 24475, "republished": 24476, "bolshevik": 24477, "refurbishment": 24478, "antibiotics": 24479, "martini": 24480, "methane": 24481, "newscasts": 24482, "royale": 24483, "horizons": 24484, "levant": 24485, "iain": 24486, "visas": 24487, "##ischen": 24488, "paler": 24489, "##around": 24490, "manifestation": 24491, "snuck": 24492, "alf": 24493, "chop": 24494, "futile": 24495, "pedestal": 24496, "rehab": 24497, "##kat": 24498, "bmg": 24499, "kerman": 24500, "res": 24501, "fairbanks": 24502, "jarrett": 24503, "abstraction": 24504, "saharan": 24505, "##zek": 24506, "1746": 24507, "procedural": 24508, "clearer": 24509, "kincaid": 24510, "sash": 24511, "luciano": 24512, "##ffey": 24513, "crunch": 24514, "helmut": 24515, "##vara": 24516, "revolutionaries": 24517, "##tute": 24518, "creamy": 24519, "leach": 24520, "##mmon": 24521, "1747": 24522, "permitting": 24523, "nes": 24524, "plight": 24525, "wendell": 24526, "##lese": 24527, "contra": 24528, "ts": 24529, "clancy": 24530, "ipa": 24531, "mach": 24532, "staples": 24533, "autopsy": 24534, "disturbances": 24535, "nueva": 24536, "karin": 24537, "pontiac": 24538, "##uding": 24539, "proxy": 24540, "venerable": 24541, "haunt": 24542, "leto": 24543, "bergman": 24544, "expands": 24545, "##helm": 24546, "wal": 24547, "##pipe": 24548, "canning": 24549, "celine": 24550, "cords": 24551, "obesity": 24552, "##enary": 24553, "intrusion": 24554, "planner": 24555, "##phate": 24556, "reasoned": 24557, "sequencing": 24558, "307": 24559, "harrow": 24560, "##chon": 24561, "##dora": 24562, "marred": 24563, "mcintyre": 24564, "repay": 24565, "tarzan": 24566, "darting": 24567, "248": 24568, "harrisburg": 24569, "margarita": 24570, "repulsed": 24571, "##hur": 24572, "##lding": 24573, "belinda": 24574, "hamburger": 24575, "novo": 24576, "compliant": 24577, "runways": 24578, "bingham": 24579, "registrar": 24580, "skyscraper": 24581, "ic": 24582, "cuthbert": 24583, "improvisation": 24584, "livelihood": 24585, "##corp": 24586, "##elial": 24587, "admiring": 24588, "##dened": 24589, "sporadic": 24590, "believer": 24591, "casablanca": 24592, "popcorn": 24593, "##29": 24594, "asha": 24595, "shovel": 24596, "##bek": 24597, "##dice": 24598, "coiled": 24599, "tangible": 24600, "##dez": 24601, "casper": 24602, "elsie": 24603, "resin": 24604, "tenderness": 24605, "rectory": 24606, "##ivision": 24607, "avail": 24608, "sonar": 24609, "##mori": 24610, "boutique": 24611, "##dier": 24612, "guerre": 24613, "bathed": 24614, "upbringing": 24615, "vaulted": 24616, "sandals": 24617, "blessings": 24618, "##naut": 24619, "##utnant": 24620, "1680": 24621, "306": 24622, "foxes": 24623, "pia": 24624, "corrosion": 24625, "hesitantly": 24626, "confederates": 24627, "crystalline": 24628, "footprints": 24629, "shapiro": 24630, "tirana": 24631, "valentin": 24632, "drones": 24633, "45th": 24634, "microscope": 24635, "shipments": 24636, "texted": 24637, "inquisition": 24638, "wry": 24639, "guernsey": 24640, "unauthorized": 24641, "resigning": 24642, "760": 24643, "ripple": 24644, "schubert": 24645, "stu": 24646, "reassure": 24647, "felony": 24648, "##ardo": 24649, "brittle": 24650, "koreans": 24651, "##havan": 24652, "##ives": 24653, "dun": 24654, "implicit": 24655, "tyres": 24656, "##aldi": 24657, "##lth": 24658, "magnolia": 24659, "##ehan": 24660, "##puri": 24661, "##poulos": 24662, "aggressively": 24663, "fei": 24664, "gr": 24665, "familiarity": 24666, "##poo": 24667, "indicative": 24668, "##trust": 24669, "fundamentally": 24670, "jimmie": 24671, "overrun": 24672, "395": 24673, "anchors": 24674, "moans": 24675, "##opus": 24676, "britannia": 24677, "armagh": 24678, "##ggle": 24679, "purposely": 24680, "seizing": 24681, "##vao": 24682, "bewildered": 24683, "mundane": 24684, "avoidance": 24685, "cosmopolitan": 24686, "geometridae": 24687, "quartermaster": 24688, "caf": 24689, "415": 24690, "chatter": 24691, "engulfed": 24692, "gleam": 24693, "purge": 24694, "##icate": 24695, "juliette": 24696, "jurisprudence": 24697, "guerra": 24698, "revisions": 24699, "##bn": 24700, "casimir": 24701, "brew": 24702, "##jm": 24703, "1749": 24704, "clapton": 24705, "cloudy": 24706, "conde": 24707, "hermitage": 24708, "278": 24709, "simulations": 24710, "torches": 24711, "vincenzo": 24712, "matteo": 24713, "##rill": 24714, "hidalgo": 24715, "booming": 24716, "westbound": 24717, "accomplishment": 24718, "tentacles": 24719, "unaffected": 24720, "##sius": 24721, "annabelle": 24722, "flopped": 24723, "sloping": 24724, "##litz": 24725, "dreamer": 24726, "interceptor": 24727, "vu": 24728, "##loh": 24729, "consecration": 24730, "copying": 24731, "messaging": 24732, "breaker": 24733, "climates": 24734, "hospitalized": 24735, "1752": 24736, "torino": 24737, "afternoons": 24738, "winfield": 24739, "witnessing": 24740, "##teacher": 24741, "breakers": 24742, "choirs": 24743, "sawmill": 24744, "coldly": 24745, "##ege": 24746, "sipping": 24747, "haste": 24748, "uninhabited": 24749, "conical": 24750, "bibliography": 24751, "pamphlets": 24752, "severn": 24753, "edict": 24754, "##oca": 24755, "deux": 24756, "illnesses": 24757, "grips": 24758, "##pl": 24759, "rehearsals": 24760, "sis": 24761, "thinkers": 24762, "tame": 24763, "##keepers": 24764, "1690": 24765, "acacia": 24766, "reformer": 24767, "##osed": 24768, "##rys": 24769, "shuffling": 24770, "##iring": 24771, "##shima": 24772, "eastbound": 24773, "ionic": 24774, "rhea": 24775, "flees": 24776, "littered": 24777, "##oum": 24778, "rocker": 24779, "vomiting": 24780, "groaning": 24781, "champ": 24782, "overwhelmingly": 24783, "civilizations": 24784, "paces": 24785, "sloop": 24786, "adoptive": 24787, "##tish": 24788, "skaters": 24789, "##vres": 24790, "aiding": 24791, "mango": 24792, "##joy": 24793, "nikola": 24794, "shriek": 24795, "##ignon": 24796, "pharmaceuticals": 24797, "##mg": 24798, "tuna": 24799, "calvert": 24800, "gustavo": 24801, "stocked": 24802, "yearbook": 24803, "##urai": 24804, "##mana": 24805, "computed": 24806, "subsp": 24807, "riff": 24808, "hanoi": 24809, "kelvin": 24810, "hamid": 24811, "moors": 24812, "pastures": 24813, "summons": 24814, "jihad": 24815, "nectar": 24816, "##ctors": 24817, "bayou": 24818, "untitled": 24819, "pleasing": 24820, "vastly": 24821, "republics": 24822, "intellect": 24823, "##η": 24824, "##ulio": 24825, "##tou": 24826, "crumbling": 24827, "stylistic": 24828, "sb": 24829, "##ی": 24830, "consolation": 24831, "frequented": 24832, "h₂o": 24833, "walden": 24834, "widows": 24835, "##iens": 24836, "404": 24837, "##ignment": 24838, "chunks": 24839, "improves": 24840, "288": 24841, "grit": 24842, "recited": 24843, "##dev": 24844, "snarl": 24845, "sociological": 24846, "##arte": 24847, "##gul": 24848, "inquired": 24849, "##held": 24850, "bruise": 24851, "clube": 24852, "consultancy": 24853, "homogeneous": 24854, "hornets": 24855, "multiplication": 24856, "pasta": 24857, "prick": 24858, "savior": 24859, "##grin": 24860, "##kou": 24861, "##phile": 24862, "yoon": 24863, "##gara": 24864, "grimes": 24865, "vanishing": 24866, "cheering": 24867, "reacting": 24868, "bn": 24869, "distillery": 24870, "##quisite": 24871, "##vity": 24872, "coe": 24873, "dockyard": 24874, "massif": 24875, "##jord": 24876, "escorts": 24877, "voss": 24878, "##valent": 24879, "byte": 24880, "chopped": 24881, "hawke": 24882, "illusions": 24883, "workings": 24884, "floats": 24885, "##koto": 24886, "##vac": 24887, "kv": 24888, "annapolis": 24889, "madden": 24890, "##onus": 24891, "alvaro": 24892, "noctuidae": 24893, "##cum": 24894, "##scopic": 24895, "avenge": 24896, "steamboat": 24897, "forte": 24898, "illustrates": 24899, "erika": 24900, "##trip": 24901, "570": 24902, "dew": 24903, "nationalities": 24904, "bran": 24905, "manifested": 24906, "thirsty": 24907, "diversified": 24908, "muscled": 24909, "reborn": 24910, "##standing": 24911, "arson": 24912, "##lessness": 24913, "##dran": 24914, "##logram": 24915, "##boys": 24916, "##kushima": 24917, "##vious": 24918, "willoughby": 24919, "##phobia": 24920, "286": 24921, "alsace": 24922, "dashboard": 24923, "yuki": 24924, "##chai": 24925, "granville": 24926, "myspace": 24927, "publicized": 24928, "tricked": 24929, "##gang": 24930, "adjective": 24931, "##ater": 24932, "relic": 24933, "reorganisation": 24934, "enthusiastically": 24935, "indications": 24936, "saxe": 24937, "##lassified": 24938, "consolidate": 24939, "iec": 24940, "padua": 24941, "helplessly": 24942, "ramps": 24943, "renaming": 24944, "regulars": 24945, "pedestrians": 24946, "accents": 24947, "convicts": 24948, "inaccurate": 24949, "lowers": 24950, "mana": 24951, "##pati": 24952, "barrie": 24953, "bjp": 24954, "outta": 24955, "someplace": 24956, "berwick": 24957, "flanking": 24958, "invoked": 24959, "marrow": 24960, "sparsely": 24961, "excerpts": 24962, "clothed": 24963, "rei": 24964, "##ginal": 24965, "wept": 24966, "##straße": 24967, "##vish": 24968, "alexa": 24969, "excel": 24970, "##ptive": 24971, "membranes": 24972, "aquitaine": 24973, "creeks": 24974, "cutler": 24975, "sheppard": 24976, "implementations": 24977, "ns": 24978, "##dur": 24979, "fragrance": 24980, "budge": 24981, "concordia": 24982, "magnesium": 24983, "marcelo": 24984, "##antes": 24985, "gladly": 24986, "vibrating": 24987, "##rral": 24988, "##ggles": 24989, "montrose": 24990, "##omba": 24991, "lew": 24992, "seamus": 24993, "1630": 24994, "cocky": 24995, "##ament": 24996, "##uen": 24997, "bjorn": 24998, "##rrick": 24999, "fielder": 25000, "fluttering": 25001, "##lase": 25002, "methyl": 25003, "kimberley": 25004, "mcdowell": 25005, "reductions": 25006, "barbed": 25007, "##jic": 25008, "##tonic": 25009, "aeronautical": 25010, "condensed": 25011, "distracting": 25012, "##promising": 25013, "huffed": 25014, "##cala": 25015, "##sle": 25016, "claudius": 25017, "invincible": 25018, "missy": 25019, "pious": 25020, "balthazar": 25021, "ci": 25022, "##lang": 25023, "butte": 25024, "combo": 25025, "orson": 25026, "##dication": 25027, "myriad": 25028, "1707": 25029, "silenced": 25030, "##fed": 25031, "##rh": 25032, "coco": 25033, "netball": 25034, "yourselves": 25035, "##oza": 25036, "clarify": 25037, "heller": 25038, "peg": 25039, "durban": 25040, "etudes": 25041, "offender": 25042, "roast": 25043, "blackmail": 25044, "curvature": 25045, "##woods": 25046, "vile": 25047, "309": 25048, "illicit": 25049, "suriname": 25050, "##linson": 25051, "overture": 25052, "1685": 25053, "bubbling": 25054, "gymnast": 25055, "tucking": 25056, "##mming": 25057, "##ouin": 25058, "maldives": 25059, "##bala": 25060, "gurney": 25061, "##dda": 25062, "##eased": 25063, "##oides": 25064, "backside": 25065, "pinto": 25066, "jars": 25067, "racehorse": 25068, "tending": 25069, "##rdial": 25070, "baronetcy": 25071, "wiener": 25072, "duly": 25073, "##rke": 25074, "barbarian": 25075, "cupping": 25076, "flawed": 25077, "##thesis": 25078, "bertha": 25079, "pleistocene": 25080, "puddle": 25081, "swearing": 25082, "##nob": 25083, "##tically": 25084, "fleeting": 25085, "prostate": 25086, "amulet": 25087, "educating": 25088, "##mined": 25089, "##iti": 25090, "##tler": 25091, "75th": 25092, "jens": 25093, "respondents": 25094, "analytics": 25095, "cavaliers": 25096, "papacy": 25097, "raju": 25098, "##iente": 25099, "##ulum": 25100, "##tip": 25101, "funnel": 25102, "271": 25103, "disneyland": 25104, "##lley": 25105, "sociologist": 25106, "##iam": 25107, "2500": 25108, "faulkner": 25109, "louvre": 25110, "menon": 25111, "##dson": 25112, "276": 25113, "##ower": 25114, "afterlife": 25115, "mannheim": 25116, "peptide": 25117, "referees": 25118, "comedians": 25119, "meaningless": 25120, "##anger": 25121, "##laise": 25122, "fabrics": 25123, "hurley": 25124, "renal": 25125, "sleeps": 25126, "##bour": 25127, "##icle": 25128, "breakout": 25129, "kristin": 25130, "roadside": 25131, "animator": 25132, "clover": 25133, "disdain": 25134, "unsafe": 25135, "redesign": 25136, "##urity": 25137, "firth": 25138, "barnsley": 25139, "portage": 25140, "reset": 25141, "narrows": 25142, "268": 25143, "commandos": 25144, "expansive": 25145, "speechless": 25146, "tubular": 25147, "##lux": 25148, "essendon": 25149, "eyelashes": 25150, "smashwords": 25151, "##yad": 25152, "##bang": 25153, "##claim": 25154, "craved": 25155, "sprinted": 25156, "chet": 25157, "somme": 25158, "astor": 25159, "wrocław": 25160, "orton": 25161, "266": 25162, "bane": 25163, "##erving": 25164, "##uing": 25165, "mischief": 25166, "##amps": 25167, "##sund": 25168, "scaling": 25169, "terre": 25170, "##xious": 25171, "impairment": 25172, "offenses": 25173, "undermine": 25174, "moi": 25175, "soy": 25176, "contiguous": 25177, "arcadia": 25178, "inuit": 25179, "seam": 25180, "##tops": 25181, "macbeth": 25182, "rebelled": 25183, "##icative": 25184, "##iot": 25185, "590": 25186, "elaborated": 25187, "frs": 25188, "uniformed": 25189, "##dberg": 25190, "259": 25191, "powerless": 25192, "priscilla": 25193, "stimulated": 25194, "980": 25195, "qc": 25196, "arboretum": 25197, "frustrating": 25198, "trieste": 25199, "bullock": 25200, "##nified": 25201, "enriched": 25202, "glistening": 25203, "intern": 25204, "##adia": 25205, "locus": 25206, "nouvelle": 25207, "ollie": 25208, "ike": 25209, "lash": 25210, "starboard": 25211, "ee": 25212, "tapestry": 25213, "headlined": 25214, "hove": 25215, "rigged": 25216, "##vite": 25217, "pollock": 25218, "##yme": 25219, "thrive": 25220, "clustered": 25221, "cas": 25222, "roi": 25223, "gleamed": 25224, "olympiad": 25225, "##lino": 25226, "pressured": 25227, "regimes": 25228, "##hosis": 25229, "##lick": 25230, "ripley": 25231, "##ophone": 25232, "kickoff": 25233, "gallon": 25234, "rockwell": 25235, "##arable": 25236, "crusader": 25237, "glue": 25238, "revolutions": 25239, "scrambling": 25240, "1714": 25241, "grover": 25242, "##jure": 25243, "englishman": 25244, "aztec": 25245, "263": 25246, "contemplating": 25247, "coven": 25248, "ipad": 25249, "preach": 25250, "triumphant": 25251, "tufts": 25252, "##esian": 25253, "rotational": 25254, "##phus": 25255, "328": 25256, "falkland": 25257, "##brates": 25258, "strewn": 25259, "clarissa": 25260, "rejoin": 25261, "environmentally": 25262, "glint": 25263, "banded": 25264, "drenched": 25265, "moat": 25266, "albanians": 25267, "johor": 25268, "rr": 25269, "maestro": 25270, "malley": 25271, "nouveau": 25272, "shaded": 25273, "taxonomy": 25274, "v6": 25275, "adhere": 25276, "bunk": 25277, "airfields": 25278, "##ritan": 25279, "1741": 25280, "encompass": 25281, "remington": 25282, "tran": 25283, "##erative": 25284, "amelie": 25285, "mazda": 25286, "friar": 25287, "morals": 25288, "passions": 25289, "##zai": 25290, "breadth": 25291, "vis": 25292, "##hae": 25293, "argus": 25294, "burnham": 25295, "caressing": 25296, "insider": 25297, "rudd": 25298, "##imov": 25299, "##mini": 25300, "##rso": 25301, "italianate": 25302, "murderous": 25303, "textual": 25304, "wainwright": 25305, "armada": 25306, "bam": 25307, "weave": 25308, "timer": 25309, "##taken": 25310, "##nh": 25311, "fra": 25312, "##crest": 25313, "ardent": 25314, "salazar": 25315, "taps": 25316, "tunis": 25317, "##ntino": 25318, "allegro": 25319, "gland": 25320, "philanthropic": 25321, "##chester": 25322, "implication": 25323, "##optera": 25324, "esq": 25325, "judas": 25326, "noticeably": 25327, "wynn": 25328, "##dara": 25329, "inched": 25330, "indexed": 25331, "crises": 25332, "villiers": 25333, "bandit": 25334, "royalties": 25335, "patterned": 25336, "cupboard": 25337, "interspersed": 25338, "accessory": 25339, "isla": 25340, "kendrick": 25341, "entourage": 25342, "stitches": 25343, "##esthesia": 25344, "headwaters": 25345, "##ior": 25346, "interlude": 25347, "distraught": 25348, "draught": 25349, "1727": 25350, "##basket": 25351, "biased": 25352, "sy": 25353, "transient": 25354, "triad": 25355, "subgenus": 25356, "adapting": 25357, "kidd": 25358, "shortstop": 25359, "##umatic": 25360, "dimly": 25361, "spiked": 25362, "mcleod": 25363, "reprint": 25364, "nellie": 25365, "pretoria": 25366, "windmill": 25367, "##cek": 25368, "singled": 25369, "##mps": 25370, "273": 25371, "reunite": 25372, "##orous": 25373, "747": 25374, "bankers": 25375, "outlying": 25376, "##omp": 25377, "##ports": 25378, "##tream": 25379, "apologies": 25380, "cosmetics": 25381, "patsy": 25382, "##deh": 25383, "##ocks": 25384, "##yson": 25385, "bender": 25386, "nantes": 25387, "serene": 25388, "##nad": 25389, "lucha": 25390, "mmm": 25391, "323": 25392, "##cius": 25393, "##gli": 25394, "cmll": 25395, "coinage": 25396, "nestor": 25397, "juarez": 25398, "##rook": 25399, "smeared": 25400, "sprayed": 25401, "twitching": 25402, "sterile": 25403, "irina": 25404, "embodied": 25405, "juveniles": 25406, "enveloped": 25407, "miscellaneous": 25408, "cancers": 25409, "dq": 25410, "gulped": 25411, "luisa": 25412, "crested": 25413, "swat": 25414, "donegal": 25415, "ref": 25416, "##anov": 25417, "##acker": 25418, "hearst": 25419, "mercantile": 25420, "##lika": 25421, "doorbell": 25422, "ua": 25423, "vicki": 25424, "##alla": 25425, "##som": 25426, "bilbao": 25427, "psychologists": 25428, "stryker": 25429, "sw": 25430, "horsemen": 25431, "turkmenistan": 25432, "wits": 25433, "##national": 25434, "anson": 25435, "mathew": 25436, "screenings": 25437, "##umb": 25438, "rihanna": 25439, "##agne": 25440, "##nessy": 25441, "aisles": 25442, "##iani": 25443, "##osphere": 25444, "hines": 25445, "kenton": 25446, "saskatoon": 25447, "tasha": 25448, "truncated": 25449, "##champ": 25450, "##itan": 25451, "mildred": 25452, "advises": 25453, "fredrik": 25454, "interpreting": 25455, "inhibitors": 25456, "##athi": 25457, "spectroscopy": 25458, "##hab": 25459, "##kong": 25460, "karim": 25461, "panda": 25462, "##oia": 25463, "##nail": 25464, "##vc": 25465, "conqueror": 25466, "kgb": 25467, "leukemia": 25468, "##dity": 25469, "arrivals": 25470, "cheered": 25471, "pisa": 25472, "phosphorus": 25473, "shielded": 25474, "##riated": 25475, "mammal": 25476, "unitarian": 25477, "urgently": 25478, "chopin": 25479, "sanitary": 25480, "##mission": 25481, "spicy": 25482, "drugged": 25483, "hinges": 25484, "##tort": 25485, "tipping": 25486, "trier": 25487, "impoverished": 25488, "westchester": 25489, "##caster": 25490, "267": 25491, "epoch": 25492, "nonstop": 25493, "##gman": 25494, "##khov": 25495, "aromatic": 25496, "centrally": 25497, "cerro": 25498, "##tively": 25499, "##vio": 25500, "billions": 25501, "modulation": 25502, "sedimentary": 25503, "283": 25504, "facilitating": 25505, "outrageous": 25506, "goldstein": 25507, "##eak": 25508, "##kt": 25509, "ld": 25510, "maitland": 25511, "penultimate": 25512, "pollard": 25513, "##dance": 25514, "fleets": 25515, "spaceship": 25516, "vertebrae": 25517, "##nig": 25518, "alcoholism": 25519, "als": 25520, "recital": 25521, "##bham": 25522, "##ference": 25523, "##omics": 25524, "m2": 25525, "##bm": 25526, "trois": 25527, "##tropical": 25528, "##в": 25529, "commemorates": 25530, "##meric": 25531, "marge": 25532, "##raction": 25533, "1643": 25534, "670": 25535, "cosmetic": 25536, "ravaged": 25537, "##ige": 25538, "catastrophe": 25539, "eng": 25540, "##shida": 25541, "albrecht": 25542, "arterial": 25543, "bellamy": 25544, "decor": 25545, "harmon": 25546, "##rde": 25547, "bulbs": 25548, "synchronized": 25549, "vito": 25550, "easiest": 25551, "shetland": 25552, "shielding": 25553, "wnba": 25554, "##glers": 25555, "##ssar": 25556, "##riam": 25557, "brianna": 25558, "cumbria": 25559, "##aceous": 25560, "##rard": 25561, "cores": 25562, "thayer": 25563, "##nsk": 25564, "brood": 25565, "hilltop": 25566, "luminous": 25567, "carts": 25568, "keynote": 25569, "larkin": 25570, "logos": 25571, "##cta": 25572, "##ا": 25573, "##mund": 25574, "##quay": 25575, "lilith": 25576, "tinted": 25577, "277": 25578, "wrestle": 25579, "mobilization": 25580, "##uses": 25581, "sequential": 25582, "siam": 25583, "bloomfield": 25584, "takahashi": 25585, "274": 25586, "##ieving": 25587, "presenters": 25588, "ringo": 25589, "blazed": 25590, "witty": 25591, "##oven": 25592, "##ignant": 25593, "devastation": 25594, "haydn": 25595, "harmed": 25596, "newt": 25597, "therese": 25598, "##peed": 25599, "gershwin": 25600, "molina": 25601, "rabbis": 25602, "sudanese": 25603, "001": 25604, "innate": 25605, "restarted": 25606, "##sack": 25607, "##fus": 25608, "slices": 25609, "wb": 25610, "##shah": 25611, "enroll": 25612, "hypothetical": 25613, "hysterical": 25614, "1743": 25615, "fabio": 25616, "indefinite": 25617, "warped": 25618, "##hg": 25619, "exchanging": 25620, "525": 25621, "unsuitable": 25622, "##sboro": 25623, "gallo": 25624, "1603": 25625, "bret": 25626, "cobalt": 25627, "homemade": 25628, "##hunter": 25629, "mx": 25630, "operatives": 25631, "##dhar": 25632, "terraces": 25633, "durable": 25634, "latch": 25635, "pens": 25636, "whorls": 25637, "##ctuated": 25638, "##eaux": 25639, "billing": 25640, "ligament": 25641, "succumbed": 25642, "##gly": 25643, "regulators": 25644, "spawn": 25645, "##brick": 25646, "##stead": 25647, "filmfare": 25648, "rochelle": 25649, "##nzo": 25650, "1725": 25651, "circumstance": 25652, "saber": 25653, "supplements": 25654, "##nsky": 25655, "##tson": 25656, "crowe": 25657, "wellesley": 25658, "carrot": 25659, "##9th": 25660, "##movable": 25661, "primate": 25662, "drury": 25663, "sincerely": 25664, "topical": 25665, "##mad": 25666, "##rao": 25667, "callahan": 25668, "kyiv": 25669, "smarter": 25670, "tits": 25671, "undo": 25672, "##yeh": 25673, "announcements": 25674, "anthologies": 25675, "barrio": 25676, "nebula": 25677, "##islaus": 25678, "##shaft": 25679, "##tyn": 25680, "bodyguards": 25681, "2021": 25682, "assassinate": 25683, "barns": 25684, "emmett": 25685, "scully": 25686, "##mah": 25687, "##yd": 25688, "##eland": 25689, "##tino": 25690, "##itarian": 25691, "demoted": 25692, "gorman": 25693, "lashed": 25694, "prized": 25695, "adventist": 25696, "writ": 25697, "##gui": 25698, "alla": 25699, "invertebrates": 25700, "##ausen": 25701, "1641": 25702, "amman": 25703, "1742": 25704, "align": 25705, "healy": 25706, "redistribution": 25707, "##gf": 25708, "##rize": 25709, "insulation": 25710, "##drop": 25711, "adherents": 25712, "hezbollah": 25713, "vitro": 25714, "ferns": 25715, "yanking": 25716, "269": 25717, "php": 25718, "registering": 25719, "uppsala": 25720, "cheerleading": 25721, "confines": 25722, "mischievous": 25723, "tully": 25724, "##ross": 25725, "49th": 25726, "docked": 25727, "roam": 25728, "stipulated": 25729, "pumpkin": 25730, "##bry": 25731, "prompt": 25732, "##ezer": 25733, "blindly": 25734, "shuddering": 25735, "craftsmen": 25736, "frail": 25737, "scented": 25738, "katharine": 25739, "scramble": 25740, "shaggy": 25741, "sponge": 25742, "helix": 25743, "zaragoza": 25744, "279": 25745, "##52": 25746, "43rd": 25747, "backlash": 25748, "fontaine": 25749, "seizures": 25750, "posse": 25751, "cowan": 25752, "nonfiction": 25753, "telenovela": 25754, "wwii": 25755, "hammered": 25756, "undone": 25757, "##gpur": 25758, "encircled": 25759, "irs": 25760, "##ivation": 25761, "artefacts": 25762, "oneself": 25763, "searing": 25764, "smallpox": 25765, "##belle": 25766, "##osaurus": 25767, "shandong": 25768, "breached": 25769, "upland": 25770, "blushing": 25771, "rankin": 25772, "infinitely": 25773, "psyche": 25774, "tolerated": 25775, "docking": 25776, "evicted": 25777, "##col": 25778, "unmarked": 25779, "##lving": 25780, "gnome": 25781, "lettering": 25782, "litres": 25783, "musique": 25784, "##oint": 25785, "benevolent": 25786, "##jal": 25787, "blackened": 25788, "##anna": 25789, "mccall": 25790, "racers": 25791, "tingle": 25792, "##ocene": 25793, "##orestation": 25794, "introductions": 25795, "radically": 25796, "292": 25797, "##hiff": 25798, "##باد": 25799, "1610": 25800, "1739": 25801, "munchen": 25802, "plead": 25803, "##nka": 25804, "condo": 25805, "scissors": 25806, "##sight": 25807, "##tens": 25808, "apprehension": 25809, "##cey": 25810, "##yin": 25811, "hallmark": 25812, "watering": 25813, "formulas": 25814, "sequels": 25815, "##llas": 25816, "aggravated": 25817, "bae": 25818, "commencing": 25819, "##building": 25820, "enfield": 25821, "prohibits": 25822, "marne": 25823, "vedic": 25824, "civilized": 25825, "euclidean": 25826, "jagger": 25827, "beforehand": 25828, "blasts": 25829, "dumont": 25830, "##arney": 25831, "##nem": 25832, "740": 25833, "conversions": 25834, "hierarchical": 25835, "rios": 25836, "simulator": 25837, "##dya": 25838, "##lellan": 25839, "hedges": 25840, "oleg": 25841, "thrusts": 25842, "shadowed": 25843, "darby": 25844, "maximize": 25845, "1744": 25846, "gregorian": 25847, "##nded": 25848, "##routed": 25849, "sham": 25850, "unspecified": 25851, "##hog": 25852, "emory": 25853, "factual": 25854, "##smo": 25855, "##tp": 25856, "fooled": 25857, "##rger": 25858, "ortega": 25859, "wellness": 25860, "marlon": 25861, "##oton": 25862, "##urance": 25863, "casket": 25864, "keating": 25865, "ley": 25866, "enclave": 25867, "##ayan": 25868, "char": 25869, "influencing": 25870, "jia": 25871, "##chenko": 25872, "412": 25873, "ammonia": 25874, "erebidae": 25875, "incompatible": 25876, "violins": 25877, "cornered": 25878, "##arat": 25879, "grooves": 25880, "astronauts": 25881, "columbian": 25882, "rampant": 25883, "fabrication": 25884, "kyushu": 25885, "mahmud": 25886, "vanish": 25887, "##dern": 25888, "mesopotamia": 25889, "##lete": 25890, "ict": 25891, "##rgen": 25892, "caspian": 25893, "kenji": 25894, "pitted": 25895, "##vered": 25896, "999": 25897, "grimace": 25898, "roanoke": 25899, "tchaikovsky": 25900, "twinned": 25901, "##analysis": 25902, "##awan": 25903, "xinjiang": 25904, "arias": 25905, "clemson": 25906, "kazakh": 25907, "sizable": 25908, "1662": 25909, "##khand": 25910, "##vard": 25911, "plunge": 25912, "tatum": 25913, "vittorio": 25914, "##nden": 25915, "cholera": 25916, "##dana": 25917, "##oper": 25918, "bracing": 25919, "indifference": 25920, "projectile": 25921, "superliga": 25922, "##chee": 25923, "realises": 25924, "upgrading": 25925, "299": 25926, "porte": 25927, "retribution": 25928, "##vies": 25929, "nk": 25930, "stil": 25931, "##resses": 25932, "ama": 25933, "bureaucracy": 25934, "blackberry": 25935, "bosch": 25936, "testosterone": 25937, "collapses": 25938, "greer": 25939, "##pathic": 25940, "ioc": 25941, "fifties": 25942, "malls": 25943, "##erved": 25944, "bao": 25945, "baskets": 25946, "adolescents": 25947, "siegfried": 25948, "##osity": 25949, "##tosis": 25950, "mantra": 25951, "detecting": 25952, "existent": 25953, "fledgling": 25954, "##cchi": 25955, "dissatisfied": 25956, "gan": 25957, "telecommunication": 25958, "mingled": 25959, "sobbed": 25960, "6000": 25961, "controversies": 25962, "outdated": 25963, "taxis": 25964, "##raus": 25965, "fright": 25966, "slams": 25967, "##lham": 25968, "##fect": 25969, "##tten": 25970, "detectors": 25971, "fetal": 25972, "tanned": 25973, "##uw": 25974, "fray": 25975, "goth": 25976, "olympian": 25977, "skipping": 25978, "mandates": 25979, "scratches": 25980, "sheng": 25981, "unspoken": 25982, "hyundai": 25983, "tracey": 25984, "hotspur": 25985, "restrictive": 25986, "##buch": 25987, "americana": 25988, "mundo": 25989, "##bari": 25990, "burroughs": 25991, "diva": 25992, "vulcan": 25993, "##6th": 25994, "distinctions": 25995, "thumping": 25996, "##ngen": 25997, "mikey": 25998, "sheds": 25999, "fide": 26000, "rescues": 26001, "springsteen": 26002, "vested": 26003, "valuation": 26004, "##ece": 26005, "##ely": 26006, "pinnacle": 26007, "rake": 26008, "sylvie": 26009, "##edo": 26010, "almond": 26011, "quivering": 26012, "##irus": 26013, "alteration": 26014, "faltered": 26015, "##wad": 26016, "51st": 26017, "hydra": 26018, "ticked": 26019, "##kato": 26020, "recommends": 26021, "##dicated": 26022, "antigua": 26023, "arjun": 26024, "stagecoach": 26025, "wilfred": 26026, "trickle": 26027, "pronouns": 26028, "##pon": 26029, "aryan": 26030, "nighttime": 26031, "##anian": 26032, "gall": 26033, "pea": 26034, "stitch": 26035, "##hei": 26036, "leung": 26037, "milos": 26038, "##dini": 26039, "eritrea": 26040, "nexus": 26041, "starved": 26042, "snowfall": 26043, "kant": 26044, "parasitic": 26045, "cot": 26046, "discus": 26047, "hana": 26048, "strikers": 26049, "appleton": 26050, "kitchens": 26051, "##erina": 26052, "##partisan": 26053, "##itha": 26054, "##vius": 26055, "disclose": 26056, "metis": 26057, "##channel": 26058, "1701": 26059, "tesla": 26060, "##vera": 26061, "fitch": 26062, "1735": 26063, "blooded": 26064, "##tila": 26065, "decimal": 26066, "##tang": 26067, "##bai": 26068, "cyclones": 26069, "eun": 26070, "bottled": 26071, "peas": 26072, "pensacola": 26073, "basha": 26074, "bolivian": 26075, "crabs": 26076, "boil": 26077, "lanterns": 26078, "partridge": 26079, "roofed": 26080, "1645": 26081, "necks": 26082, "##phila": 26083, "opined": 26084, "patting": 26085, "##kla": 26086, "##lland": 26087, "chuckles": 26088, "volta": 26089, "whereupon": 26090, "##nche": 26091, "devout": 26092, "euroleague": 26093, "suicidal": 26094, "##dee": 26095, "inherently": 26096, "involuntary": 26097, "knitting": 26098, "nasser": 26099, "##hide": 26100, "puppets": 26101, "colourful": 26102, "courageous": 26103, "southend": 26104, "stills": 26105, "miraculous": 26106, "hodgson": 26107, "richer": 26108, "rochdale": 26109, "ethernet": 26110, "greta": 26111, "uniting": 26112, "prism": 26113, "umm": 26114, "##haya": 26115, "##itical": 26116, "##utation": 26117, "deterioration": 26118, "pointe": 26119, "prowess": 26120, "##ropriation": 26121, "lids": 26122, "scranton": 26123, "billings": 26124, "subcontinent": 26125, "##koff": 26126, "##scope": 26127, "brute": 26128, "kellogg": 26129, "psalms": 26130, "degraded": 26131, "##vez": 26132, "stanisław": 26133, "##ructured": 26134, "ferreira": 26135, "pun": 26136, "astonishing": 26137, "gunnar": 26138, "##yat": 26139, "arya": 26140, "prc": 26141, "gottfried": 26142, "##tight": 26143, "excursion": 26144, "##ographer": 26145, "dina": 26146, "##quil": 26147, "##nare": 26148, "huffington": 26149, "illustrious": 26150, "wilbur": 26151, "gundam": 26152, "verandah": 26153, "##zard": 26154, "naacp": 26155, "##odle": 26156, "constructive": 26157, "fjord": 26158, "kade": 26159, "##naud": 26160, "generosity": 26161, "thrilling": 26162, "baseline": 26163, "cayman": 26164, "frankish": 26165, "plastics": 26166, "accommodations": 26167, "zoological": 26168, "##fting": 26169, "cedric": 26170, "qb": 26171, "motorized": 26172, "##dome": 26173, "##otted": 26174, "squealed": 26175, "tackled": 26176, "canucks": 26177, "budgets": 26178, "situ": 26179, "asthma": 26180, "dail": 26181, "gabled": 26182, "grasslands": 26183, "whimpered": 26184, "writhing": 26185, "judgments": 26186, "##65": 26187, "minnie": 26188, "pv": 26189, "##carbon": 26190, "bananas": 26191, "grille": 26192, "domes": 26193, "monique": 26194, "odin": 26195, "maguire": 26196, "markham": 26197, "tierney": 26198, "##estra": 26199, "##chua": 26200, "libel": 26201, "poke": 26202, "speedy": 26203, "atrium": 26204, "laval": 26205, "notwithstanding": 26206, "##edly": 26207, "fai": 26208, "kala": 26209, "##sur": 26210, "robb": 26211, "##sma": 26212, "listings": 26213, "luz": 26214, "supplementary": 26215, "tianjin": 26216, "##acing": 26217, "enzo": 26218, "jd": 26219, "ric": 26220, "scanner": 26221, "croats": 26222, "transcribed": 26223, "##49": 26224, "arden": 26225, "cv": 26226, "##hair": 26227, "##raphy": 26228, "##lver": 26229, "##uy": 26230, "357": 26231, "seventies": 26232, "staggering": 26233, "alam": 26234, "horticultural": 26235, "hs": 26236, "regression": 26237, "timbers": 26238, "blasting": 26239, "##ounded": 26240, "montagu": 26241, "manipulating": 26242, "##cit": 26243, "catalytic": 26244, "1550": 26245, "troopers": 26246, "##meo": 26247, "condemnation": 26248, "fitzpatrick": 26249, "##oire": 26250, "##roved": 26251, "inexperienced": 26252, "1670": 26253, "castes": 26254, "##lative": 26255, "outing": 26256, "314": 26257, "dubois": 26258, "flicking": 26259, "quarrel": 26260, "ste": 26261, "learners": 26262, "1625": 26263, "iq": 26264, "whistled": 26265, "##class": 26266, "282": 26267, "classify": 26268, "tariffs": 26269, "temperament": 26270, "355": 26271, "folly": 26272, "liszt": 26273, "##yles": 26274, "immersed": 26275, "jordanian": 26276, "ceasefire": 26277, "apparel": 26278, "extras": 26279, "maru": 26280, "fished": 26281, "##bio": 26282, "harta": 26283, "stockport": 26284, "assortment": 26285, "craftsman": 26286, "paralysis": 26287, "transmitters": 26288, "##cola": 26289, "blindness": 26290, "##wk": 26291, "fatally": 26292, "proficiency": 26293, "solemnly": 26294, "##orno": 26295, "repairing": 26296, "amore": 26297, "groceries": 26298, "ultraviolet": 26299, "##chase": 26300, "schoolhouse": 26301, "##tua": 26302, "resurgence": 26303, "nailed": 26304, "##otype": 26305, "##×": 26306, "ruse": 26307, "saliva": 26308, "diagrams": 26309, "##tructing": 26310, "albans": 26311, "rann": 26312, "thirties": 26313, "1b": 26314, "antennas": 26315, "hilarious": 26316, "cougars": 26317, "paddington": 26318, "stats": 26319, "##eger": 26320, "breakaway": 26321, "ipod": 26322, "reza": 26323, "authorship": 26324, "prohibiting": 26325, "scoffed": 26326, "##etz": 26327, "##ttle": 26328, "conscription": 26329, "defected": 26330, "trondheim": 26331, "##fires": 26332, "ivanov": 26333, "keenan": 26334, "##adan": 26335, "##ciful": 26336, "##fb": 26337, "##slow": 26338, "locating": 26339, "##ials": 26340, "##tford": 26341, "cadiz": 26342, "basalt": 26343, "blankly": 26344, "interned": 26345, "rags": 26346, "rattling": 26347, "##tick": 26348, "carpathian": 26349, "reassured": 26350, "sync": 26351, "bum": 26352, "guildford": 26353, "iss": 26354, "staunch": 26355, "##onga": 26356, "astronomers": 26357, "sera": 26358, "sofie": 26359, "emergencies": 26360, "susquehanna": 26361, "##heard": 26362, "duc": 26363, "mastery": 26364, "vh1": 26365, "williamsburg": 26366, "bayer": 26367, "buckled": 26368, "craving": 26369, "##khan": 26370, "##rdes": 26371, "bloomington": 26372, "##write": 26373, "alton": 26374, "barbecue": 26375, "##bians": 26376, "justine": 26377, "##hri": 26378, "##ndt": 26379, "delightful": 26380, "smartphone": 26381, "newtown": 26382, "photon": 26383, "retrieval": 26384, "peugeot": 26385, "hissing": 26386, "##monium": 26387, "##orough": 26388, "flavors": 26389, "lighted": 26390, "relaunched": 26391, "tainted": 26392, "##games": 26393, "##lysis": 26394, "anarchy": 26395, "microscopic": 26396, "hopping": 26397, "adept": 26398, "evade": 26399, "evie": 26400, "##beau": 26401, "inhibit": 26402, "sinn": 26403, "adjustable": 26404, "hurst": 26405, "intuition": 26406, "wilton": 26407, "cisco": 26408, "44th": 26409, "lawful": 26410, "lowlands": 26411, "stockings": 26412, "thierry": 26413, "##dalen": 26414, "##hila": 26415, "##nai": 26416, "fates": 26417, "prank": 26418, "tb": 26419, "maison": 26420, "lobbied": 26421, "provocative": 26422, "1724": 26423, "4a": 26424, "utopia": 26425, "##qual": 26426, "carbonate": 26427, "gujarati": 26428, "purcell": 26429, "##rford": 26430, "curtiss": 26431, "##mei": 26432, "overgrown": 26433, "arenas": 26434, "mediation": 26435, "swallows": 26436, "##rnik": 26437, "respectful": 26438, "turnbull": 26439, "##hedron": 26440, "##hope": 26441, "alyssa": 26442, "ozone": 26443, "##ʻi": 26444, "ami": 26445, "gestapo": 26446, "johansson": 26447, "snooker": 26448, "canteen": 26449, "cuff": 26450, "declines": 26451, "empathy": 26452, "stigma": 26453, "##ags": 26454, "##iner": 26455, "##raine": 26456, "taxpayers": 26457, "gui": 26458, "volga": 26459, "##wright": 26460, "##copic": 26461, "lifespan": 26462, "overcame": 26463, "tattooed": 26464, "enactment": 26465, "giggles": 26466, "##ador": 26467, "##camp": 26468, "barrington": 26469, "bribe": 26470, "obligatory": 26471, "orbiting": 26472, "peng": 26473, "##enas": 26474, "elusive": 26475, "sucker": 26476, "##vating": 26477, "cong": 26478, "hardship": 26479, "empowered": 26480, "anticipating": 26481, "estrada": 26482, "cryptic": 26483, "greasy": 26484, "detainees": 26485, "planck": 26486, "sudbury": 26487, "plaid": 26488, "dod": 26489, "marriott": 26490, "kayla": 26491, "##ears": 26492, "##vb": 26493, "##zd": 26494, "mortally": 26495, "##hein": 26496, "cognition": 26497, "radha": 26498, "319": 26499, "liechtenstein": 26500, "meade": 26501, "richly": 26502, "argyle": 26503, "harpsichord": 26504, "liberalism": 26505, "trumpets": 26506, "lauded": 26507, "tyrant": 26508, "salsa": 26509, "tiled": 26510, "lear": 26511, "promoters": 26512, "reused": 26513, "slicing": 26514, "trident": 26515, "##chuk": 26516, "##gami": 26517, "##lka": 26518, "cantor": 26519, "checkpoint": 26520, "##points": 26521, "gaul": 26522, "leger": 26523, "mammalian": 26524, "##tov": 26525, "##aar": 26526, "##schaft": 26527, "doha": 26528, "frenchman": 26529, "nirvana": 26530, "##vino": 26531, "delgado": 26532, "headlining": 26533, "##eron": 26534, "##iography": 26535, "jug": 26536, "tko": 26537, "1649": 26538, "naga": 26539, "intersections": 26540, "##jia": 26541, "benfica": 26542, "nawab": 26543, "##suka": 26544, "ashford": 26545, "gulp": 26546, "##deck": 26547, "##vill": 26548, "##rug": 26549, "brentford": 26550, "frazier": 26551, "pleasures": 26552, "dunne": 26553, "potsdam": 26554, "shenzhen": 26555, "dentistry": 26556, "##tec": 26557, "flanagan": 26558, "##dorff": 26559, "##hear": 26560, "chorale": 26561, "dinah": 26562, "prem": 26563, "quezon": 26564, "##rogated": 26565, "relinquished": 26566, "sutra": 26567, "terri": 26568, "##pani": 26569, "flaps": 26570, "##rissa": 26571, "poly": 26572, "##rnet": 26573, "homme": 26574, "aback": 26575, "##eki": 26576, "linger": 26577, "womb": 26578, "##kson": 26579, "##lewood": 26580, "doorstep": 26581, "orthodoxy": 26582, "threaded": 26583, "westfield": 26584, "##rval": 26585, "dioceses": 26586, "fridays": 26587, "subsided": 26588, "##gata": 26589, "loyalists": 26590, "##biotic": 26591, "##ettes": 26592, "letterman": 26593, "lunatic": 26594, "prelate": 26595, "tenderly": 26596, "invariably": 26597, "souza": 26598, "thug": 26599, "winslow": 26600, "##otide": 26601, "furlongs": 26602, "gogh": 26603, "jeopardy": 26604, "##runa": 26605, "pegasus": 26606, "##umble": 26607, "humiliated": 26608, "standalone": 26609, "tagged": 26610, "##roller": 26611, "freshmen": 26612, "klan": 26613, "##bright": 26614, "attaining": 26615, "initiating": 26616, "transatlantic": 26617, "logged": 26618, "viz": 26619, "##uance": 26620, "1723": 26621, "combatants": 26622, "intervening": 26623, "stephane": 26624, "chieftain": 26625, "despised": 26626, "grazed": 26627, "317": 26628, "cdc": 26629, "galveston": 26630, "godzilla": 26631, "macro": 26632, "simulate": 26633, "##planes": 26634, "parades": 26635, "##esses": 26636, "960": 26637, "##ductive": 26638, "##unes": 26639, "equator": 26640, "overdose": 26641, "##cans": 26642, "##hosh": 26643, "##lifting": 26644, "joshi": 26645, "epstein": 26646, "sonora": 26647, "treacherous": 26648, "aquatics": 26649, "manchu": 26650, "responsive": 26651, "##sation": 26652, "supervisory": 26653, "##christ": 26654, "##llins": 26655, "##ibar": 26656, "##balance": 26657, "##uso": 26658, "kimball": 26659, "karlsruhe": 26660, "mab": 26661, "##emy": 26662, "ignores": 26663, "phonetic": 26664, "reuters": 26665, "spaghetti": 26666, "820": 26667, "almighty": 26668, "danzig": 26669, "rumbling": 26670, "tombstone": 26671, "designations": 26672, "lured": 26673, "outset": 26674, "##felt": 26675, "supermarkets": 26676, "##wt": 26677, "grupo": 26678, "kei": 26679, "kraft": 26680, "susanna": 26681, "##blood": 26682, "comprehension": 26683, "genealogy": 26684, "##aghan": 26685, "##verted": 26686, "redding": 26687, "##ythe": 26688, "1722": 26689, "bowing": 26690, "##pore": 26691, "##roi": 26692, "lest": 26693, "sharpened": 26694, "fulbright": 26695, "valkyrie": 26696, "sikhs": 26697, "##unds": 26698, "swans": 26699, "bouquet": 26700, "merritt": 26701, "##tage": 26702, "##venting": 26703, "commuted": 26704, "redhead": 26705, "clerks": 26706, "leasing": 26707, "cesare": 26708, "dea": 26709, "hazy": 26710, "##vances": 26711, "fledged": 26712, "greenfield": 26713, "servicemen": 26714, "##gical": 26715, "armando": 26716, "blackout": 26717, "dt": 26718, "sagged": 26719, "downloadable": 26720, "intra": 26721, "potion": 26722, "pods": 26723, "##4th": 26724, "##mism": 26725, "xp": 26726, "attendants": 26727, "gambia": 26728, "stale": 26729, "##ntine": 26730, "plump": 26731, "asteroids": 26732, "rediscovered": 26733, "buds": 26734, "flea": 26735, "hive": 26736, "##neas": 26737, "1737": 26738, "classifications": 26739, "debuts": 26740, "##eles": 26741, "olympus": 26742, "scala": 26743, "##eurs": 26744, "##gno": 26745, "##mute": 26746, "hummed": 26747, "sigismund": 26748, "visuals": 26749, "wiggled": 26750, "await": 26751, "pilasters": 26752, "clench": 26753, "sulfate": 26754, "##ances": 26755, "bellevue": 26756, "enigma": 26757, "trainee": 26758, "snort": 26759, "##sw": 26760, "clouded": 26761, "denim": 26762, "##rank": 26763, "##rder": 26764, "churning": 26765, "hartman": 26766, "lodges": 26767, "riches": 26768, "sima": 26769, "##missible": 26770, "accountable": 26771, "socrates": 26772, "regulates": 26773, "mueller": 26774, "##cr": 26775, "1702": 26776, "avoids": 26777, "solids": 26778, "himalayas": 26779, "nutrient": 26780, "pup": 26781, "##jevic": 26782, "squat": 26783, "fades": 26784, "nec": 26785, "##lates": 26786, "##pina": 26787, "##rona": 26788, "##ου": 26789, "privateer": 26790, "tequila": 26791, "##gative": 26792, "##mpton": 26793, "apt": 26794, "hornet": 26795, "immortals": 26796, "##dou": 26797, "asturias": 26798, "cleansing": 26799, "dario": 26800, "##rries": 26801, "##anta": 26802, "etymology": 26803, "servicing": 26804, "zhejiang": 26805, "##venor": 26806, "##nx": 26807, "horned": 26808, "erasmus": 26809, "rayon": 26810, "relocating": 26811, "£10": 26812, "##bags": 26813, "escalated": 26814, "promenade": 26815, "stubble": 26816, "2010s": 26817, "artisans": 26818, "axial": 26819, "liquids": 26820, "mora": 26821, "sho": 26822, "yoo": 26823, "##tsky": 26824, "bundles": 26825, "oldies": 26826, "##nally": 26827, "notification": 26828, "bastion": 26829, "##ths": 26830, "sparkle": 26831, "##lved": 26832, "1728": 26833, "leash": 26834, "pathogen": 26835, "highs": 26836, "##hmi": 26837, "immature": 26838, "880": 26839, "gonzaga": 26840, "ignatius": 26841, "mansions": 26842, "monterrey": 26843, "sweets": 26844, "bryson": 26845, "##loe": 26846, "polled": 26847, "regatta": 26848, "brightest": 26849, "pei": 26850, "rosy": 26851, "squid": 26852, "hatfield": 26853, "payroll": 26854, "addict": 26855, "meath": 26856, "cornerback": 26857, "heaviest": 26858, "lodging": 26859, "##mage": 26860, "capcom": 26861, "rippled": 26862, "##sily": 26863, "barnet": 26864, "mayhem": 26865, "ymca": 26866, "snuggled": 26867, "rousseau": 26868, "##cute": 26869, "blanchard": 26870, "284": 26871, "fragmented": 26872, "leighton": 26873, "chromosomes": 26874, "risking": 26875, "##md": 26876, "##strel": 26877, "##utter": 26878, "corinne": 26879, "coyotes": 26880, "cynical": 26881, "hiroshi": 26882, "yeomanry": 26883, "##ractive": 26884, "ebook": 26885, "grading": 26886, "mandela": 26887, "plume": 26888, "agustin": 26889, "magdalene": 26890, "##rkin": 26891, "bea": 26892, "femme": 26893, "trafford": 26894, "##coll": 26895, "##lun": 26896, "##tance": 26897, "52nd": 26898, "fourier": 26899, "upton": 26900, "##mental": 26901, "camilla": 26902, "gust": 26903, "iihf": 26904, "islamabad": 26905, "longevity": 26906, "##kala": 26907, "feldman": 26908, "netting": 26909, "##rization": 26910, "endeavour": 26911, "foraging": 26912, "mfa": 26913, "orr": 26914, "##open": 26915, "greyish": 26916, "contradiction": 26917, "graz": 26918, "##ruff": 26919, "handicapped": 26920, "marlene": 26921, "tweed": 26922, "oaxaca": 26923, "spp": 26924, "campos": 26925, "miocene": 26926, "pri": 26927, "configured": 26928, "cooks": 26929, "pluto": 26930, "cozy": 26931, "pornographic": 26932, "##entes": 26933, "70th": 26934, "fairness": 26935, "glided": 26936, "jonny": 26937, "lynne": 26938, "rounding": 26939, "sired": 26940, "##emon": 26941, "##nist": 26942, "remade": 26943, "uncover": 26944, "##mack": 26945, "complied": 26946, "lei": 26947, "newsweek": 26948, "##jured": 26949, "##parts": 26950, "##enting": 26951, "##pg": 26952, "293": 26953, "finer": 26954, "guerrillas": 26955, "athenian": 26956, "deng": 26957, "disused": 26958, "stepmother": 26959, "accuse": 26960, "gingerly": 26961, "seduction": 26962, "521": 26963, "confronting": 26964, "##walker": 26965, "##going": 26966, "gora": 26967, "nostalgia": 26968, "sabres": 26969, "virginity": 26970, "wrenched": 26971, "##minated": 26972, "syndication": 26973, "wielding": 26974, "eyre": 26975, "##56": 26976, "##gnon": 26977, "##igny": 26978, "behaved": 26979, "taxpayer": 26980, "sweeps": 26981, "##growth": 26982, "childless": 26983, "gallant": 26984, "##ywood": 26985, "amplified": 26986, "geraldine": 26987, "scrape": 26988, "##ffi": 26989, "babylonian": 26990, "fresco": 26991, "##rdan": 26992, "##kney": 26993, "##position": 26994, "1718": 26995, "restricting": 26996, "tack": 26997, "fukuoka": 26998, "osborn": 26999, "selector": 27000, "partnering": 27001, "##dlow": 27002, "318": 27003, "gnu": 27004, "kia": 27005, "tak": 27006, "whitley": 27007, "gables": 27008, "##54": 27009, "##mania": 27010, "mri": 27011, "softness": 27012, "immersion": 27013, "##bots": 27014, "##evsky": 27015, "1713": 27016, "chilling": 27017, "insignificant": 27018, "pcs": 27019, "##uis": 27020, "elites": 27021, "lina": 27022, "purported": 27023, "supplemental": 27024, "teaming": 27025, "##americana": 27026, "##dding": 27027, "##inton": 27028, "proficient": 27029, "rouen": 27030, "##nage": 27031, "##rret": 27032, "niccolo": 27033, "selects": 27034, "##bread": 27035, "fluffy": 27036, "1621": 27037, "gruff": 27038, "knotted": 27039, "mukherjee": 27040, "polgara": 27041, "thrash": 27042, "nicholls": 27043, "secluded": 27044, "smoothing": 27045, "thru": 27046, "corsica": 27047, "loaf": 27048, "whitaker": 27049, "inquiries": 27050, "##rrier": 27051, "##kam": 27052, "indochina": 27053, "289": 27054, "marlins": 27055, "myles": 27056, "peking": 27057, "##tea": 27058, "extracts": 27059, "pastry": 27060, "superhuman": 27061, "connacht": 27062, "vogel": 27063, "##ditional": 27064, "##het": 27065, "##udged": 27066, "##lash": 27067, "gloss": 27068, "quarries": 27069, "refit": 27070, "teaser": 27071, "##alic": 27072, "##gaon": 27073, "20s": 27074, "materialized": 27075, "sling": 27076, "camped": 27077, "pickering": 27078, "tung": 27079, "tracker": 27080, "pursuant": 27081, "##cide": 27082, "cranes": 27083, "soc": 27084, "##cini": 27085, "##typical": 27086, "##viere": 27087, "anhalt": 27088, "overboard": 27089, "workout": 27090, "chores": 27091, "fares": 27092, "orphaned": 27093, "stains": 27094, "##logie": 27095, "fenton": 27096, "surpassing": 27097, "joyah": 27098, "triggers": 27099, "##itte": 27100, "grandmaster": 27101, "##lass": 27102, "##lists": 27103, "clapping": 27104, "fraudulent": 27105, "ledger": 27106, "nagasaki": 27107, "##cor": 27108, "##nosis": 27109, "##tsa": 27110, "eucalyptus": 27111, "tun": 27112, "##icio": 27113, "##rney": 27114, "##tara": 27115, "dax": 27116, "heroism": 27117, "ina": 27118, "wrexham": 27119, "onboard": 27120, "unsigned": 27121, "##dates": 27122, "moshe": 27123, "galley": 27124, "winnie": 27125, "droplets": 27126, "exiles": 27127, "praises": 27128, "watered": 27129, "noodles": 27130, "##aia": 27131, "fein": 27132, "adi": 27133, "leland": 27134, "multicultural": 27135, "stink": 27136, "bingo": 27137, "comets": 27138, "erskine": 27139, "modernized": 27140, "canned": 27141, "constraint": 27142, "domestically": 27143, "chemotherapy": 27144, "featherweight": 27145, "stifled": 27146, "##mum": 27147, "darkly": 27148, "irresistible": 27149, "refreshing": 27150, "hasty": 27151, "isolate": 27152, "##oys": 27153, "kitchener": 27154, "planners": 27155, "##wehr": 27156, "cages": 27157, "yarn": 27158, "implant": 27159, "toulon": 27160, "elects": 27161, "childbirth": 27162, "yue": 27163, "##lind": 27164, "##lone": 27165, "cn": 27166, "rightful": 27167, "sportsman": 27168, "junctions": 27169, "remodeled": 27170, "specifies": 27171, "##rgh": 27172, "291": 27173, "##oons": 27174, "complimented": 27175, "##urgent": 27176, "lister": 27177, "ot": 27178, "##logic": 27179, "bequeathed": 27180, "cheekbones": 27181, "fontana": 27182, "gabby": 27183, "##dial": 27184, "amadeus": 27185, "corrugated": 27186, "maverick": 27187, "resented": 27188, "triangles": 27189, "##hered": 27190, "##usly": 27191, "nazareth": 27192, "tyrol": 27193, "1675": 27194, "assent": 27195, "poorer": 27196, "sectional": 27197, "aegean": 27198, "##cous": 27199, "296": 27200, "nylon": 27201, "ghanaian": 27202, "##egorical": 27203, "##weig": 27204, "cushions": 27205, "forbid": 27206, "fusiliers": 27207, "obstruction": 27208, "somerville": 27209, "##scia": 27210, "dime": 27211, "earrings": 27212, "elliptical": 27213, "leyte": 27214, "oder": 27215, "polymers": 27216, "timmy": 27217, "atm": 27218, "midtown": 27219, "piloted": 27220, "settles": 27221, "continual": 27222, "externally": 27223, "mayfield": 27224, "##uh": 27225, "enrichment": 27226, "henson": 27227, "keane": 27228, "persians": 27229, "1733": 27230, "benji": 27231, "braden": 27232, "pep": 27233, "324": 27234, "##efe": 27235, "contenders": 27236, "pepsi": 27237, "valet": 27238, "##isches": 27239, "298": 27240, "##asse": 27241, "##earing": 27242, "goofy": 27243, "stroll": 27244, "##amen": 27245, "authoritarian": 27246, "occurrences": 27247, "adversary": 27248, "ahmedabad": 27249, "tangent": 27250, "toppled": 27251, "dorchester": 27252, "1672": 27253, "modernism": 27254, "marxism": 27255, "islamist": 27256, "charlemagne": 27257, "exponential": 27258, "racks": 27259, "unicode": 27260, "brunette": 27261, "mbc": 27262, "pic": 27263, "skirmish": 27264, "##bund": 27265, "##lad": 27266, "##powered": 27267, "##yst": 27268, "hoisted": 27269, "messina": 27270, "shatter": 27271, "##ctum": 27272, "jedi": 27273, "vantage": 27274, "##music": 27275, "##neil": 27276, "clemens": 27277, "mahmoud": 27278, "corrupted": 27279, "authentication": 27280, "lowry": 27281, "nils": 27282, "##washed": 27283, "omnibus": 27284, "wounding": 27285, "jillian": 27286, "##itors": 27287, "##opped": 27288, "serialized": 27289, "narcotics": 27290, "handheld": 27291, "##arm": 27292, "##plicity": 27293, "intersecting": 27294, "stimulating": 27295, "##onis": 27296, "crate": 27297, "fellowships": 27298, "hemingway": 27299, "casinos": 27300, "climatic": 27301, "fordham": 27302, "copeland": 27303, "drip": 27304, "beatty": 27305, "leaflets": 27306, "robber": 27307, "brothel": 27308, "madeira": 27309, "##hedral": 27310, "sphinx": 27311, "ultrasound": 27312, "##vana": 27313, "valor": 27314, "forbade": 27315, "leonid": 27316, "villas": 27317, "##aldo": 27318, "duane": 27319, "marquez": 27320, "##cytes": 27321, "disadvantaged": 27322, "forearms": 27323, "kawasaki": 27324, "reacts": 27325, "consular": 27326, "lax": 27327, "uncles": 27328, "uphold": 27329, "##hopper": 27330, "concepcion": 27331, "dorsey": 27332, "lass": 27333, "##izan": 27334, "arching": 27335, "passageway": 27336, "1708": 27337, "researches": 27338, "tia": 27339, "internationals": 27340, "##graphs": 27341, "##opers": 27342, "distinguishes": 27343, "javanese": 27344, "divert": 27345, "##uven": 27346, "plotted": 27347, "##listic": 27348, "##rwin": 27349, "##erik": 27350, "##tify": 27351, "affirmative": 27352, "signifies": 27353, "validation": 27354, "##bson": 27355, "kari": 27356, "felicity": 27357, "georgina": 27358, "zulu": 27359, "##eros": 27360, "##rained": 27361, "##rath": 27362, "overcoming": 27363, "##dot": 27364, "argyll": 27365, "##rbin": 27366, "1734": 27367, "chiba": 27368, "ratification": 27369, "windy": 27370, "earls": 27371, "parapet": 27372, "##marks": 27373, "hunan": 27374, "pristine": 27375, "astrid": 27376, "punta": 27377, "##gart": 27378, "brodie": 27379, "##kota": 27380, "##oder": 27381, "malaga": 27382, "minerva": 27383, "rouse": 27384, "##phonic": 27385, "bellowed": 27386, "pagoda": 27387, "portals": 27388, "reclamation": 27389, "##gur": 27390, "##odies": 27391, "##⁄₄": 27392, "parentheses": 27393, "quoting": 27394, "allergic": 27395, "palette": 27396, "showcases": 27397, "benefactor": 27398, "heartland": 27399, "nonlinear": 27400, "##tness": 27401, "bladed": 27402, "cheerfully": 27403, "scans": 27404, "##ety": 27405, "##hone": 27406, "1666": 27407, "girlfriends": 27408, "pedersen": 27409, "hiram": 27410, "sous": 27411, "##liche": 27412, "##nator": 27413, "1683": 27414, "##nery": 27415, "##orio": 27416, "##umen": 27417, "bobo": 27418, "primaries": 27419, "smiley": 27420, "##cb": 27421, "unearthed": 27422, "uniformly": 27423, "fis": 27424, "metadata": 27425, "1635": 27426, "ind": 27427, "##oted": 27428, "recoil": 27429, "##titles": 27430, "##tura": 27431, "##ια": 27432, "406": 27433, "hilbert": 27434, "jamestown": 27435, "mcmillan": 27436, "tulane": 27437, "seychelles": 27438, "##frid": 27439, "antics": 27440, "coli": 27441, "fated": 27442, "stucco": 27443, "##grants": 27444, "1654": 27445, "bulky": 27446, "accolades": 27447, "arrays": 27448, "caledonian": 27449, "carnage": 27450, "optimism": 27451, "puebla": 27452, "##tative": 27453, "##cave": 27454, "enforcing": 27455, "rotherham": 27456, "seo": 27457, "dunlop": 27458, "aeronautics": 27459, "chimed": 27460, "incline": 27461, "zoning": 27462, "archduke": 27463, "hellenistic": 27464, "##oses": 27465, "##sions": 27466, "candi": 27467, "thong": 27468, "##ople": 27469, "magnate": 27470, "rustic": 27471, "##rsk": 27472, "projective": 27473, "slant": 27474, "##offs": 27475, "danes": 27476, "hollis": 27477, "vocalists": 27478, "##ammed": 27479, "congenital": 27480, "contend": 27481, "gesellschaft": 27482, "##ocating": 27483, "##pressive": 27484, "douglass": 27485, "quieter": 27486, "##cm": 27487, "##kshi": 27488, "howled": 27489, "salim": 27490, "spontaneously": 27491, "townsville": 27492, "buena": 27493, "southport": 27494, "##bold": 27495, "kato": 27496, "1638": 27497, "faerie": 27498, "stiffly": 27499, "##vus": 27500, "##rled": 27501, "297": 27502, "flawless": 27503, "realising": 27504, "taboo": 27505, "##7th": 27506, "bytes": 27507, "straightening": 27508, "356": 27509, "jena": 27510, "##hid": 27511, "##rmin": 27512, "cartwright": 27513, "berber": 27514, "bertram": 27515, "soloists": 27516, "411": 27517, "noses": 27518, "417": 27519, "coping": 27520, "fission": 27521, "hardin": 27522, "inca": 27523, "##cen": 27524, "1717": 27525, "mobilized": 27526, "vhf": 27527, "##raf": 27528, "biscuits": 27529, "curate": 27530, "##85": 27531, "##anial": 27532, "331": 27533, "gaunt": 27534, "neighbourhoods": 27535, "1540": 27536, "##abas": 27537, "blanca": 27538, "bypassed": 27539, "sockets": 27540, "behold": 27541, "coincidentally": 27542, "##bane": 27543, "nara": 27544, "shave": 27545, "splinter": 27546, "terrific": 27547, "##arion": 27548, "##erian": 27549, "commonplace": 27550, "juris": 27551, "redwood": 27552, "waistband": 27553, "boxed": 27554, "caitlin": 27555, "fingerprints": 27556, "jennie": 27557, "naturalized": 27558, "##ired": 27559, "balfour": 27560, "craters": 27561, "jody": 27562, "bungalow": 27563, "hugely": 27564, "quilt": 27565, "glitter": 27566, "pigeons": 27567, "undertaker": 27568, "bulging": 27569, "constrained": 27570, "goo": 27571, "##sil": 27572, "##akh": 27573, "assimilation": 27574, "reworked": 27575, "##person": 27576, "persuasion": 27577, "##pants": 27578, "felicia": 27579, "##cliff": 27580, "##ulent": 27581, "1732": 27582, "explodes": 27583, "##dun": 27584, "##inium": 27585, "##zic": 27586, "lyman": 27587, "vulture": 27588, "hog": 27589, "overlook": 27590, "begs": 27591, "northwards": 27592, "ow": 27593, "spoil": 27594, "##urer": 27595, "fatima": 27596, "favorably": 27597, "accumulate": 27598, "sargent": 27599, "sorority": 27600, "corresponded": 27601, "dispersal": 27602, "kochi": 27603, "toned": 27604, "##imi": 27605, "##lita": 27606, "internacional": 27607, "newfound": 27608, "##agger": 27609, "##lynn": 27610, "##rigue": 27611, "booths": 27612, "peanuts": 27613, "##eborg": 27614, "medicare": 27615, "muriel": 27616, "nur": 27617, "##uram": 27618, "crates": 27619, "millennia": 27620, "pajamas": 27621, "worsened": 27622, "##breakers": 27623, "jimi": 27624, "vanuatu": 27625, "yawned": 27626, "##udeau": 27627, "carousel": 27628, "##hony": 27629, "hurdle": 27630, "##ccus": 27631, "##mounted": 27632, "##pod": 27633, "rv": 27634, "##eche": 27635, "airship": 27636, "ambiguity": 27637, "compulsion": 27638, "recapture": 27639, "##claiming": 27640, "arthritis": 27641, "##osomal": 27642, "1667": 27643, "asserting": 27644, "ngc": 27645, "sniffing": 27646, "dade": 27647, "discontent": 27648, "glendale": 27649, "ported": 27650, "##amina": 27651, "defamation": 27652, "rammed": 27653, "##scent": 27654, "fling": 27655, "livingstone": 27656, "##fleet": 27657, "875": 27658, "##ppy": 27659, "apocalyptic": 27660, "comrade": 27661, "lcd": 27662, "##lowe": 27663, "cessna": 27664, "eine": 27665, "persecuted": 27666, "subsistence": 27667, "demi": 27668, "hoop": 27669, "reliefs": 27670, "710": 27671, "coptic": 27672, "progressing": 27673, "stemmed": 27674, "perpetrators": 27675, "1665": 27676, "priestess": 27677, "##nio": 27678, "dobson": 27679, "ebony": 27680, "rooster": 27681, "itf": 27682, "tortricidae": 27683, "##bbon": 27684, "##jian": 27685, "cleanup": 27686, "##jean": 27687, "##øy": 27688, "1721": 27689, "eighties": 27690, "taxonomic": 27691, "holiness": 27692, "##hearted": 27693, "##spar": 27694, "antilles": 27695, "showcasing": 27696, "stabilized": 27697, "##nb": 27698, "gia": 27699, "mascara": 27700, "michelangelo": 27701, "dawned": 27702, "##uria": 27703, "##vinsky": 27704, "extinguished": 27705, "fitz": 27706, "grotesque": 27707, "£100": 27708, "##fera": 27709, "##loid": 27710, "##mous": 27711, "barges": 27712, "neue": 27713, "throbbed": 27714, "cipher": 27715, "johnnie": 27716, "##a1": 27717, "##mpt": 27718, "outburst": 27719, "##swick": 27720, "spearheaded": 27721, "administrations": 27722, "c1": 27723, "heartbreak": 27724, "pixels": 27725, "pleasantly": 27726, "##enay": 27727, "lombardy": 27728, "plush": 27729, "##nsed": 27730, "bobbie": 27731, "##hly": 27732, "reapers": 27733, "tremor": 27734, "xiang": 27735, "minogue": 27736, "substantive": 27737, "hitch": 27738, "barak": 27739, "##wyl": 27740, "kwan": 27741, "##encia": 27742, "910": 27743, "obscene": 27744, "elegance": 27745, "indus": 27746, "surfer": 27747, "bribery": 27748, "conserve": 27749, "##hyllum": 27750, "##masters": 27751, "horatio": 27752, "##fat": 27753, "apes": 27754, "rebound": 27755, "psychotic": 27756, "##pour": 27757, "iteration": 27758, "##mium": 27759, "##vani": 27760, "botanic": 27761, "horribly": 27762, "antiques": 27763, "dispose": 27764, "paxton": 27765, "##hli": 27766, "##wg": 27767, "timeless": 27768, "1704": 27769, "disregard": 27770, "engraver": 27771, "hounds": 27772, "##bau": 27773, "##version": 27774, "looted": 27775, "uno": 27776, "facilitates": 27777, "groans": 27778, "masjid": 27779, "rutland": 27780, "antibody": 27781, "disqualification": 27782, "decatur": 27783, "footballers": 27784, "quake": 27785, "slacks": 27786, "48th": 27787, "rein": 27788, "scribe": 27789, "stabilize": 27790, "commits": 27791, "exemplary": 27792, "tho": 27793, "##hort": 27794, "##chison": 27795, "pantry": 27796, "traversed": 27797, "##hiti": 27798, "disrepair": 27799, "identifiable": 27800, "vibrated": 27801, "baccalaureate": 27802, "##nnis": 27803, "csa": 27804, "interviewing": 27805, "##iensis": 27806, "##raße": 27807, "greaves": 27808, "wealthiest": 27809, "343": 27810, "classed": 27811, "jogged": 27812, "£5": 27813, "##58": 27814, "##atal": 27815, "illuminating": 27816, "knicks": 27817, "respecting": 27818, "##uno": 27819, "scrubbed": 27820, "##iji": 27821, "##dles": 27822, "kruger": 27823, "moods": 27824, "growls": 27825, "raider": 27826, "silvia": 27827, "chefs": 27828, "kam": 27829, "vr": 27830, "cree": 27831, "percival": 27832, "##terol": 27833, "gunter": 27834, "counterattack": 27835, "defiant": 27836, "henan": 27837, "ze": 27838, "##rasia": 27839, "##riety": 27840, "equivalence": 27841, "submissions": 27842, "##fra": 27843, "##thor": 27844, "bautista": 27845, "mechanically": 27846, "##heater": 27847, "cornice": 27848, "herbal": 27849, "templar": 27850, "##mering": 27851, "outputs": 27852, "ruining": 27853, "ligand": 27854, "renumbered": 27855, "extravagant": 27856, "mika": 27857, "blockbuster": 27858, "eta": 27859, "insurrection": 27860, "##ilia": 27861, "darkening": 27862, "ferocious": 27863, "pianos": 27864, "strife": 27865, "kinship": 27866, "##aer": 27867, "melee": 27868, "##anor": 27869, "##iste": 27870, "##may": 27871, "##oue": 27872, "decidedly": 27873, "weep": 27874, "##jad": 27875, "##missive": 27876, "##ppel": 27877, "354": 27878, "puget": 27879, "unease": 27880, "##gnant": 27881, "1629": 27882, "hammering": 27883, "kassel": 27884, "ob": 27885, "wessex": 27886, "##lga": 27887, "bromwich": 27888, "egan": 27889, "paranoia": 27890, "utilization": 27891, "##atable": 27892, "##idad": 27893, "contradictory": 27894, "provoke": 27895, "##ols": 27896, "##ouring": 27897, "##tangled": 27898, "knesset": 27899, "##very": 27900, "##lette": 27901, "plumbing": 27902, "##sden": 27903, "##¹": 27904, "greensboro": 27905, "occult": 27906, "sniff": 27907, "338": 27908, "zev": 27909, "beaming": 27910, "gamer": 27911, "haggard": 27912, "mahal": 27913, "##olt": 27914, "##pins": 27915, "mendes": 27916, "utmost": 27917, "briefing": 27918, "gunnery": 27919, "##gut": 27920, "##pher": 27921, "##zh": 27922, "##rok": 27923, "1679": 27924, "khalifa": 27925, "sonya": 27926, "##boot": 27927, "principals": 27928, "urbana": 27929, "wiring": 27930, "##liffe": 27931, "##minating": 27932, "##rrado": 27933, "dahl": 27934, "nyu": 27935, "skepticism": 27936, "np": 27937, "townspeople": 27938, "ithaca": 27939, "lobster": 27940, "somethin": 27941, "##fur": 27942, "##arina": 27943, "##−1": 27944, "freighter": 27945, "zimmerman": 27946, "biceps": 27947, "contractual": 27948, "##herton": 27949, "amend": 27950, "hurrying": 27951, "subconscious": 27952, "##anal": 27953, "336": 27954, "meng": 27955, "clermont": 27956, "spawning": 27957, "##eia": 27958, "##lub": 27959, "dignitaries": 27960, "impetus": 27961, "snacks": 27962, "spotting": 27963, "twigs": 27964, "##bilis": 27965, "##cz": 27966, "##ouk": 27967, "libertadores": 27968, "nic": 27969, "skylar": 27970, "##aina": 27971, "##firm": 27972, "gustave": 27973, "asean": 27974, "##anum": 27975, "dieter": 27976, "legislatures": 27977, "flirt": 27978, "bromley": 27979, "trolls": 27980, "umar": 27981, "##bbies": 27982, "##tyle": 27983, "blah": 27984, "parc": 27985, "bridgeport": 27986, "crank": 27987, "negligence": 27988, "##nction": 27989, "46th": 27990, "constantin": 27991, "molded": 27992, "bandages": 27993, "seriousness": 27994, "00pm": 27995, "siegel": 27996, "carpets": 27997, "compartments": 27998, "upbeat": 27999, "statehood": 28000, "##dner": 28001, "##edging": 28002, "marko": 28003, "730": 28004, "platt": 28005, "##hane": 28006, "paving": 28007, "##iy": 28008, "1738": 28009, "abbess": 28010, "impatience": 28011, "limousine": 28012, "nbl": 28013, "##talk": 28014, "441": 28015, "lucille": 28016, "mojo": 28017, "nightfall": 28018, "robbers": 28019, "##nais": 28020, "karel": 28021, "brisk": 28022, "calves": 28023, "replicate": 28024, "ascribed": 28025, "telescopes": 28026, "##olf": 28027, "intimidated": 28028, "##reen": 28029, "ballast": 28030, "specialization": 28031, "##sit": 28032, "aerodynamic": 28033, "caliphate": 28034, "rainer": 28035, "visionary": 28036, "##arded": 28037, "epsilon": 28038, "##aday": 28039, "##onte": 28040, "aggregation": 28041, "auditory": 28042, "boosted": 28043, "reunification": 28044, "kathmandu": 28045, "loco": 28046, "robyn": 28047, "402": 28048, "acknowledges": 28049, "appointing": 28050, "humanoid": 28051, "newell": 28052, "redeveloped": 28053, "restraints": 28054, "##tained": 28055, "barbarians": 28056, "chopper": 28057, "1609": 28058, "italiana": 28059, "##lez": 28060, "##lho": 28061, "investigates": 28062, "wrestlemania": 28063, "##anies": 28064, "##bib": 28065, "690": 28066, "##falls": 28067, "creaked": 28068, "dragoons": 28069, "gravely": 28070, "minions": 28071, "stupidity": 28072, "volley": 28073, "##harat": 28074, "##week": 28075, "musik": 28076, "##eries": 28077, "##uously": 28078, "fungal": 28079, "massimo": 28080, "semantics": 28081, "malvern": 28082, "##ahl": 28083, "##pee": 28084, "discourage": 28085, "embryo": 28086, "imperialism": 28087, "1910s": 28088, "profoundly": 28089, "##ddled": 28090, "jiangsu": 28091, "sparkled": 28092, "stat": 28093, "##holz": 28094, "sweatshirt": 28095, "tobin": 28096, "##iction": 28097, "sneered": 28098, "##cheon": 28099, "##oit": 28100, "brit": 28101, "causal": 28102, "smyth": 28103, "##neuve": 28104, "diffuse": 28105, "perrin": 28106, "silvio": 28107, "##ipes": 28108, "##recht": 28109, "detonated": 28110, "iqbal": 28111, "selma": 28112, "##nism": 28113, "##zumi": 28114, "roasted": 28115, "##riders": 28116, "tay": 28117, "##ados": 28118, "##mament": 28119, "##mut": 28120, "##rud": 28121, "840": 28122, "completes": 28123, "nipples": 28124, "cfa": 28125, "flavour": 28126, "hirsch": 28127, "##laus": 28128, "calderon": 28129, "sneakers": 28130, "moravian": 28131, "##ksha": 28132, "1622": 28133, "rq": 28134, "294": 28135, "##imeters": 28136, "bodo": 28137, "##isance": 28138, "##pre": 28139, "##ronia": 28140, "anatomical": 28141, "excerpt": 28142, "##lke": 28143, "dh": 28144, "kunst": 28145, "##tablished": 28146, "##scoe": 28147, "biomass": 28148, "panted": 28149, "unharmed": 28150, "gael": 28151, "housemates": 28152, "montpellier": 28153, "##59": 28154, "coa": 28155, "rodents": 28156, "tonic": 28157, "hickory": 28158, "singleton": 28159, "##taro": 28160, "451": 28161, "1719": 28162, "aldo": 28163, "breaststroke": 28164, "dempsey": 28165, "och": 28166, "rocco": 28167, "##cuit": 28168, "merton": 28169, "dissemination": 28170, "midsummer": 28171, "serials": 28172, "##idi": 28173, "haji": 28174, "polynomials": 28175, "##rdon": 28176, "gs": 28177, "enoch": 28178, "prematurely": 28179, "shutter": 28180, "taunton": 28181, "£3": 28182, "##grating": 28183, "##inates": 28184, "archangel": 28185, "harassed": 28186, "##asco": 28187, "326": 28188, "archway": 28189, "dazzling": 28190, "##ecin": 28191, "1736": 28192, "sumo": 28193, "wat": 28194, "##kovich": 28195, "1086": 28196, "honneur": 28197, "##ently": 28198, "##nostic": 28199, "##ttal": 28200, "##idon": 28201, "1605": 28202, "403": 28203, "1716": 28204, "blogger": 28205, "rents": 28206, "##gnan": 28207, "hires": 28208, "##ikh": 28209, "##dant": 28210, "howie": 28211, "##rons": 28212, "handler": 28213, "retracted": 28214, "shocks": 28215, "1632": 28216, "arun": 28217, "duluth": 28218, "kepler": 28219, "trumpeter": 28220, "##lary": 28221, "peeking": 28222, "seasoned": 28223, "trooper": 28224, "##mara": 28225, "laszlo": 28226, "##iciencies": 28227, "##rti": 28228, "heterosexual": 28229, "##inatory": 28230, "##ssion": 28231, "indira": 28232, "jogging": 28233, "##inga": 28234, "##lism": 28235, "beit": 28236, "dissatisfaction": 28237, "malice": 28238, "##ately": 28239, "nedra": 28240, "peeling": 28241, "##rgeon": 28242, "47th": 28243, "stadiums": 28244, "475": 28245, "vertigo": 28246, "##ains": 28247, "iced": 28248, "restroom": 28249, "##plify": 28250, "##tub": 28251, "illustrating": 28252, "pear": 28253, "##chner": 28254, "##sibility": 28255, "inorganic": 28256, "rappers": 28257, "receipts": 28258, "watery": 28259, "##kura": 28260, "lucinda": 28261, "##oulos": 28262, "reintroduced": 28263, "##8th": 28264, "##tched": 28265, "gracefully": 28266, "saxons": 28267, "nutritional": 28268, "wastewater": 28269, "rained": 28270, "favourites": 28271, "bedrock": 28272, "fisted": 28273, "hallways": 28274, "likeness": 28275, "upscale": 28276, "##lateral": 28277, "1580": 28278, "blinds": 28279, "prequel": 28280, "##pps": 28281, "##tama": 28282, "deter": 28283, "humiliating": 28284, "restraining": 28285, "tn": 28286, "vents": 28287, "1659": 28288, "laundering": 28289, "recess": 28290, "rosary": 28291, "tractors": 28292, "coulter": 28293, "federer": 28294, "##ifiers": 28295, "##plin": 28296, "persistence": 28297, "##quitable": 28298, "geschichte": 28299, "pendulum": 28300, "quakers": 28301, "##beam": 28302, "bassett": 28303, "pictorial": 28304, "buffet": 28305, "koln": 28306, "##sitor": 28307, "drills": 28308, "reciprocal": 28309, "shooters": 28310, "##57": 28311, "##cton": 28312, "##tees": 28313, "converge": 28314, "pip": 28315, "dmitri": 28316, "donnelly": 28317, "yamamoto": 28318, "aqua": 28319, "azores": 28320, "demographics": 28321, "hypnotic": 28322, "spitfire": 28323, "suspend": 28324, "wryly": 28325, "roderick": 28326, "##rran": 28327, "sebastien": 28328, "##asurable": 28329, "mavericks": 28330, "##fles": 28331, "##200": 28332, "himalayan": 28333, "prodigy": 28334, "##iance": 28335, "transvaal": 28336, "demonstrators": 28337, "handcuffs": 28338, "dodged": 28339, "mcnamara": 28340, "sublime": 28341, "1726": 28342, "crazed": 28343, "##efined": 28344, "##till": 28345, "ivo": 28346, "pondered": 28347, "reconciled": 28348, "shrill": 28349, "sava": 28350, "##duk": 28351, "bal": 28352, "cad": 28353, "heresy": 28354, "jaipur": 28355, "goran": 28356, "##nished": 28357, "341": 28358, "lux": 28359, "shelly": 28360, "whitehall": 28361, "##hre": 28362, "israelis": 28363, "peacekeeping": 28364, "##wled": 28365, "1703": 28366, "demetrius": 28367, "ousted": 28368, "##arians": 28369, "##zos": 28370, "beale": 28371, "anwar": 28372, "backstroke": 28373, "raged": 28374, "shrinking": 28375, "cremated": 28376, "##yck": 28377, "benign": 28378, "towing": 28379, "wadi": 28380, "darmstadt": 28381, "landfill": 28382, "parana": 28383, "soothe": 28384, "colleen": 28385, "sidewalks": 28386, "mayfair": 28387, "tumble": 28388, "hepatitis": 28389, "ferrer": 28390, "superstructure": 28391, "##gingly": 28392, "##urse": 28393, "##wee": 28394, "anthropological": 28395, "translators": 28396, "##mies": 28397, "closeness": 28398, "hooves": 28399, "##pw": 28400, "mondays": 28401, "##roll": 28402, "##vita": 28403, "landscaping": 28404, "##urized": 28405, "purification": 28406, "sock": 28407, "thorns": 28408, "thwarted": 28409, "jalan": 28410, "tiberius": 28411, "##taka": 28412, "saline": 28413, "##rito": 28414, "confidently": 28415, "khyber": 28416, "sculptors": 28417, "##ij": 28418, "brahms": 28419, "hammersmith": 28420, "inspectors": 28421, "battista": 28422, "fivb": 28423, "fragmentation": 28424, "hackney": 28425, "##uls": 28426, "arresting": 28427, "exercising": 28428, "antoinette": 28429, "bedfordshire": 28430, "##zily": 28431, "dyed": 28432, "##hema": 28433, "1656": 28434, "racetrack": 28435, "variability": 28436, "##tique": 28437, "1655": 28438, "austrians": 28439, "deteriorating": 28440, "madman": 28441, "theorists": 28442, "aix": 28443, "lehman": 28444, "weathered": 28445, "1731": 28446, "decreed": 28447, "eruptions": 28448, "1729": 28449, "flaw": 28450, "quinlan": 28451, "sorbonne": 28452, "flutes": 28453, "nunez": 28454, "1711": 28455, "adored": 28456, "downwards": 28457, "fable": 28458, "rasped": 28459, "1712": 28460, "moritz": 28461, "mouthful": 28462, "renegade": 28463, "shivers": 28464, "stunts": 28465, "dysfunction": 28466, "restrain": 28467, "translit": 28468, "327": 28469, "pancakes": 28470, "##avio": 28471, "##cision": 28472, "##tray": 28473, "351": 28474, "vial": 28475, "##lden": 28476, "bain": 28477, "##maid": 28478, "##oxide": 28479, "chihuahua": 28480, "malacca": 28481, "vimes": 28482, "##rba": 28483, "##rnier": 28484, "1664": 28485, "donnie": 28486, "plaques": 28487, "##ually": 28488, "337": 28489, "bangs": 28490, "floppy": 28491, "huntsville": 28492, "loretta": 28493, "nikolay": 28494, "##otte": 28495, "eater": 28496, "handgun": 28497, "ubiquitous": 28498, "##hett": 28499, "eras": 28500, "zodiac": 28501, "1634": 28502, "##omorphic": 28503, "1820s": 28504, "##zog": 28505, "cochran": 28506, "##bula": 28507, "##lithic": 28508, "warring": 28509, "##rada": 28510, "dalai": 28511, "excused": 28512, "blazers": 28513, "mcconnell": 28514, "reeling": 28515, "bot": 28516, "este": 28517, "##abi": 28518, "geese": 28519, "hoax": 28520, "taxon": 28521, "##bla": 28522, "guitarists": 28523, "##icon": 28524, "condemning": 28525, "hunts": 28526, "inversion": 28527, "moffat": 28528, "taekwondo": 28529, "##lvis": 28530, "1624": 28531, "stammered": 28532, "##rest": 28533, "##rzy": 28534, "sousa": 28535, "fundraiser": 28536, "marylebone": 28537, "navigable": 28538, "uptown": 28539, "cabbage": 28540, "daniela": 28541, "salman": 28542, "shitty": 28543, "whimper": 28544, "##kian": 28545, "##utive": 28546, "programmers": 28547, "protections": 28548, "rm": 28549, "##rmi": 28550, "##rued": 28551, "forceful": 28552, "##enes": 28553, "fuss": 28554, "##tao": 28555, "##wash": 28556, "brat": 28557, "oppressive": 28558, "reykjavik": 28559, "spartak": 28560, "ticking": 28561, "##inkles": 28562, "##kiewicz": 28563, "adolph": 28564, "horst": 28565, "maui": 28566, "protege": 28567, "straighten": 28568, "cpc": 28569, "landau": 28570, "concourse": 28571, "clements": 28572, "resultant": 28573, "##ando": 28574, "imaginative": 28575, "joo": 28576, "reactivated": 28577, "##rem": 28578, "##ffled": 28579, "##uising": 28580, "consultative": 28581, "##guide": 28582, "flop": 28583, "kaitlyn": 28584, "mergers": 28585, "parenting": 28586, "somber": 28587, "##vron": 28588, "supervise": 28589, "vidhan": 28590, "##imum": 28591, "courtship": 28592, "exemplified": 28593, "harmonies": 28594, "medallist": 28595, "refining": 28596, "##rrow": 28597, "##ка": 28598, "amara": 28599, "##hum": 28600, "780": 28601, "goalscorer": 28602, "sited": 28603, "overshadowed": 28604, "rohan": 28605, "displeasure": 28606, "secretive": 28607, "multiplied": 28608, "osman": 28609, "##orth": 28610, "engravings": 28611, "padre": 28612, "##kali": 28613, "##veda": 28614, "miniatures": 28615, "mis": 28616, "##yala": 28617, "clap": 28618, "pali": 28619, "rook": 28620, "##cana": 28621, "1692": 28622, "57th": 28623, "antennae": 28624, "astro": 28625, "oskar": 28626, "1628": 28627, "bulldog": 28628, "crotch": 28629, "hackett": 28630, "yucatan": 28631, "##sure": 28632, "amplifiers": 28633, "brno": 28634, "ferrara": 28635, "migrating": 28636, "##gree": 28637, "thanking": 28638, "turing": 28639, "##eza": 28640, "mccann": 28641, "ting": 28642, "andersson": 28643, "onslaught": 28644, "gaines": 28645, "ganga": 28646, "incense": 28647, "standardization": 28648, "##mation": 28649, "sentai": 28650, "scuba": 28651, "stuffing": 28652, "turquoise": 28653, "waivers": 28654, "alloys": 28655, "##vitt": 28656, "regaining": 28657, "vaults": 28658, "##clops": 28659, "##gizing": 28660, "digger": 28661, "furry": 28662, "memorabilia": 28663, "probing": 28664, "##iad": 28665, "payton": 28666, "rec": 28667, "deutschland": 28668, "filippo": 28669, "opaque": 28670, "seamen": 28671, "zenith": 28672, "afrikaans": 28673, "##filtration": 28674, "disciplined": 28675, "inspirational": 28676, "##merie": 28677, "banco": 28678, "confuse": 28679, "grafton": 28680, "tod": 28681, "##dgets": 28682, "championed": 28683, "simi": 28684, "anomaly": 28685, "biplane": 28686, "##ceptive": 28687, "electrode": 28688, "##para": 28689, "1697": 28690, "cleavage": 28691, "crossbow": 28692, "swirl": 28693, "informant": 28694, "##lars": 28695, "##osta": 28696, "afi": 28697, "bonfire": 28698, "spec": 28699, "##oux": 28700, "lakeside": 28701, "slump": 28702, "##culus": 28703, "##lais": 28704, "##qvist": 28705, "##rrigan": 28706, "1016": 28707, "facades": 28708, "borg": 28709, "inwardly": 28710, "cervical": 28711, "xl": 28712, "pointedly": 28713, "050": 28714, "stabilization": 28715, "##odon": 28716, "chests": 28717, "1699": 28718, "hacked": 28719, "ctv": 28720, "orthogonal": 28721, "suzy": 28722, "##lastic": 28723, "gaulle": 28724, "jacobite": 28725, "rearview": 28726, "##cam": 28727, "##erted": 28728, "ashby": 28729, "##drik": 28730, "##igate": 28731, "##mise": 28732, "##zbek": 28733, "affectionately": 28734, "canine": 28735, "disperse": 28736, "latham": 28737, "##istles": 28738, "##ivar": 28739, "spielberg": 28740, "##orin": 28741, "##idium": 28742, "ezekiel": 28743, "cid": 28744, "##sg": 28745, "durga": 28746, "middletown": 28747, "##cina": 28748, "customized": 28749, "frontiers": 28750, "harden": 28751, "##etano": 28752, "##zzy": 28753, "1604": 28754, "bolsheviks": 28755, "##66": 28756, "coloration": 28757, "yoko": 28758, "##bedo": 28759, "briefs": 28760, "slabs": 28761, "debra": 28762, "liquidation": 28763, "plumage": 28764, "##oin": 28765, "blossoms": 28766, "dementia": 28767, "subsidy": 28768, "1611": 28769, "proctor": 28770, "relational": 28771, "jerseys": 28772, "parochial": 28773, "ter": 28774, "##ici": 28775, "esa": 28776, "peshawar": 28777, "cavalier": 28778, "loren": 28779, "cpi": 28780, "idiots": 28781, "shamrock": 28782, "1646": 28783, "dutton": 28784, "malabar": 28785, "mustache": 28786, "##endez": 28787, "##ocytes": 28788, "referencing": 28789, "terminates": 28790, "marche": 28791, "yarmouth": 28792, "##sop": 28793, "acton": 28794, "mated": 28795, "seton": 28796, "subtly": 28797, "baptised": 28798, "beige": 28799, "extremes": 28800, "jolted": 28801, "kristina": 28802, "telecast": 28803, "##actic": 28804, "safeguard": 28805, "waldo": 28806, "##baldi": 28807, "##bular": 28808, "endeavors": 28809, "sloppy": 28810, "subterranean": 28811, "##ensburg": 28812, "##itung": 28813, "delicately": 28814, "pigment": 28815, "tq": 28816, "##scu": 28817, "1626": 28818, "##ound": 28819, "collisions": 28820, "coveted": 28821, "herds": 28822, "##personal": 28823, "##meister": 28824, "##nberger": 28825, "chopra": 28826, "##ricting": 28827, "abnormalities": 28828, "defective": 28829, "galician": 28830, "lucie": 28831, "##dilly": 28832, "alligator": 28833, "likened": 28834, "##genase": 28835, "burundi": 28836, "clears": 28837, "complexion": 28838, "derelict": 28839, "deafening": 28840, "diablo": 28841, "fingered": 28842, "champaign": 28843, "dogg": 28844, "enlist": 28845, "isotope": 28846, "labeling": 28847, "mrna": 28848, "##erre": 28849, "brilliance": 28850, "marvelous": 28851, "##ayo": 28852, "1652": 28853, "crawley": 28854, "ether": 28855, "footed": 28856, "dwellers": 28857, "deserts": 28858, "hamish": 28859, "rubs": 28860, "warlock": 28861, "skimmed": 28862, "##lizer": 28863, "870": 28864, "buick": 28865, "embark": 28866, "heraldic": 28867, "irregularities": 28868, "##ajan": 28869, "kiara": 28870, "##kulam": 28871, "##ieg": 28872, "antigen": 28873, "kowalski": 28874, "##lge": 28875, "oakley": 28876, "visitation": 28877, "##mbit": 28878, "vt": 28879, "##suit": 28880, "1570": 28881, "murderers": 28882, "##miento": 28883, "##rites": 28884, "chimneys": 28885, "##sling": 28886, "condemn": 28887, "custer": 28888, "exchequer": 28889, "havre": 28890, "##ghi": 28891, "fluctuations": 28892, "##rations": 28893, "dfb": 28894, "hendricks": 28895, "vaccines": 28896, "##tarian": 28897, "nietzsche": 28898, "biking": 28899, "juicy": 28900, "##duced": 28901, "brooding": 28902, "scrolling": 28903, "selangor": 28904, "##ragan": 28905, "352": 28906, "annum": 28907, "boomed": 28908, "seminole": 28909, "sugarcane": 28910, "##dna": 28911, "departmental": 28912, "dismissing": 28913, "innsbruck": 28914, "arteries": 28915, "ashok": 28916, "batavia": 28917, "daze": 28918, "kun": 28919, "overtook": 28920, "##rga": 28921, "##tlan": 28922, "beheaded": 28923, "gaddafi": 28924, "holm": 28925, "electronically": 28926, "faulty": 28927, "galilee": 28928, "fractures": 28929, "kobayashi": 28930, "##lized": 28931, "gunmen": 28932, "magma": 28933, "aramaic": 28934, "mala": 28935, "eastenders": 28936, "inference": 28937, "messengers": 28938, "bf": 28939, "##qu": 28940, "407": 28941, "bathrooms": 28942, "##vere": 28943, "1658": 28944, "flashbacks": 28945, "ideally": 28946, "misunderstood": 28947, "##jali": 28948, "##weather": 28949, "mendez": 28950, "##grounds": 28951, "505": 28952, "uncanny": 28953, "##iii": 28954, "1709": 28955, "friendships": 28956, "##nbc": 28957, "sacrament": 28958, "accommodated": 28959, "reiterated": 28960, "logistical": 28961, "pebbles": 28962, "thumped": 28963, "##escence": 28964, "administering": 28965, "decrees": 28966, "drafts": 28967, "##flight": 28968, "##cased": 28969, "##tula": 28970, "futuristic": 28971, "picket": 28972, "intimidation": 28973, "winthrop": 28974, "##fahan": 28975, "interfered": 28976, "339": 28977, "afar": 28978, "francoise": 28979, "morally": 28980, "uta": 28981, "cochin": 28982, "croft": 28983, "dwarfs": 28984, "##bruck": 28985, "##dents": 28986, "##nami": 28987, "biker": 28988, "##hner": 28989, "##meral": 28990, "nano": 28991, "##isen": 28992, "##ometric": 28993, "##pres": 28994, "##ан": 28995, "brightened": 28996, "meek": 28997, "parcels": 28998, "securely": 28999, "gunners": 29000, "##jhl": 29001, "##zko": 29002, "agile": 29003, "hysteria": 29004, "##lten": 29005, "##rcus": 29006, "bukit": 29007, "champs": 29008, "chevy": 29009, "cuckoo": 29010, "leith": 29011, "sadler": 29012, "theologians": 29013, "welded": 29014, "##section": 29015, "1663": 29016, "jj": 29017, "plurality": 29018, "xander": 29019, "##rooms": 29020, "##formed": 29021, "shredded": 29022, "temps": 29023, "intimately": 29024, "pau": 29025, "tormented": 29026, "##lok": 29027, "##stellar": 29028, "1618": 29029, "charred": 29030, "ems": 29031, "essen": 29032, "##mmel": 29033, "alarms": 29034, "spraying": 29035, "ascot": 29036, "blooms": 29037, "twinkle": 29038, "##abia": 29039, "##apes": 29040, "internment": 29041, "obsidian": 29042, "##chaft": 29043, "snoop": 29044, "##dav": 29045, "##ooping": 29046, "malibu": 29047, "##tension": 29048, "quiver": 29049, "##itia": 29050, "hays": 29051, "mcintosh": 29052, "travers": 29053, "walsall": 29054, "##ffie": 29055, "1623": 29056, "beverley": 29057, "schwarz": 29058, "plunging": 29059, "structurally": 29060, "m3": 29061, "rosenthal": 29062, "vikram": 29063, "##tsk": 29064, "770": 29065, "ghz": 29066, "##onda": 29067, "##tiv": 29068, "chalmers": 29069, "groningen": 29070, "pew": 29071, "reckon": 29072, "unicef": 29073, "##rvis": 29074, "55th": 29075, "##gni": 29076, "1651": 29077, "sulawesi": 29078, "avila": 29079, "cai": 29080, "metaphysical": 29081, "screwing": 29082, "turbulence": 29083, "##mberg": 29084, "augusto": 29085, "samba": 29086, "56th": 29087, "baffled": 29088, "momentary": 29089, "toxin": 29090, "##urian": 29091, "##wani": 29092, "aachen": 29093, "condoms": 29094, "dali": 29095, "steppe": 29096, "##3d": 29097, "##app": 29098, "##oed": 29099, "##year": 29100, "adolescence": 29101, "dauphin": 29102, "electrically": 29103, "inaccessible": 29104, "microscopy": 29105, "nikita": 29106, "##ega": 29107, "atv": 29108, "##cel": 29109, "##enter": 29110, "##oles": 29111, "##oteric": 29112, "##ы": 29113, "accountants": 29114, "punishments": 29115, "wrongly": 29116, "bribes": 29117, "adventurous": 29118, "clinch": 29119, "flinders": 29120, "southland": 29121, "##hem": 29122, "##kata": 29123, "gough": 29124, "##ciency": 29125, "lads": 29126, "soared": 29127, "##ה": 29128, "undergoes": 29129, "deformation": 29130, "outlawed": 29131, "rubbish": 29132, "##arus": 29133, "##mussen": 29134, "##nidae": 29135, "##rzburg": 29136, "arcs": 29137, "##ingdon": 29138, "##tituted": 29139, "1695": 29140, "wheelbase": 29141, "wheeling": 29142, "bombardier": 29143, "campground": 29144, "zebra": 29145, "##lices": 29146, "##oj": 29147, "##bain": 29148, "lullaby": 29149, "##ecure": 29150, "donetsk": 29151, "wylie": 29152, "grenada": 29153, "##arding": 29154, "##ης": 29155, "squinting": 29156, "eireann": 29157, "opposes": 29158, "##andra": 29159, "maximal": 29160, "runes": 29161, "##broken": 29162, "##cuting": 29163, "##iface": 29164, "##ror": 29165, "##rosis": 29166, "additive": 29167, "britney": 29168, "adultery": 29169, "triggering": 29170, "##drome": 29171, "detrimental": 29172, "aarhus": 29173, "containment": 29174, "jc": 29175, "swapped": 29176, "vichy": 29177, "##ioms": 29178, "madly": 29179, "##oric": 29180, "##rag": 29181, "brant": 29182, "##ckey": 29183, "##trix": 29184, "1560": 29185, "1612": 29186, "broughton": 29187, "rustling": 29188, "##stems": 29189, "##uder": 29190, "asbestos": 29191, "mentoring": 29192, "##nivorous": 29193, "finley": 29194, "leaps": 29195, "##isan": 29196, "apical": 29197, "pry": 29198, "slits": 29199, "substitutes": 29200, "##dict": 29201, "intuitive": 29202, "fantasia": 29203, "insistent": 29204, "unreasonable": 29205, "##igen": 29206, "##vna": 29207, "domed": 29208, "hannover": 29209, "margot": 29210, "ponder": 29211, "##zziness": 29212, "impromptu": 29213, "jian": 29214, "lc": 29215, "rampage": 29216, "stemming": 29217, "##eft": 29218, "andrey": 29219, "gerais": 29220, "whichever": 29221, "amnesia": 29222, "appropriated": 29223, "anzac": 29224, "clicks": 29225, "modifying": 29226, "ultimatum": 29227, "cambrian": 29228, "maids": 29229, "verve": 29230, "yellowstone": 29231, "##mbs": 29232, "conservatoire": 29233, "##scribe": 29234, "adherence": 29235, "dinners": 29236, "spectra": 29237, "imperfect": 29238, "mysteriously": 29239, "sidekick": 29240, "tatar": 29241, "tuba": 29242, "##aks": 29243, "##ifolia": 29244, "distrust": 29245, "##athan": 29246, "##zle": 29247, "c2": 29248, "ronin": 29249, "zac": 29250, "##pse": 29251, "celaena": 29252, "instrumentalist": 29253, "scents": 29254, "skopje": 29255, "##mbling": 29256, "comical": 29257, "compensated": 29258, "vidal": 29259, "condor": 29260, "intersect": 29261, "jingle": 29262, "wavelengths": 29263, "##urrent": 29264, "mcqueen": 29265, "##izzly": 29266, "carp": 29267, "weasel": 29268, "422": 29269, "kanye": 29270, "militias": 29271, "postdoctoral": 29272, "eugen": 29273, "gunslinger": 29274, "##ɛ": 29275, "faux": 29276, "hospice": 29277, "##for": 29278, "appalled": 29279, "derivation": 29280, "dwarves": 29281, "##elis": 29282, "dilapidated": 29283, "##folk": 29284, "astoria": 29285, "philology": 29286, "##lwyn": 29287, "##otho": 29288, "##saka": 29289, "inducing": 29290, "philanthropy": 29291, "##bf": 29292, "##itative": 29293, "geek": 29294, "markedly": 29295, "sql": 29296, "##yce": 29297, "bessie": 29298, "indices": 29299, "rn": 29300, "##flict": 29301, "495": 29302, "frowns": 29303, "resolving": 29304, "weightlifting": 29305, "tugs": 29306, "cleric": 29307, "contentious": 29308, "1653": 29309, "mania": 29310, "rms": 29311, "##miya": 29312, "##reate": 29313, "##ruck": 29314, "##tucket": 29315, "bien": 29316, "eels": 29317, "marek": 29318, "##ayton": 29319, "##cence": 29320, "discreet": 29321, "unofficially": 29322, "##ife": 29323, "leaks": 29324, "##bber": 29325, "1705": 29326, "332": 29327, "dung": 29328, "compressor": 29329, "hillsborough": 29330, "pandit": 29331, "shillings": 29332, "distal": 29333, "##skin": 29334, "381": 29335, "##tat": 29336, "##you": 29337, "nosed": 29338, "##nir": 29339, "mangrove": 29340, "undeveloped": 29341, "##idia": 29342, "textures": 29343, "##inho": 29344, "##500": 29345, "##rise": 29346, "ae": 29347, "irritating": 29348, "nay": 29349, "amazingly": 29350, "bancroft": 29351, "apologetic": 29352, "compassionate": 29353, "kata": 29354, "symphonies": 29355, "##lovic": 29356, "airspace": 29357, "##lch": 29358, "930": 29359, "gifford": 29360, "precautions": 29361, "fulfillment": 29362, "sevilla": 29363, "vulgar": 29364, "martinique": 29365, "##urities": 29366, "looting": 29367, "piccolo": 29368, "tidy": 29369, "##dermott": 29370, "quadrant": 29371, "armchair": 29372, "incomes": 29373, "mathematicians": 29374, "stampede": 29375, "nilsson": 29376, "##inking": 29377, "##scan": 29378, "foo": 29379, "quarterfinal": 29380, "##ostal": 29381, "shang": 29382, "shouldered": 29383, "squirrels": 29384, "##owe": 29385, "344": 29386, "vinegar": 29387, "##bner": 29388, "##rchy": 29389, "##systems": 29390, "delaying": 29391, "##trics": 29392, "ars": 29393, "dwyer": 29394, "rhapsody": 29395, "sponsoring": 29396, "##gration": 29397, "bipolar": 29398, "cinder": 29399, "starters": 29400, "##olio": 29401, "##urst": 29402, "421": 29403, "signage": 29404, "##nty": 29405, "aground": 29406, "figurative": 29407, "mons": 29408, "acquaintances": 29409, "duets": 29410, "erroneously": 29411, "soyuz": 29412, "elliptic": 29413, "recreated": 29414, "##cultural": 29415, "##quette": 29416, "##ssed": 29417, "##tma": 29418, "##zcz": 29419, "moderator": 29420, "scares": 29421, "##itaire": 29422, "##stones": 29423, "##udence": 29424, "juniper": 29425, "sighting": 29426, "##just": 29427, "##nsen": 29428, "britten": 29429, "calabria": 29430, "ry": 29431, "bop": 29432, "cramer": 29433, "forsyth": 29434, "stillness": 29435, "##л": 29436, "airmen": 29437, "gathers": 29438, "unfit": 29439, "##umber": 29440, "##upt": 29441, "taunting": 29442, "##rip": 29443, "seeker": 29444, "streamlined": 29445, "##bution": 29446, "holster": 29447, "schumann": 29448, "tread": 29449, "vox": 29450, "##gano": 29451, "##onzo": 29452, "strive": 29453, "dil": 29454, "reforming": 29455, "covent": 29456, "newbury": 29457, "predicting": 29458, "##orro": 29459, "decorate": 29460, "tre": 29461, "##puted": 29462, "andover": 29463, "ie": 29464, "asahi": 29465, "dept": 29466, "dunkirk": 29467, "gills": 29468, "##tori": 29469, "buren": 29470, "huskies": 29471, "##stis": 29472, "##stov": 29473, "abstracts": 29474, "bets": 29475, "loosen": 29476, "##opa": 29477, "1682": 29478, "yearning": 29479, "##glio": 29480, "##sir": 29481, "berman": 29482, "effortlessly": 29483, "enamel": 29484, "napoli": 29485, "persist": 29486, "##peration": 29487, "##uez": 29488, "attache": 29489, "elisa": 29490, "b1": 29491, "invitations": 29492, "##kic": 29493, "accelerating": 29494, "reindeer": 29495, "boardwalk": 29496, "clutches": 29497, "nelly": 29498, "polka": 29499, "starbucks": 29500, "##kei": 29501, "adamant": 29502, "huey": 29503, "lough": 29504, "unbroken": 29505, "adventurer": 29506, "embroidery": 29507, "inspecting": 29508, "stanza": 29509, "##ducted": 29510, "naia": 29511, "taluka": 29512, "##pone": 29513, "##roids": 29514, "chases": 29515, "deprivation": 29516, "florian": 29517, "##jing": 29518, "##ppet": 29519, "earthly": 29520, "##lib": 29521, "##ssee": 29522, "colossal": 29523, "foreigner": 29524, "vet": 29525, "freaks": 29526, "patrice": 29527, "rosewood": 29528, "triassic": 29529, "upstate": 29530, "##pkins": 29531, "dominates": 29532, "ata": 29533, "chants": 29534, "ks": 29535, "vo": 29536, "##400": 29537, "##bley": 29538, "##raya": 29539, "##rmed": 29540, "555": 29541, "agra": 29542, "infiltrate": 29543, "##ailing": 29544, "##ilation": 29545, "##tzer": 29546, "##uppe": 29547, "##werk": 29548, "binoculars": 29549, "enthusiast": 29550, "fujian": 29551, "squeak": 29552, "##avs": 29553, "abolitionist": 29554, "almeida": 29555, "boredom": 29556, "hampstead": 29557, "marsden": 29558, "rations": 29559, "##ands": 29560, "inflated": 29561, "334": 29562, "bonuses": 29563, "rosalie": 29564, "patna": 29565, "##rco": 29566, "329": 29567, "detachments": 29568, "penitentiary": 29569, "54th": 29570, "flourishing": 29571, "woolf": 29572, "##dion": 29573, "##etched": 29574, "papyrus": 29575, "##lster": 29576, "##nsor": 29577, "##toy": 29578, "bobbed": 29579, "dismounted": 29580, "endelle": 29581, "inhuman": 29582, "motorola": 29583, "tbs": 29584, "wince": 29585, "wreath": 29586, "##ticus": 29587, "hideout": 29588, "inspections": 29589, "sanjay": 29590, "disgrace": 29591, "infused": 29592, "pudding": 29593, "stalks": 29594, "##urbed": 29595, "arsenic": 29596, "leases": 29597, "##hyl": 29598, "##rrard": 29599, "collarbone": 29600, "##waite": 29601, "##wil": 29602, "dowry": 29603, "##bant": 29604, "##edance": 29605, "genealogical": 29606, "nitrate": 29607, "salamanca": 29608, "scandals": 29609, "thyroid": 29610, "necessitated": 29611, "##!": 29612, "##\"": 29613, "###": 29614, "##$": 29615, "##%": 29616, "##&": 29617, "##'": 29618, "##(": 29619, "##)": 29620, "##*": 29621, "##+": 29622, "##,": 29623, "##-": 29624, "##.": 29625, "##/": 29626, "##:": 29627, "##;": 29628, "##<": 29629, "##=": 29630, "##>": 29631, "##?": 29632, "##@": 29633, "##[": 29634, "##\\": 29635, "##]": 29636, "##^": 29637, "##_": 29638, "##`": 29639, "##{": 29640, "##|": 29641, "##}": 29642, "##~": 29643, "##¡": 29644, "##¢": 29645, "##£": 29646, "##¤": 29647, "##¥": 29648, "##¦": 29649, "##§": 29650, "##¨": 29651, "##©": 29652, "##ª": 29653, "##«": 29654, "##¬": 29655, "##®": 29656, "##±": 29657, "##´": 29658, "##µ": 29659, "##¶": 29660, "##·": 29661, "##º": 29662, "##»": 29663, "##¼": 29664, "##¾": 29665, "##¿": 29666, "##æ": 29667, "##ð": 29668, "##÷": 29669, "##þ": 29670, "##đ": 29671, "##ħ": 29672, "##ŋ": 29673, "##œ": 29674, "##ƒ": 29675, "##ɐ": 29676, "##ɑ": 29677, "##ɒ": 29678, "##ɔ": 29679, "##ɕ": 29680, "##ə": 29681, "##ɡ": 29682, "##ɣ": 29683, "##ɨ": 29684, "##ɪ": 29685, "##ɫ": 29686, "##ɬ": 29687, "##ɯ": 29688, "##ɲ": 29689, "##ɴ": 29690, "##ɹ": 29691, "##ɾ": 29692, "##ʀ": 29693, "##ʁ": 29694, "##ʂ": 29695, "##ʃ": 29696, "##ʉ": 29697, "##ʊ": 29698, "##ʋ": 29699, "##ʌ": 29700, "##ʎ": 29701, "##ʐ": 29702, "##ʑ": 29703, "##ʒ": 29704, "##ʔ": 29705, "##ʰ": 29706, "##ʲ": 29707, "##ʳ": 29708, "##ʷ": 29709, "##ʸ": 29710, "##ʻ": 29711, "##ʼ": 29712, "##ʾ": 29713, "##ʿ": 29714, "##ˈ": 29715, "##ˡ": 29716, "##ˢ": 29717, "##ˣ": 29718, "##ˤ": 29719, "##β": 29720, "##γ": 29721, "##δ": 29722, "##ε": 29723, "##ζ": 29724, "##θ": 29725, "##κ": 29726, "##λ": 29727, "##μ": 29728, "##ξ": 29729, "##ο": 29730, "##π": 29731, "##ρ": 29732, "##σ": 29733, "##τ": 29734, "##υ": 29735, "##φ": 29736, "##χ": 29737, "##ψ": 29738, "##ω": 29739, "##б": 29740, "##г": 29741, "##д": 29742, "##ж": 29743, "##з": 29744, "##м": 29745, "##п": 29746, "##с": 29747, "##у": 29748, "##ф": 29749, "##х": 29750, "##ц": 29751, "##ч": 29752, "##ш": 29753, "##щ": 29754, "##ъ": 29755, "##э": 29756, "##ю": 29757, "##ђ": 29758, "##є": 29759, "##і": 29760, "##ј": 29761, "##љ": 29762, "##њ": 29763, "##ћ": 29764, "##ӏ": 29765, "##ա": 29766, "##բ": 29767, "##գ": 29768, "##դ": 29769, "##ե": 29770, "##թ": 29771, "##ի": 29772, "##լ": 29773, "##կ": 29774, "##հ": 29775, "##մ": 29776, "##յ": 29777, "##ն": 29778, "##ո": 29779, "##պ": 29780, "##ս": 29781, "##վ": 29782, "##տ": 29783, "##ր": 29784, "##ւ": 29785, "##ք": 29786, "##־": 29787, "##א": 29788, "##ב": 29789, "##ג": 29790, "##ד": 29791, "##ו": 29792, "##ז": 29793, "##ח": 29794, "##ט": 29795, "##י": 29796, "##ך": 29797, "##כ": 29798, "##ל": 29799, "##ם": 29800, "##מ": 29801, "##ן": 29802, "##נ": 29803, "##ס": 29804, "##ע": 29805, "##ף": 29806, "##פ": 29807, "##ץ": 29808, "##צ": 29809, "##ק": 29810, "##ר": 29811, "##ש": 29812, "##ת": 29813, "##،": 29814, "##ء": 29815, "##ب": 29816, "##ت": 29817, "##ث": 29818, "##ج": 29819, "##ح": 29820, "##خ": 29821, "##ذ": 29822, "##ز": 29823, "##س": 29824, "##ش": 29825, "##ص": 29826, "##ض": 29827, "##ط": 29828, "##ظ": 29829, "##ع": 29830, "##غ": 29831, "##ـ": 29832, "##ف": 29833, "##ق": 29834, "##ك": 29835, "##و": 29836, "##ى": 29837, "##ٹ": 29838, "##پ": 29839, "##چ": 29840, "##ک": 29841, "##گ": 29842, "##ں": 29843, "##ھ": 29844, "##ہ": 29845, "##ے": 29846, "##अ": 29847, "##आ": 29848, "##उ": 29849, "##ए": 29850, "##क": 29851, "##ख": 29852, "##ग": 29853, "##च": 29854, "##ज": 29855, "##ट": 29856, "##ड": 29857, "##ण": 29858, "##त": 29859, "##थ": 29860, "##द": 29861, "##ध": 29862, "##न": 29863, "##प": 29864, "##ब": 29865, "##भ": 29866, "##म": 29867, "##य": 29868, "##र": 29869, "##ल": 29870, "##व": 29871, "##श": 29872, "##ष": 29873, "##स": 29874, "##ह": 29875, "##ा": 29876, "##ि": 29877, "##ी": 29878, "##ो": 29879, "##।": 29880, "##॥": 29881, "##ং": 29882, "##অ": 29883, "##আ": 29884, "##ই": 29885, "##উ": 29886, "##এ": 29887, "##ও": 29888, "##ক": 29889, "##খ": 29890, "##গ": 29891, "##চ": 29892, "##ছ": 29893, "##জ": 29894, "##ট": 29895, "##ড": 29896, "##ণ": 29897, "##ত": 29898, "##থ": 29899, "##দ": 29900, "##ধ": 29901, "##ন": 29902, "##প": 29903, "##ব": 29904, "##ভ": 29905, "##ম": 29906, "##য": 29907, "##র": 29908, "##ল": 29909, "##শ": 29910, "##ষ": 29911, "##স": 29912, "##হ": 29913, "##া": 29914, "##ি": 29915, "##ী": 29916, "##ে": 29917, "##க": 29918, "##ச": 29919, "##ட": 29920, "##த": 29921, "##ந": 29922, "##ன": 29923, "##ப": 29924, "##ம": 29925, "##ய": 29926, "##ர": 29927, "##ல": 29928, "##ள": 29929, "##வ": 29930, "##ா": 29931, "##ி": 29932, "##ு": 29933, "##ே": 29934, "##ை": 29935, "##ನ": 29936, "##ರ": 29937, "##ಾ": 29938, "##ක": 29939, "##ය": 29940, "##ර": 29941, "##ල": 29942, "##ව": 29943, "##ා": 29944, "##ก": 29945, "##ง": 29946, "##ต": 29947, "##ท": 29948, "##น": 29949, "##พ": 29950, "##ม": 29951, "##ย": 29952, "##ร": 29953, "##ล": 29954, "##ว": 29955, "##ส": 29956, "##อ": 29957, "##า": 29958, "##เ": 29959, "##་": 29960, "##།": 29961, "##ག": 29962, "##ང": 29963, "##ད": 29964, "##ན": 29965, "##པ": 29966, "##བ": 29967, "##མ": 29968, "##འ": 29969, "##ར": 29970, "##ལ": 29971, "##ས": 29972, "##မ": 29973, "##ა": 29974, "##ბ": 29975, "##გ": 29976, "##დ": 29977, "##ე": 29978, "##ვ": 29979, "##თ": 29980, "##ი": 29981, "##კ": 29982, "##ლ": 29983, "##მ": 29984, "##ნ": 29985, "##ო": 29986, "##რ": 29987, "##ს": 29988, "##ტ": 29989, "##უ": 29990, "##ᄀ": 29991, "##ᄂ": 29992, "##ᄃ": 29993, "##ᄅ": 29994, "##ᄆ": 29995, "##ᄇ": 29996, "##ᄉ": 29997, "##ᄊ": 29998, "##ᄋ": 29999, "##ᄌ": 30000, "##ᄎ": 30001, "##ᄏ": 30002, "##ᄐ": 30003, "##ᄑ": 30004, "##ᄒ": 30005, "##ᅡ": 30006, "##ᅢ": 30007, "##ᅥ": 30008, "##ᅦ": 30009, "##ᅧ": 30010, "##ᅩ": 30011, "##ᅪ": 30012, "##ᅭ": 30013, "##ᅮ": 30014, "##ᅯ": 30015, "##ᅲ": 30016, "##ᅳ": 30017, "##ᅴ": 30018, "##ᅵ": 30019, "##ᆨ": 30020, "##ᆫ": 30021, "##ᆯ": 30022, "##ᆷ": 30023, "##ᆸ": 30024, "##ᆼ": 30025, "##ᴬ": 30026, "##ᴮ": 30027, "##ᴰ": 30028, "##ᴵ": 30029, "##ᴺ": 30030, "##ᵀ": 30031, "##ᵃ": 30032, "##ᵇ": 30033, "##ᵈ": 30034, "##ᵉ": 30035, "##ᵍ": 30036, "##ᵏ": 30037, "##ᵐ": 30038, "##ᵒ": 30039, "##ᵖ": 30040, "##ᵗ": 30041, "##ᵘ": 30042, "##ᵣ": 30043, "##ᵤ": 30044, "##ᵥ": 30045, "##ᶜ": 30046, "##ᶠ": 30047, "##‐": 30048, "##‑": 30049, "##‒": 30050, "##–": 30051, "##—": 30052, "##―": 30053, "##‖": 30054, "##‘": 30055, "##’": 30056, "##‚": 30057, "##“": 30058, "##”": 30059, "##„": 30060, "##†": 30061, "##‡": 30062, "##•": 30063, "##…": 30064, "##‰": 30065, "##′": 30066, "##″": 30067, "##›": 30068, "##‿": 30069, "##⁄": 30070, "##⁰": 30071, "##ⁱ": 30072, "##⁴": 30073, "##⁵": 30074, "##⁶": 30075, "##⁷": 30076, "##⁸": 30077, "##⁹": 30078, "##⁻": 30079, "##ⁿ": 30080, "##₅": 30081, "##₆": 30082, "##₇": 30083, "##₈": 30084, "##₉": 30085, "##₊": 30086, "##₍": 30087, "##₎": 30088, "##ₐ": 30089, "##ₑ": 30090, "##ₒ": 30091, "##ₓ": 30092, "##ₕ": 30093, "##ₖ": 30094, "##ₗ": 30095, "##ₘ": 30096, "##ₚ": 30097, "##ₛ": 30098, "##ₜ": 30099, "##₤": 30100, "##₩": 30101, "##€": 30102, "##₱": 30103, "##₹": 30104, "##ℓ": 30105, "##№": 30106, "##ℝ": 30107, "##™": 30108, "##⅓": 30109, "##⅔": 30110, "##←": 30111, "##↑": 30112, "##→": 30113, "##↓": 30114, "##↔": 30115, "##↦": 30116, "##⇄": 30117, "##⇌": 30118, "##⇒": 30119, "##∂": 30120, "##∅": 30121, "##∆": 30122, "##∇": 30123, "##∈": 30124, "##∗": 30125, "##∘": 30126, "##√": 30127, "##∞": 30128, "##∧": 30129, "##∨": 30130, "##∩": 30131, "##∪": 30132, "##≈": 30133, "##≡": 30134, "##≤": 30135, "##≥": 30136, "##⊂": 30137, "##⊆": 30138, "##⊕": 30139, "##⊗": 30140, "##⋅": 30141, "##─": 30142, "##│": 30143, "##■": 30144, "##▪": 30145, "##●": 30146, "##★": 30147, "##☆": 30148, "##☉": 30149, "##♠": 30150, "##♣": 30151, "##♥": 30152, "##♦": 30153, "##♯": 30154, "##⟨": 30155, "##⟩": 30156, "##ⱼ": 30157, "##⺩": 30158, "##⺼": 30159, "##⽥": 30160, "##、": 30161, "##。": 30162, "##〈": 30163, "##〉": 30164, "##《": 30165, "##》": 30166, "##「": 30167, "##」": 30168, "##『": 30169, "##』": 30170, "##〜": 30171, "##あ": 30172, "##い": 30173, "##う": 30174, "##え": 30175, "##お": 30176, "##か": 30177, "##き": 30178, "##く": 30179, "##け": 30180, "##こ": 30181, "##さ": 30182, "##し": 30183, "##す": 30184, "##せ": 30185, "##そ": 30186, "##た": 30187, "##ち": 30188, "##っ": 30189, "##つ": 30190, "##て": 30191, "##と": 30192, "##な": 30193, "##に": 30194, "##ぬ": 30195, "##ね": 30196, "##の": 30197, "##は": 30198, "##ひ": 30199, "##ふ": 30200, "##へ": 30201, "##ほ": 30202, "##ま": 30203, "##み": 30204, "##む": 30205, "##め": 30206, "##も": 30207, "##や": 30208, "##ゆ": 30209, "##よ": 30210, "##ら": 30211, "##り": 30212, "##る": 30213, "##れ": 30214, "##ろ": 30215, "##を": 30216, "##ん": 30217, "##ァ": 30218, "##ア": 30219, "##ィ": 30220, "##イ": 30221, "##ウ": 30222, "##ェ": 30223, "##エ": 30224, "##オ": 30225, "##カ": 30226, "##キ": 30227, "##ク": 30228, "##ケ": 30229, "##コ": 30230, "##サ": 30231, "##シ": 30232, "##ス": 30233, "##セ": 30234, "##タ": 30235, "##チ": 30236, "##ッ": 30237, "##ツ": 30238, "##テ": 30239, "##ト": 30240, "##ナ": 30241, "##ニ": 30242, "##ノ": 30243, "##ハ": 30244, "##ヒ": 30245, "##フ": 30246, "##ヘ": 30247, "##ホ": 30248, "##マ": 30249, "##ミ": 30250, "##ム": 30251, "##メ": 30252, "##モ": 30253, "##ャ": 30254, "##ュ": 30255, "##ョ": 30256, "##ラ": 30257, "##リ": 30258, "##ル": 30259, "##レ": 30260, "##ロ": 30261, "##ワ": 30262, "##ン": 30263, "##・": 30264, "##ー": 30265, "##一": 30266, "##三": 30267, "##上": 30268, "##下": 30269, "##不": 30270, "##世": 30271, "##中": 30272, "##主": 30273, "##久": 30274, "##之": 30275, "##也": 30276, "##事": 30277, "##二": 30278, "##五": 30279, "##井": 30280, "##京": 30281, "##人": 30282, "##亻": 30283, "##仁": 30284, "##介": 30285, "##代": 30286, "##仮": 30287, "##伊": 30288, "##会": 30289, "##佐": 30290, "##侍": 30291, "##保": 30292, "##信": 30293, "##健": 30294, "##元": 30295, "##光": 30296, "##八": 30297, "##公": 30298, "##内": 30299, "##出": 30300, "##分": 30301, "##前": 30302, "##劉": 30303, "##力": 30304, "##加": 30305, "##勝": 30306, "##北": 30307, "##区": 30308, "##十": 30309, "##千": 30310, "##南": 30311, "##博": 30312, "##原": 30313, "##口": 30314, "##古": 30315, "##史": 30316, "##司": 30317, "##合": 30318, "##吉": 30319, "##同": 30320, "##名": 30321, "##和": 30322, "##囗": 30323, "##四": 30324, "##国": 30325, "##國": 30326, "##土": 30327, "##地": 30328, "##坂": 30329, "##城": 30330, "##堂": 30331, "##場": 30332, "##士": 30333, "##夏": 30334, "##外": 30335, "##大": 30336, "##天": 30337, "##太": 30338, "##夫": 30339, "##奈": 30340, "##女": 30341, "##子": 30342, "##学": 30343, "##宀": 30344, "##宇": 30345, "##安": 30346, "##宗": 30347, "##定": 30348, "##宣": 30349, "##宮": 30350, "##家": 30351, "##宿": 30352, "##寺": 30353, "##將": 30354, "##小": 30355, "##尚": 30356, "##山": 30357, "##岡": 30358, "##島": 30359, "##崎": 30360, "##川": 30361, "##州": 30362, "##巿": 30363, "##帝": 30364, "##平": 30365, "##年": 30366, "##幸": 30367, "##广": 30368, "##弘": 30369, "##張": 30370, "##彳": 30371, "##後": 30372, "##御": 30373, "##德": 30374, "##心": 30375, "##忄": 30376, "##志": 30377, "##忠": 30378, "##愛": 30379, "##成": 30380, "##我": 30381, "##戦": 30382, "##戸": 30383, "##手": 30384, "##扌": 30385, "##政": 30386, "##文": 30387, "##新": 30388, "##方": 30389, "##日": 30390, "##明": 30391, "##星": 30392, "##春": 30393, "##昭": 30394, "##智": 30395, "##曲": 30396, "##書": 30397, "##月": 30398, "##有": 30399, "##朝": 30400, "##木": 30401, "##本": 30402, "##李": 30403, "##村": 30404, "##東": 30405, "##松": 30406, "##林": 30407, "##森": 30408, "##楊": 30409, "##樹": 30410, "##橋": 30411, "##歌": 30412, "##止": 30413, "##正": 30414, "##武": 30415, "##比": 30416, "##氏": 30417, "##民": 30418, "##水": 30419, "##氵": 30420, "##氷": 30421, "##永": 30422, "##江": 30423, "##沢": 30424, "##河": 30425, "##治": 30426, "##法": 30427, "##海": 30428, "##清": 30429, "##漢": 30430, "##瀬": 30431, "##火": 30432, "##版": 30433, "##犬": 30434, "##王": 30435, "##生": 30436, "##田": 30437, "##男": 30438, "##疒": 30439, "##発": 30440, "##白": 30441, "##的": 30442, "##皇": 30443, "##目": 30444, "##相": 30445, "##省": 30446, "##真": 30447, "##石": 30448, "##示": 30449, "##社": 30450, "##神": 30451, "##福": 30452, "##禾": 30453, "##秀": 30454, "##秋": 30455, "##空": 30456, "##立": 30457, "##章": 30458, "##竹": 30459, "##糹": 30460, "##美": 30461, "##義": 30462, "##耳": 30463, "##良": 30464, "##艹": 30465, "##花": 30466, "##英": 30467, "##華": 30468, "##葉": 30469, "##藤": 30470, "##行": 30471, "##街": 30472, "##西": 30473, "##見": 30474, "##訁": 30475, "##語": 30476, "##谷": 30477, "##貝": 30478, "##貴": 30479, "##車": 30480, "##軍": 30481, "##辶": 30482, "##道": 30483, "##郎": 30484, "##郡": 30485, "##部": 30486, "##都": 30487, "##里": 30488, "##野": 30489, "##金": 30490, "##鈴": 30491, "##镇": 30492, "##長": 30493, "##門": 30494, "##間": 30495, "##阝": 30496, "##阿": 30497, "##陳": 30498, "##陽": 30499, "##雄": 30500, "##青": 30501, "##面": 30502, "##風": 30503, "##食": 30504, "##香": 30505, "##馬": 30506, "##高": 30507, "##龍": 30508, "##龸": 30509, "##fi": 30510, "##fl": 30511, "##!": 30512, "##(": 30513, "##)": 30514, "##,": 30515, "##-": 30516, "##.": 30517, "##/": 30518, "##:": 30519, "##?": 30520, "##~": 30521 } } } ================================================ FILE: main.py ================================================ from commands.cli import cli from commands.llm import llm if __name__ == '__main__': cli() ================================================ FILE: nginx.conf ================================================ # Define the user and worker processes user nginx; worker_processes auto; # Set the error log and pid file locations error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; # Main HTTP block events {} http { include /etc/nginx/mime.types; default_type application/octet-stream; # Access and error log access_log /var/log/nginx/access.log; upstream zitadel { server zitadel:8080; # This references the 'zitedal' service by its name and internal port 8080 } upstream backend { server backend:8001; # This references the 'backend' service by its name and internal port 8080 } # Server block for HTTP (port 80) server { listen 80; client_max_body_size 100M; # Set to 10 MB or your desired size # server_name 20.84.41.108; # Set the root directory for static files root /usr/share/nginx/html; index index.html index.htm; location /api/ { proxy_pass http://backend/api/; # Forward to ZiteDal proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location / { proxy_pass http://backend/; # Forward to ZiteDal proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # Handle 404 errors for any unknown routes error_page 404 /404.html; location = /404.html { root /usr/share/nginx/html; } # Handle 50x errors error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } server { listen 82; # server_name 20.84.41.108; # Set the root directory for static files root /usr/share/nginx/html; index index.html index.htm; location /ui/ { proxy_pass http://zitadel/ui/; # Forward to ZiteDal proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /oauth/ { proxy_pass http://zitadel/oauth/; # Forward to ZiteDal proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location / { proxy_pass http://zitadel/; # Forward to ZiteDal proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # proxy_set_header X-Forwarded-Uri $request_uri; } # Handle 404 errors for any unknown routes error_page 404 /404.html; location = /404.html { root /usr/share/nginx/html; } # Handle 50x errors error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } } ================================================ FILE: pyproject.toml ================================================ [tool.poetry] name = "raggenie" version = "0.0.1" description = "Raggenie is a platform for easy RAG building and integration." authors = ["Sirocco ventures "] license = "MIT" readme = "README.md" [tool.poetry.dependencies] python = "^3.11" aiofiles = "23.2.1" aiohappyeyeballs = "2.4.0" aiohttp = "3.10.5" aiosignal = "1.3.1" annotated-types = "0.7.0" anyio = "4.4.0" apscheduler = "3.10.4" argcomplete = "3.5.0" asgiref = "3.8.1" asyncer = "0.0.7" attrs = "24.2.0" backoff = "2.2.1" bcrypt = "4.2.0" beautifulsoup4 = "4.12.3" bidict = "0.23.1" build = "1.2.2" cachetools = "5.5.0" certifi = "2024.8.30" cffi = "1.17.1" chainlit = "1.1.404" chardet = "5.2.0" charset-normalizer = "3.3.2" chevron = "0.14.0" chroma-hnswlib = "0.7.6" chromadb = "0.5.5" click = "8.1.7" coloredlogs = "15.0.1" cryptography = "43.0.1" dependency-injector = "4.42.0" deprecated = "1.2.14" deprecation = "2.1.0" docx2txt = "0.8" ebooklib = "0.18" et-xmlfile = "1.1.0" fastapi = "0.110.3" filelock = "3.16.0" filetype = "1.2.0" flatbuffers = "24.3.25" flatdict = "4.0.1" frozenlist = "1.4.1" fsspec = "2024.9.0" google-api-core = "2.19.2" google-auth = "2.34.0" google-cloud = "0.34.0" google-cloud-bigquery = "3.25.0" google-cloud-core = "2.4.1" google-crc32c = "1.6.0" google-resumable-media = "2.7.2" googleapis-common-protos = "1.65.0" grpcio = "1.66.1" grpcio-status = "1.62.3" h11 = "0.14.0" httpcore = "1.0.5" httptools = "0.6.1" httpx = "0.27.2" huggingface-hub = "0.24.7" humanfriendly = "10.0" idna = "3.10" importlib-metadata = "8.4.0" importlib-resources = "6.4.5" jsonpatch = "1.33" jsonpointer = "3.0.0" kubernetes = "30.1.0" langchain = "0.3.0" langchain-core = "0.3.0" langchain-text-splitters = "0.3.0" langsmith = "0.1.120" lazify = "0.4.0" literalai = "0.0.607" loguru = "0.7.2" lxml = "5.3.0" markdown-it-py = "3.0.0" marshmallow = "3.22.0" mdurl = "0.1.2" mmh3 = "4.1.0" monotonic = "1.6" mpmath = "1.3.0" multidict = "6.1.0" mypy-extensions = "1.0.0" mysql-connector-python = "9.0.0" nest-asyncio = "1.6.0" numpy = "1.26.4" oauthlib = "3.2.2" onnxruntime = "1.19.2" openpyxl = "3.1.5" oracledb = "^2.4.1" orjson = "3.10.7" overrides = "7.7.0" packaging = "23.2" pillow = "10.4.0" posthog = "3.6.5" proto-plus = "1.24.0" protobuf = "4.25.4" psycopg2-binary = "2.9.9" pyasn1 = "0.6.1" pyasn1-modules = "0.4.1" pycparser = "2.22" pydantic = "2.9.1" pydantic-settings = "2.5.2" pydantic-core = "2.23.3" pygments = "2.18.0" pyjwt = "2.9.0" pymupdf = "1.24.10" pymupdfb = "1.24.10" pymysql = "1.1.1" pypika = "0.48.9" pyproject-hooks = "1.1.0" python-dateutil = "2.9.0.post0" python-dotenv = "1.0.1" python-engineio = "4.9.1" python-multipart = "0.0.9" python-pptx = "1.0.2" python-socketio = "5.11.4" pytz = "2024.2" pyyaml = "6.0.2" requests = "2.32.3" requests-oauthlib = "2.0.0" rich = "13.8.1" rsa = "4.9" setuptools = "75.0.0" shellingham = "1.5.4" simple-websocket = "1.0.0" six = "1.16.0" sniffio = "1.3.1" soupsieve = "2.6" speechrecognition = "3.10.4" splunk-sdk = "2.0.2" sqlalchemy = "2.0.34" sqlparse = "0.5.1" sqlvalidator = "0.0.20" starlette = "0.37.2" sympy = "1.13.2" syncer = "2.0.3" tenacity = "8.5.0" textract = "1.5.0" tokenizers = "0.20.0" tomark = "0.1.4" tomli = "2.0.1" tqdm = "4.66.5" typer = "0.12.5" typing-inspect = "0.9.0" typing-extensions = "4.12.2" tzlocal = "5.2" uptrace = "1.26.0" urllib3 = "2.2.3" uvicorn = "0.25.0" uvloop = "0.20.0" watchfiles = "0.20.0" websocket-client = "1.8.0" websockets = "13.0.1" wrapt = "1.16.0" wsproto = "1.2.0" xlrd = "2.0.1" xlsxwriter = "3.2.0" xmltodict = "0.13.0" yarl = "1.11.1" zipp = "3.20.2" pymongo = "4.8.0" poetry = "^1.8.3" pre-commit = "^3.8.0" codespell = "^2.3.0" flake8 = "^7.1.1" pep8-naming = "^0.14.1" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" ================================================ FILE: requirements.txt ================================================ aiofiles==23.2.1 aiohappyeyeballs==2.4.0 aiohttp==3.10.5 aiosignal==1.3.1 annotated-types==0.7.0 anyio==4.4.0 APScheduler==3.10.4 argcomplete==3.5.0 asgiref==3.8.1 asyncer==0.0.7 attrs==24.2.0 backoff==2.2.1 bcrypt==4.2.0 beautifulsoup4==4.12.3 bidict==0.23.1 build==1.2.2 cachetools==5.5.0 certifi==2024.8.30 cffi==1.17.1 chainlit==1.1.404 chardet==5.2.0 charset-normalizer==3.3.2 chevron==0.14.0 chroma-hnswlib==0.7.6 chromadb==0.5.5 click==8.1.7 coloredlogs==15.0.1 cryptography==43.0.1 dependency-injector==4.42.0 Deprecated==1.2.14 deprecation==2.1.0 docx2txt==0.8 EbookLib==0.18 et-xmlfile==1.1.0 fastapi==0.110.3 filelock==3.16.0 filetype==1.2.0 flatbuffers==24.3.25 flatdict==4.0.1 frozenlist==1.4.1 fsspec==2024.9.0 google-api-core==2.19.2 google-auth==2.34.0 google-cloud==0.34.0 google-cloud-bigquery==3.25.0 google-cloud-core==2.4.1 google-crc32c==1.6.0 google-resumable-media==2.7.2 googleapis-common-protos==1.65.0 grpcio==1.66.1 grpcio-status==1.62.3 h11==0.14.0 httpcore==1.0.5 httptools==0.6.1 httpx==0.27.2 huggingface-hub==0.24.7 humanfriendly==10.0 idna==3.10 importlib_metadata==8.4.0 importlib_resources==6.4.5 jsonpatch==1.33 jsonpointer==3.0.0 kubernetes==30.1.0 langchain==0.3.0 langchain-core==0.3.0 langchain-text-splitters==0.3.0 langsmith==0.1.120 Lazify==0.4.0 literalai==0.0.607 loguru==0.7.2 lxml==5.3.0 markdown-it-py==3.0.0 marshmallow==3.22.0 mdurl==0.1.2 mmh3==4.1.0 monotonic==1.6 mpmath==1.3.0 multidict==6.1.0 mypy-extensions==1.0.0 mysql-connector-python==9.0.0 nest-asyncio==1.6.0 numpy==1.26.4 oauthlib==3.2.2 onnxruntime==1.20.0 openpyxl==3.1.5 oracledb==2.4.1 orjson==3.10.7 overrides==7.7.0 packaging==23.2 pandas==2.2.3 pillow==10.4.0 posthog==3.6.5 proto-plus==1.24.0 psycopg2-binary==2.9.9 pyasn1==0.6.1 pyasn1_modules==0.4.1 pycparser==2.22 pydantic==2.9.1 pydantic-settings==2.5.2 pydantic_core==2.23.3 Pygments==2.18.0 PyJWT==2.9.0 PyMySQL==1.1.1 pyodbc==5.2.0 PyPika==0.48.9 pyproject_hooks==1.1.0 pytest==8.3.3 pytest-cov==5.0.0 python-dateutil==2.9.0.post0 python-dotenv==1.0.1 python-engineio==4.9.1 python-multipart==0.0.9 python-pptx==1.0.2 python-socketio==5.11.4 pytz==2024.2 PyYAML==6.0.2 requests==2.32.3 requests-oauthlib==2.0.0 rich==13.8.1 rsa==4.9 setuptools==75.0.0 shellingham==1.5.4 simple-websocket==1.0.0 six==1.16.0 sniffio==1.3.1 soupsieve==2.6 SpeechRecognition==3.10.4 splunk-sdk==2.0.2 SQLAlchemy==2.0.34 sqlparse==0.5.1 sqlvalidator==0.0.20 starlette==0.37.2 sympy==1.13.2 syncer==2.0.3 tenacity==8.5.0 textract==1.5.0 oracledb tokenizers==0.20.0 tomark==0.1.4 tomli==2.0.1 tqdm==4.66.5 typer==0.12.5 typing-inspect==0.9.0 typing_extensions==4.12.2 tzlocal==5.2 uptrace==1.26.0 urllib3==2.2.3 uvicorn==0.25.0 watchfiles==0.20.0 websocket-client==1.8.0 websockets==13.0.1 wrapt==1.16.0 wsproto==1.2.0 xlrd==2.0.1 XlsxWriter==3.2.0 xmltodict==0.13.0 yarl==1.11.1 zipp==3.20.2 pymongo==4.8.0 poetry==1.8.3 pre-commit==3.8.0 codespell==2.3.0 flake8==7.1.1 pep8-naming==0.14.1 uvloop==0.20.0; sys_platform != 'win32' Jinja2==3.1.4 docling==2.39.0 mariadb==1.1.12 rapidocr_onnxruntime==1.4.4 ================================================ FILE: setup.py ================================================ import os from setuptools import setup, find_packages def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() # Function to read requirements from requirements.txt def parse_requirements(filename): with open(filename, 'r') as f: return f.read().splitlines() setup( name='raggenie', version='0.0.1', author='sirocco ventures', author_email='info@siroccoventures.com', description='Raggenie is a platform for easy RAG building and integration.', long_description=open('README.md').read(), long_description_content_type='text/markdown', url="https://github.com/sirocco-ventures/raggenie", license='MIT', packages=find_packages(), install_requires=parse_requirements('requirements.txt'), # Pulls dependencies from requirements.txt ) ================================================ FILE: tests/README.md ================================================ ## Getting Started This project includes functional, integration, and unit testing using pytest. Tests are organized into separate folders based on their type, and a conftest.py file is used to manage shared configurations and fixtures. ### Project Structure - `functional/`: Contains functional tests (`test_*.py`). - `integration/`: Contains integration tests (`test_*.py`). - `unittest/`: Contains unit tests (`test_*.py`). ## Requirements - `pip install pytest pytest-cov` ### Running Tests - Run all tests: `pytest` - To run specific tests: - Functional tests: `pytest functional/` - Integration tests: `pytest integration/` - Unit tests: pytest `unittest/` ### Test Coverage To measure test coverage using pytest-cov: - Run tests with coverage: `pytest --cov=.` - To view detailed missing line coverage in the terminal: `pytest --cov=. --cov-report=term-missing` - To generate an HTML coverage report: `pytest --cov=. --cov-report=term-missing --cov-report=html` ### Configuration Test configurations and database setups are defined in conftest.py. The test environment uses SQLite for isolated testing. ================================================ FILE: tests/__init__.py ================================================ ================================================ FILE: tests/conftest.py ================================================ from typing import Generator, Any import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import Session from app.models.provider import Provider from app.utils.database import Base from app.utils.database import get_db from app.api.v1.provider import router from app.api.v1.llmchat import chat_router from app.api.v1.connector import router as ConnectorRouter from app.api.v1.connector import cap_router as capabilityrouter from app.api.v1.connector import inference_router as inference_router from app.api.v1.connector import actions as actions from app.api.v1.main_router import MainRouter from app.api.v1.provider import sample as sample_sql # Function to initialize the FastAPI application with all necessary routers def start_application() -> FastAPI: app = FastAPI() app.include_router(MainRouter, prefix="/api/v1/query") app.include_router(router, prefix="/api/v1/provider") app.include_router(chat_router, prefix="/api/v1/chat") app.include_router(capabilityrouter, prefix="/api/v1/capability") app.include_router(inference_router, prefix="/api/v1/inference") app.include_router(ConnectorRouter, prefix="/api/v1/connector") app.include_router(actions, prefix="/api/v1/actions") app.include_router(sample_sql, prefix="/api/v1/sql") return app # Database URL for testing with SQLite SQLALCHEMY_DATABASE_URL = "sqlite:///./test_db.db" # Create a SQLAlchemy engine for testing engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}) SessionTesting = sessionmaker(autocommit=False, autoflush=False, bind=engine) # Fixture to create a fresh database for each test case @pytest.fixture(scope="function") def app() -> Generator[FastAPI, None, None]: """ Create a fresh database on each test case. """ Base.metadata.create_all(engine) # Create the database tables _app = start_application() # Initialize the FastAPI application yield _app # Yield the application instance for use in tests Base.metadata.drop_all(engine) # Drop the database tables after tests # Fixture to manage database sessions for tests @pytest.fixture(scope="function") def db_session(app: FastAPI) -> Generator[Session, None, None]: # Connect to the database and begin a transaction for testing connection = engine.connect() transaction = connection.begin() session = SessionTesting(bind=connection) # Create a new session yield session # Yield the session for use in tests session.close() # Close the session after tests transaction.rollback() # Roll back the transaction to maintain isolation connection.close() # Close the database connection # Fixture to create a FastAPI TestClient for sending requests in tests @pytest.fixture(scope="function") def client(app: FastAPI, db_session: Session) -> Generator[TestClient, None, None]: """ Create a new FastAPI TestClient that uses the `db_session` fixture to override the `get_db` dependency that is injected into routes. """ # Override the get_db dependency to use the test database session def _get_test_db(): try: yield db_session # Yield the test database session finally: pass app.dependency_overrides[get_db] = _get_test_db # Apply the dependency override with TestClient(app) as client: yield client # Yield the TestClient for use in tests # Fixture to create a sample Provider for testing @pytest.fixture def provider_fixture(db_session: Session) -> Provider: # Sample provider data for creating a Provider instance provider_data = { "name": "website provider", "description": "Provider for website connectors", "enable": True, "icon": "website.png", "category_id": 1, "key": "website", } new_provider = Provider(**provider_data) # Create a new Provider instance db_session.add(new_provider) # Add the provider to the session db_session.commit() # Commit the session to save the provider db_session.refresh(new_provider) # Refresh the provider instance to get updated data return new_provider # Return the created Provider instance ================================================ FILE: tests/functional/test_commons.py ================================================ ================================================ FILE: tests/functional/test_connectors.py ================================================ import pytest from unittest.mock import patch from fastapi.testclient import TestClient # Use the pytest fixture for the FastAPI test client @pytest.mark.usefixtures("client") class TestConnectorAPI: # Parameterized test for listing connectors @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: valid connector data returned ([{"id": 1, "name": "Connector A"}], None, { "status": True, "status_code": 200, "data": {"connectors": [{"id": 1, "name": "Connector A"}]}, "message": "Connectors Found", "error": None }, 200), # Empty connector case: no connectors found ([], None, { "status": True, "status_code": 200, "data": {"connectors": []}, "message": "Connector Not Found", "error": "Not Found" }, 200), # Database error case: simulate a database error ("DB Error", "DB Error", { "status": False, "status_code": 422, "data": {"connectors": []}, "message": "DB Error", "error": "DB Error" }, 200) ] ) @patch('app.services.connector.list_connectors') def test_list_connectors(self, mock_list_connectors, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Mock the list_connectors service to return the specified value and error mock_list_connectors.return_value = (mock_return_value, error) # Make a GET request to the list connectors endpoint response = client.get("/api/v1/connector/list") # Assert the response status code and content assert response.status_code == expected_status_code assert response.json() == expected_response # Parameterized test for getting a specific connector @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: valid connector data returned ({"id": 1, "name": "Connector A"}, None, { "status": True, "status_code": 200, "data": {"connector": {"id": 1, "name": "Connector A"}}, "message": "Connector Found", "error": None }, 200), # Connector not found case: empty response ({}, None, { "status": True, "status_code": 200, "data": {"connector": {}}, "message": "Connector Not Found", "error": "Not Found" }, 200), # Database error case: simulate a database error ("DB Error", "DB Error", { "status": False, "status_code": 422, "data": {"connector": {}}, "message": "DB Error", "error": "DB Error" }, 200) ] ) @patch('app.services.connector.get_connector') def test_get_connector(self, mock_get_connector, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Mock the get_connector service to return the specified value and error mock_get_connector.return_value = (mock_return_value, error) # Make a GET request to the get connector endpoint response = client.get("/api/v1/connector/get/1") # Assert the response status code and content assert response.status_code == expected_status_code assert response.json() == expected_response # Parameterized test for creating a new connector @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: valid connector creation ({"id": 1, "name": "Connector A", "type": 1, "config": {"type": "Config A"}}, None, { "status": True, "status_code": 201, "data": {"connector": {"id": 1, "name": "Connector A", "type": 1, "config": {"type": "Config A"}}}, "message": "Connector Created", "error": None }, 200), # Database error case: simulate a database error ("DB Error", "DB Error", { "status": False, "status_code": 422, "data": {"connector": {}}, "message": "Connector Not Created", "error": "DB Error" }, 200) ] ) @patch('app.services.connector.create_connector') def test_create_connector(self, mock_create_connector, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Mock the create_connector service to return the specified value and error mock_create_connector.return_value = (mock_return_value, error) # Make a POST request to the create connector endpoint with the connector data response = client.post("/api/v1/connector/create", json={ "name": "Connector A", "connector_type": 1, "connector_name": "Connector A", "connector_config": {"type": "Config A"} }) # Assert the response status code and content assert response.status_code == expected_status_code assert response.json() == expected_response # Parameterized test for updating an existing connector @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: valid connector updated ({"id": 1, "name": "Connector A"}, None, { "status": True, "status_code": 200, "data": {"connector": {"id": 1, "name": "Connector A"}}, "message": "Connector Updated", "error": None }, 200), # Connector not found case: no connector returned (None, None, { "status": True, "status_code": 200, "data": {"connector": {}}, "message": "Connector Not Found", "error": "Not Found" }, 200), # Database error case: simulate a database error ("DB Error", "DB Error", { "status": False, "status_code": 422, "data": {"connector": {}}, "message": "DB Error", "error": "DB Error" }, 200) ] ) @patch('app.services.connector.update_connector') def test_update_connector(self, mock_update_connector, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Mock the update_connector service to return the specified value and error mock_update_connector.return_value = (mock_return_value, error) # Make a POST request to the update connector endpoint with the updated data response = client.post("/api/v1/connector/update/1", json={"name": "Connector A"}) # Assert the response status code and content assert response.status_code == expected_status_code assert response.json() == expected_response # Parameterized test for deleting a connector @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: valid connector deleted ({"id": 1, "name": "Connector A"}, None, { "status": True, "status_code": 200, "data": {"connector": {"id": 1, "name": "Connector A"}}, "message": "Connector Deleted", "error": None }, 200), # Connector not found case: no connector returned (None, None, { "status": True, "status_code": 200, "data": {"connector": {}}, "message": "Connector Not Found", "error": "Not Found" }, 200), # Database error case: simulate a database error ("DB Error", "DB Error", { "status": False, "status_code": 422, "data": {"connector": {}}, "message": "DB Error", "error": "DB Error" }, 200) ] ) @patch('app.services.connector.delete_connector') def test_delete_connector(self, mock_delete_connector, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Mock the delete_connector service to return the specified value and error mock_delete_connector.return_value = (mock_return_value, error) # Make a DELETE request to the delete connector endpoint response = client.delete("/api/v1/connector/delete/1") # Assert the response status code and content assert response.status_code == expected_status_code assert response.json() == expected_response # Parameterized test for the update_schemas function @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case ({"id": 1, "schema_config": [{"key": "value"}]}, None, { "status": True, "status_code": 200, "data": {"schemas": {"id": 1, "schema_config": [{"key": "value"}]}}, "message": "Schema Updated", "error": None }, 200), # Connector not found case (None, None, { "status": True, "status_code": 200, "data": {"schemas": {}}, "message": "Connector Not Found", "error": "Not Found" }, 200), # Database error case ("DB Error", "DB Error", { "status": False, "status_code": 422, "data": {"schemas": {}}, "message": "DB Error", "error": "DB Error" }, 200) ] ) @patch('app.services.connector.updateschemas') # Mock the updateschemas function def test_update_schemas(self, mock_updateschemas, client: TestClient, mock_return_value, error, expected_response, expected_status_code): mock_updateschemas.return_value = (mock_return_value, error) # Set mock return value # Make a POST request to update schemas response = client.post("/api/v1/connector/schema/update/1", json={ "schema_config": [{"key": "value"}] }) # Assert the status code and response JSON assert response.status_code == expected_status_code assert response.json() == expected_response # Parameterized test for the list_configurations function @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case ([{"id": 1, "name": "Config A"}], None, { "status": True, "status_code": 200, "message": "Configurations retrieved successfully", "error": None, "data": {"configurations": [{"id": 1, "name": "Config A"}]} }, 200), # No configurations found case ([], None, { "status": True, "status_code": 200, "message": "Configurations Not Found", "error": "Not Found", "data": {"configurations": []} }, 200), # Database error case ("DB error", "DB error", { "status": False, "status_code": 422, "message": "DB error", "error": "DB error", "data": {"configurations": []} }, 200) ] ) @patch('app.services.connector.list_configurations') # Mock the list_configurations function def test_list_configurations(self, mock_list_configurations, client: TestClient, mock_return_value, error, expected_response, expected_status_code): mock_list_configurations.return_value = (mock_return_value, error) # Set mock return value # Make a GET request to list configurations response = client.get("/api/v1/connector/configuration/list") # Assert the status code and response JSON assert response.status_code == expected_status_code assert response.json() == expected_response # Parameterized test for the create_configuration function @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case ({"id": 1, "name": "Config A"}, None, { "status": True, "status_code": 201, "message": "Configuration created successfully", "error": None, "data": {"configuration": {"id": 1, "name": "Config A"}} }, 200), # Database error case ("DB error", "DB error", { "status": False, "status_code": 422, "message": "DB error", "error": "DB error", "data": {"configuration": []} }, 200) ] ) @patch('app.services.connector.create_configuration') # Mock the create_configuration function def test_create_configuration(self, mock_create_configuration, client: TestClient, mock_return_value, error, expected_response, expected_status_code): mock_create_configuration.return_value = (mock_return_value, error) # Set mock return value # Make a POST request to create a new configuration response = client.post("/api/v1/connector/configuration/create", json={ "name": "Config A", "short_description": "Short description", "long_description": "Long description", "status": 1, "capabilities": [1, 2] }) # Assert the status code and response JSON assert response.status_code == expected_status_code assert response.json() == expected_response # Parameterized test for the update_configuration function @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case ({"id": 1, "name": "Config A"}, None, { "status": True, "status_code": 200, "message": "Configuration updated successfully", "error": None, "data": {"configuration": {"id": 1, "name": "Config A"}} }, 200), # Database error case ("DB error", "DB error", { "status": False, "status_code": 422, "message": "DB error", "error": "DB error", "data": {"configuration": []} }, 200) ] ) @patch('app.services.connector.update_configuration') # Mock the update_configuration function def test_update_configuration(self, mock_update_configuration, client: TestClient, mock_return_value, error, expected_response, expected_status_code): mock_update_configuration.return_value = (mock_return_value, error) # Set mock return value # Make a POST request to update a configuration response = client.post("/api/v1/connector/configuration/update/1", json={ "name": "Config A Updated", "short_description": "Updated short description", "long_description": "Updated long description", "status": 1 }) # Assert the status code and response JSON assert response.status_code == expected_status_code assert response.json() == expected_response @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: A capability is created successfully ({"id": 1, "name": "Capability A"}, None, { "status": True, "status_code": 201, "message": "Capabilities created successfully", "error": None, "data": {"capability": {"id": 1, "name": "Capability A"}} }, 200), # Database error case: Simulating a database error during capability creation ("DB error", "DB error", { "status": False, "status_code": 422, "message": "DB error", "error": "DB error", "data": {"capability": {}} }, 200) ] ) @patch('app.services.connector.create_capabilities') def test_create_capability(self, mock_create_capabilities, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Mock the create_capabilities function to return the specified mock_return_value and error mock_create_capabilities.return_value = (mock_return_value, error) # Send a POST request to create a new capability response = client.post("/api/v1/capability/create", json={ "name": "Capability A", "description": "Description for Capability A", "requirements": [{"key": "value"}] }) # Assert that the response status code and JSON match the expected values assert response.status_code == expected_status_code assert response.json() == expected_response @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: List of capabilities is retrieved successfully ([{"id": 1, "name": "Capability A"}], None, { "status": True, "status_code": 200, "message": "Capabilities retrieved successfully", "error": None, "data": {"capabilities": [{"id": 1, "name": "Capability A"}]} }, 200), # Database error case: Simulating a database error while retrieving capabilities ("DB error", "DB error", { "status": False, "status_code": 422, "message": "DB error", "error": "DB error", "data": {"capabilities": []} }, 200), # Not found case: No capabilities are found ([], None, { "status": True, "status_code": 200, "message": "Capabilities Not Found", "error": "Not Found", "data": {"capabilities": []} }, 200) ] ) @patch('app.services.connector.get_all_capabilities') def test_list_capabilities(self, mock_get_all_capabilities, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Mock the get_all_capabilities function to return the specified mock_return_value and error mock_get_all_capabilities.return_value = (mock_return_value, error) # Send a GET request to retrieve all capabilities response = client.get("/api/v1/capability/all") # Assert that the response status code and JSON match the expected values assert response.status_code == expected_status_code assert response.json() == expected_response @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: A capability is updated successfully ({"id": 1, "name": "Capability A Updated"}, None, { "status": True, "status_code": 200, "message": "Capability updated successfully", "error": None, "data": {"capability": {"id": 1, "name": "Capability A Updated"}} }, 200), # Database error case: Simulating a database error during capability update ("DB error", "DB error", { "status": False, "status_code": 422, "message": "DB error", "error": "DB error", "data": {"capability": {}} }, 200), # Not found case: Capability not found during update (None, None, { "status": True, "status_code": 200, "message": "Capability Not Found", "error": "Not Found", "data": {"capability": {}} }, 200) ] ) @patch('app.services.connector.update_capability') def test_update_capability(self, mock_update_capability, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Mock the update_capability function to return the specified mock_return_value and error mock_update_capability.return_value = (mock_return_value, error) # Send a POST request to update a capability response = client.post("/api/v1/capability/update/1", json={ "name": "Capability A Updated", "description": "Updated description", "requirements": [{"key": "new_value"}] }) # Assert that the response status code and JSON match the expected values assert response.status_code == expected_status_code assert response.json() == expected_response @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: A capability is deleted successfully ({"id": 1, "name": "Capability"}, None, { "status": True, "status_code": 200, "message": "Capability deleted successfully", "error": None, "data": {"capability": {}} }, 200), # Database error case: Simulating a database error during capability deletion ("DB error", "DB error", { "status": False, "status_code": 422, "message": "DB error", "error": "DB error", "data": {"capability": {}} }, 200), # Not found case: Capability not found during deletion (None, None, { "status": True, "status_code": 200, "message": "Capability Not Found", "error": "Not Found", "data": {"capability": {}} }, 200) ] ) @patch('app.services.connector.delete_capability') def test_delete_capability(self, mock_delete_capability, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Mock the delete_capability function to return the specified mock_return_value and error mock_delete_capability.return_value = (mock_return_value, error) # Send a DELETE request to delete a capability response = client.delete("/api/v1/capability/delete/1") # Assert that the response status code and JSON match the expected values assert response.status_code == expected_status_code assert response.json() == expected_response ================================================ FILE: tests/functional/test_llmchat.py ================================================ import pytest from unittest.mock import patch from fastapi.testclient import TestClient @pytest.mark.usefixtures("client") class TestLLMChat: # Fixture to provide a sample chat payload for tests @pytest.fixture def chat_payload(self): return { "chat_context_id": "context_1", "chat_query": "What is AI?", "chat_answer": {"response": "Artificial Intelligence"}, "chat_summary": "Summary", "user_id": 123, "primary_chat": True } # Fixture to provide a sample feedback payload for tests @pytest.fixture def feedback_payload(self): return { "chat_context_id": "context_1", "chat_id": 1, "feedback_status": 1, "feedback_json": {"feedback": "Good"} } # Test case for creating a chat @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ ({"chat_id": 1}, None, { "status": True, "status_code": 201, "message": "Chat created successfully", "data": {"chat": {"chat_id": 1}}, "error": None }, 200), ("DB Error", "DB Error", { "status": False, "status_code": 422, "message": "DB Error", "data": {"chat": {}}, "error": "DB Error" }, 200) ] ) @patch('app.services.llmchat.create_chat') # Mock the create_chat function def test_create_chat(self, mock_create_chat, client: TestClient, chat_payload, mock_return_value, error, expected_response, expected_status_code): mock_create_chat.return_value = (mock_return_value, error) # Set mock return values response = client.post("/api/v1/chat/create", json=chat_payload) # Make POST request # Assertions to verify the response status code and body assert response.status_code == expected_status_code assert response.json() == expected_response # Test case for creating feedback @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ ({"chat_id": 1}, None, { "status": True, "status_code": 200, "message": "Feedback updated successfully", "data": {"chat": {"chat_id": 1}}, "error": None }, 200), ("DB Error", "DB Error", { "status": False, "status_code": 422, "message": "DB Error", "data": {"chat": {}}, "error": "DB Error" }, 200), (None, None, { "status": True, "status_code": 200, "message": "Chat Not Found", "data": {"chat": {}}, "error": "Not Found" }, 200) ] ) @patch('app.services.llmchat.create_feedback') # Mock the create_feedback function def test_create_feedback(self, mock_create_feedback, client: TestClient, feedback_payload, mock_return_value, error, expected_response, expected_status_code): mock_create_feedback.return_value = (mock_return_value, error) # Set mock return values response = client.post("/api/v1/chat/feedback/create", json=feedback_payload) # Make POST request # Assertions to verify the response status code and body assert response.status_code == expected_status_code assert response.json() == expected_response # Test case for listing chats by context @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ ([{"key": "value"}], None, { "status": True, "status_code": 200, "message": "Primary chats found", "data": {"chats": [{"key": "value"}]}, "error": None }, 200), ([], None, { "status": True, "status_code": 200, "message": "Context Not found", "data": {"chats": []}, "error": "Not Found" }, 200), ("DB Error", "DB Error", { "status": False, "status_code": 422, "message": "DB Error", "data": {"chats": []}, "error": "DB Error" }, 200) ] ) @patch('app.services.llmchat.list_chats_by_context') # Mock the list_chats_by_context function def test_list_chats_by_context(self, mock_list_chats_by_context, client: TestClient, mock_return_value, error, expected_response, expected_status_code): mock_list_chats_by_context.return_value = (mock_return_value, error) # Set mock return values response = client.get("/api/v1/chat/list/context/all") # Make GET request # Assertions to verify the response status code and body assert response.status_code == expected_status_code assert response.json() == expected_response # Test case for getting chat by context ID @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ ([{"key": "value"}], None, { "status": True, "status_code": 200, "message": "Chat found", "data": {"chats": [{"key": "value"}]}, "error": None }, 200), ([], None, { "status": True, "status_code": 200, "message": "Chat not found", "data": {"chats": []}, "error": "Not Found" }, 200), ("DB Error", "DB Error", { "status": False, "status_code": 422, "message": "DB Error", "data": {"chats": []}, "error": "DB Error" }, 200) ] ) @patch('app.services.llmchat.list_all_chats_by_context_id') # Mock the list_all_chats_by_context_id function def test_get_chat_by_context(self, mock_list_all_chats_by_context_id, client: TestClient, mock_return_value, error, expected_response, expected_status_code): mock_list_all_chats_by_context_id.return_value = (mock_return_value, error) # Set mock return values response = client.get("/api/v1/chat/get/context_1") # Make GET request # Assertions to verify the response status code and body assert response.status_code == expected_status_code assert response.json() == expected_response ================================================ FILE: tests/functional/test_provider.py ================================================ import pytest from unittest.mock import patch from fastapi.testclient import TestClient from app.schemas.provider import CredentialsHelper # Use fixtures for client management in tests @pytest.mark.usefixtures("client") class TestProviderAPI: @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: provider found ([{"id": 1, "name": "Provider A"}], None, { "status": True, "status_code": 200, "data": {"providers": [{"id": 1, "name": "Provider A"}]}, "message": "Providers Found", "error": None }, 200), # Empty provider case: no providers found ([], None, { "status": True, "status_code": 200, "data": {"providers": []}, "message": "Providers Not Found", "error": "Not Found" }, 200), # Database error case: simulates a database error ("SQL Error", "DB error", { "status": False, "status_code": 422, "data": {"providers": []}, "message": "DB error", "error": "SQL Error" }, 200) ] ) @patch('app.services.provider.list_providers') # Mock the list_providers function def test_list_providers(self, mock_list_providers, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Set the mock return value for list_providers mock_list_providers.return_value = (mock_return_value, error) # Send a GET request to the endpoint response = client.get("/api/v1/provider/list") # Assert the status code and response data match expected values assert response.status_code == expected_status_code assert response.json() == expected_response @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: specific provider found ({"id": 1, "name": "Provider A"}, None, { "status": True, "status_code": 200, "data": {"provider": {"id": 1, "name": "Provider A"}}, "message": "Provider Found", "error": None }, 200), # Provider not found case: no provider data returned ({}, None, { "status": True, "status_code": 200, "data": {"provider": {}}, "message": "Providers Not Found", "error": "Not Found" }, 200), # Database error case: simulates a database error ("DB Error", "DB Error", { "status": False, "status_code": 422, "data": {"provider": {}}, "message": "DB error", "error": "DB Error" }, 200) ] ) @patch('app.services.provider.get_provider') # Mock the get_provider function def test_get_provider(self, mock_get_provider, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Set the mock return value for get_provider mock_get_provider.return_value = (mock_return_value, error) # Send a GET request to the endpoint for a specific provider response = client.get("/api/v1/provider/get/1") # Assert the status code and response data match expected values assert response.status_code == expected_status_code assert response.json() == expected_response @pytest.mark.parametrize( "mock_return_value, error, expected_response, expected_status_code", [ # Success case: credentials test passes (True, "Test Credentials successfully completed", { "status": True, "status_code": 200, "message": "Test Credentials successfully completed", "error": None, "data": None, }, 200), # Provider not found case: simulates provider not found (None, "Provider Not Found", { "status": False, "status_code": 422, "message": "Provider Not Found", "error": "Provider Not Found", "data": None, }, 200), # Failed to get provider configurations case (None, "Failed to get provider configurations", { "status": False, "status_code": 422, "message": "Failed to get provider configurations", "error": "Failed to get provider configurations", "data": None, }, 200), # Unsupported provider case: tests for unsupported provider response (None, "Unsupported Provider", { "status": False, "status_code": 422, "message": "Unsupported Provider", "error": "Unsupported Provider", "data": None, }, 200), # Missing required key case: checks for missing config key (None, "Missing required config key: key", { "status": False, "status_code": 422, "message": "Missing required config key: key", "error": "Missing required config key: key", "data": None, }, 200), # Failed to connect case: simulates a connection error during credentials testing (None, "Test Credentials Failed: Connection error", { "status": False, "status_code": 422, "message": "Test Credentials Failed: Connection error", "error": "Test Credentials Failed: Connection error", "data": None, }, 200), ] ) @patch('app.services.provider.test_credentials') # Mock the test_credentials function def test_test_connections(self, mock_test_credentials, client: TestClient, mock_return_value, error, expected_response, expected_status_code): # Set the mock return value for test_credentials mock_test_credentials.return_value = (mock_return_value, error) # Create credentials data using the CredentialsHelper credentials = CredentialsHelper(provider_config={"key": "value"}) # Send a POST request to test credentials response = client.post("/api/v1/provider/1/test-credentials", json=credentials.model_dump()) # Assert the status code and response data match expected values assert response.status_code == expected_status_code assert response.json() == expected_response @pytest.mark.parametrize( "mock_return_value, is_error, expected_response, expected_status_code", [ # Success case: LLM providers found ({"llm_providers": ["Provider A"]}, False, { "status": True, "status_code": 200, "message": "LLM providers found", "data": {"llm_providers": ["Provider A"]}, "error": None }, 200), # Not found case: no LLM providers returned (None, True, { "status": False, "status_code": 422, "message": "LLM providers not found", "data": None, "error": None }, 200), ] ) @patch('app.services.provider.getllmproviders') # Mock the getllmproviders function def test_getllmproviders(self, mock_getllmproviders, client: TestClient, mock_return_value, is_error, expected_response, expected_status_code): # Set the mock return value for getllmproviders mock_getllmproviders.return_value = (mock_return_value, is_error) # Send a GET request to fetch LLM providers response = client.get("/api/v1/provider/llmproviders") # Assert the status code and response data match expected values assert response.status_code == expected_status_code assert response.json() == expected_response ================================================ FILE: tests/integration/test_integration_connector.py ================================================ import pytest from fastapi.testclient import TestClient from sqlalchemy.orm import Session from app.models.connector import Connector from app.models.provider import Provider, ProviderConfig from unittest.mock import patch # Use pytest fixtures for client and database session management @pytest.mark.usefixtures("client", "db_session") class TestConnectorAPI: # Integration testing for creating a PDF-based connector @patch('app.repository.provider.get_config_types') # Mock the get_config_types function to return predefined values def test_create_connector_type_2(self, mock_get_config_types, client: TestClient, db_session: Session, provider_fixture: Provider): # Mocking the return value of get_config_types to simulate a response from the provider config mock_get_config_types.return_value = ( [ ProviderConfig(slug="website_url", field="website_url"), ], False ) # Prepare the connector data for the POST request connector_data = { "connector_type": provider_fixture.id, # Use the provider ID from the fixture "connector_name": "Test Website Connector", # Name of the connector "connector_description": "Connector for Website database", # Description of the connector "connector_config": { "website_url":"https://www.siroccoventures.com/" } } # Perform the POST request to create the connector response = client.post("/api/v1/connector/create", json=connector_data) # Check the response from the API response_data = response.json() # Get the JSON response data # Assert that the response status code is 200 (OK) assert response.status_code == 200 # Assert that the status in the response data is True assert response_data["status"] is True # Assert that the message indicates the connector was created assert response_data["message"] == "Connector Created" # Assert that the returned connector name matches the input data assert response_data["data"]["connector"]["connector_name"] == connector_data["connector_name"] # Assert that the returned connector type matches the provider ID assert response_data["data"]["connector"]["connector_type"] == provider_fixture.id # Verify that the connector has been created in the database created_connector = db_session.query(Connector).filter(Connector.connector_name == connector_data["connector_name"]).first() # Assert that the created connector is not None (it should exist in the database) assert created_connector is not None ================================================ FILE: tests/unittest/test_svc/test_svc_provider.py ================================================ from fastapi.testclient import TestClient from sqlalchemy.orm import Session from app.models.provider import Provider from app.api.v1.provider import router from app.services import provider as svc from app.schemas.provider import ProviderResp from unittest.mock import patch import pytest # Use the pytest fixture for client management @pytest.mark.usefixtures("client") class TestProviderAPI: # Test case for successfully retrieving a provider by ID @patch('app.services.provider.repo') # Mock the repository layer for the test def test_get_provider_success(self, mock_repo, db_session: Session): # Create a mock provider instance to simulate a successful database return provider = Provider( id=1, name="Test Provider", description="A test provider", enable=True, icon="icon.png", category_id=1, key="test_provider" ) provider.providerconfig = [] # Initialize an empty list for provider config # Set the mock return value for the repo method mock_repo.get_provider_by_id.return_value = (provider, False) # Call the service method to get the provider result, error = svc.get_provider(1, db_session) # Assertions to verify the correct behavior assert error is None # No error should occur assert isinstance(result, ProviderResp) # Result should be an instance of ProviderResp assert result.id == 1 # ID should match the mock provider's ID assert result.name == "Test Provider" # Name should match the mock provider's name # Test case for handling a database error when retrieving a provider @patch('app.services.provider.repo') # Mock the repository layer for the test def test_get_provider_db_error(self, mock_repo, db_session: Session): # Simulate a database error by returning None and an error message mock_repo.get_provider_by_id.return_value = (None, "DB Error") # Call the service method to get the provider result, error = svc.get_provider(1, db_session) # Assertions to verify the correct error handling assert error == "DB Error" # Error should match the simulated database error assert result is None # Result should be None due to the error # Test case for handling a case where a provider is not found @patch('app.services.provider.repo') # Mock the repository layer for the test def test_get_provider_not_found(self, mock_repo, db_session: Session): # Simulate a case where no provider is found by returning an empty dict and no error mock_repo.get_provider_by_id.return_value = ({}, None) # Call the service method to get the provider result, error = svc.get_provider(1, db_session) # Assertions to verify the correct handling of a not found case assert error is None # No error should occur assert result == {} # Result should be an empty dict ================================================ FILE: ui/.dockerignore ================================================ node_modules ================================================ FILE: ui/Dockerfile ================================================ FROM node:20-alpine AS build ARG BACKEND_URL WORKDIR /app COPY package.json ./ RUN npm install COPY . . ENV VITE_BACKEND_URL=$BACKEND_URL RUN npm run build FROM nginx:stable-alpine COPY --from=build /app/dist /usr/share/nginx/html COPY --from=build /app/dist-library /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 5000 # Start Nginx CMD ["nginx", "-g", "daemon off;"] ================================================ FILE: ui/README.md ================================================ # Ragginie Frontend ## Run Locally Clone the project ```bash git clone https://github.com/sirocco-ventures/raggenie ``` Go to the project directory ```bash cd raggenie/ui ``` Install dependencies ```bash npm install ``` Create a .env file add the following env variables ```env VITE_BACKEND_URL=${BACKEND_URL} ``` Start the server ```bash npm run dev ``` ================================================ FILE: ui/eslint.config.js ================================================ import globals from "globals"; import pluginJs from "@eslint/js"; import pluginReact from "eslint-plugin-react"; export default [ { files: ["**/*.{js,mjs,cjs,jsx}"] }, { languageOptions: { globals: globals.browser } }, pluginJs.configs.recommended, pluginReact.configs.flat.recommended, { "rules": { "no-console": "error", "no-multiple-empty-lines": "error", "react/react-in-jsx-scope": "off", "react/prop-types": "off", "react/jsx-uses-react": "off", } } ]; ================================================ FILE: ui/index.html ================================================ Raggenie
================================================ FILE: ui/jsconfig.json ================================================ { "compilerOptions": { "baseUrl": ".", "paths": { "src/*": ["./src/*"], } } } ================================================ FILE: ui/nginx.conf ================================================ server { listen 5000;server_name localhost; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } } ================================================ FILE: ui/package.json ================================================ { "name": "raggenie", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "vite build", "prebuild": "vite build --config vite.library.config.js", "lint": "eslint .", "preview": "vite preview", "test": "vitest" }, "dependencies": { "axios": "^1.7.2", "eslint": "^9.11.0", "react": "^18.3.1", "react-confirm-alert": "^2.0.0", "react-data-table-component": "^7.6.2", "react-dom": "^18.3.1", "react-hook-form": "^7.53.0", "react-icons": "^5.2.1", "react-markdown": "^9.0.1", "react-router-dom": "^6.24.1", "react-select": "^5.8.0", "react-syntax-highlighter": "^15.5.0", "react-toastify": "^10.0.5", "recharts": "^2.12.7", "styled-components": "^6.1.12", "uuid": "^10.0.0", "zustand": "^5.0.0-rc.2" }, "devDependencies": { "@testing-library/jest-dom": "^6.5.0", "@testing-library/react": "^16.0.1", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react-swc": "^3.5.0", "eslint-plugin-react": "^7.37.1", "jsdom": "^25.0.1", "vite": "^5.3.1", "vite-plugin-css-injected-by-js": "^3.5.2", "vitest": "^2.1.3" } } ================================================ FILE: ui/src/App.jsx ================================================ import MainRoute from './routes/MainRoute' function App() { return ( <> ) } export default App ================================================ FILE: ui/src/components/Breadcrumbs/Breadcrumbs.jsx ================================================ ================================================ FILE: ui/src/components/Breadcrumbs/Breadcrumbs.module.css ================================================ ================================================ FILE: ui/src/components/Button/Button.jsx ================================================ import style from "./Button.module.css" const Button = ({ children, buttonType="button", type = "solid", variant = "primary", className = "", ...props })=>{ return( ) } const BUTTON_TYPE = { SOLID: "solid", TRANSPARENT: "transparent" } const BUTTON_VARIANT = { PRIMARY: "primary", WARNING: "warning", DANGER: "danger", PRIMARY_SECONDARY: "primary-secondary", DANGER_SECONDARY: "danger-secondary", } export default Button export { BUTTON_TYPE, BUTTON_VARIANT} ================================================ FILE: ui/src/components/Button/Button.module.css ================================================ .Button { gap: 6px; display: inline-flex; padding: 3px 13px; text-align: left; border-radius: 4px; cursor: pointer; border: 0px; font-family: Inter; font-size: 16px; font-style: normal; font-weight: 400; line-height: 150%; align-content: center; align-items: center; } .Button:disabled { background: #C1C1C1; color: #888787; } .solid-primary { background: #3893FF; color : #FFF } .solid-primary:not(:disabled):hover { background: #84BCFF; color : #FFF } .solid-secondary { background: #ECF5FF;; color : #3893FF } .solid-secondary:not(:disabled):hover { background: #CDE5FF;; color : #3893FF; } .solid-danger { background: #FF7F6D; color : #FFF } .solid-danger:not(:disabled):hover { background: #FFB9AF; color : #FFF } .solid-secondary-danger { background: #FFF2F0;; color : #FF7F6D } .solid-secondary-danger:not(:disabled):hover { background: #FFDDD9; color : #FF7F6D; } /* transparent */ .transparent-primary { background-color: transparent !important; color: #3893FF; } .transparent-primary:not(:disabled):hover { color: #84BCFF;; } ================================================ FILE: ui/src/components/Button/Button.test.jsx ================================================ import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/react'; import Button, { BUTTON_TYPE, BUTTON_VARIANT } from './Button'; describe('Button', () => { it('renders with default props', () => { render(); const button = screen.getByRole('button', { name: /click me/i }); expect(button).toBeInTheDocument(); expect(button).toHaveAttribute('type', 'button'); expect(button.className).toContain('Button'); expect(button.className).toContain('solid-primary'); }); it('renders with custom type and variant', () => { render(); const button = screen.getByRole('button', { name: /warning/i }); expect(button).toHaveAttribute('type', 'button'); expect(button.className).toContain('Button'); expect(button.className).toContain('transparent-warning'); }); it('applies custom className', () => { render(); const button = screen.getByRole('button', { name: /custom/i }); expect(button).toHaveAttribute('type', 'button'); expect(button.className).toContain('Button'); expect(button.className).toContain('solid-primary'); expect(button.className).toContain('custom-class'); }); it('renders as submit button', () => { render(); const button = screen.getByRole('button', { name: /submit/i }); expect(button).toHaveAttribute('type', 'submit'); expect(button.className).toContain('Button'); expect(button.className).toContain('solid-primary'); }); it('renders with danger variant', () => { render(); const button = screen.getByRole('button', { name: /danger/i }); expect(button).toHaveAttribute('type', 'button'); expect(button.className).toContain('Button'); expect(button.className).toContain('solid-danger'); }); it('passes additional props to button element', () => { render(); const button = screen.getByRole('button', { name: /disabled/i }); expect(button).toBeDisabled(); expect(button).toHaveAttribute('type', 'button'); expect(button.className).toContain('Button'); expect(button.className).toContain('solid-primary'); }); }); ================================================ FILE: ui/src/components/Chart/AreaChart/AreaChart.jsx ================================================ import style from "../style.module.css"; import { AreaChart as ReAreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts'; function AreaChart({ title = "Area Chart", data = [], xAxis = "name", yAxis = "value"}, dataLength = 12) { return ( <>
{title}
} /> } />
); } const CustomTick = ({ x, y, payload, axis }) => { const commonProps = { color: "rgba(28, 28, 28, 0.40", textAlign: "center", opacity: "40%", fontFamily: "Inter", fontSize: "11px", fontStyle: "normal", fontWeight: "400", lineHeight: "18px", /* 180% */ }; return ( {payload.value} ); }; export default AreaChart; ================================================ FILE: ui/src/components/Chart/BarChart/BarChart.jsx ================================================ import { Bar, BarChart as ReBarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts" import style from "../style.module.css" const BarChart = ({title ="Bar Chart", data = [], xAxis = "name", yAxis = "value", dataLength = 12,})=>{ const customBar = (props)=>{ const {x, y, height } = props; return ( ) } const customAxisLabel = ({ payload, x, y, width, height })=>{ return( {payload.value} ) } return( <>
{title}
) } export default BarChart ================================================ FILE: ui/src/components/Chart/LineChart/LineChart.jsx ================================================ import { LineChart as ReLineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'; import style from "../style.module.css" const LineChart = ({title ="Line Chart", data = [], xAxis = "name", yAxis = "value", dataLength = 12})=>{ const customXAxisLabel = ({ payload, x, y, width, height })=>{ return( {payload.value} ) } const customYAxisLabel = ({ payload, x, y, width, height })=>{ return( {payload.value} ) } return( <>
{title}
) } export default LineChart ================================================ FILE: ui/src/components/Chart/PieChart/PieChart.jsx ================================================ import { PieChart as RePieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend } from 'recharts'; import style from '../style.module.css'; const COLORS = ['#3893FF', '#84BCFF', '#CDE5FF', '#FF8042']; const CustomLegend = (props) => { const { payload, label } = props; return (
{payload.map((entry, index) => (
{entry.payload[label]}
))}
); }; const PieChart = ({ title = "Pie Chart", data = [] , dataKey= "value", labelKey="label", dataLength = 12 }) => { return ( <>
{title}
{data.map((entry, index) => ( ))} } layout="vertical" align="right" verticalAlign="middle" wrapperStyle={{top: "0px", height: "200px", overflow: "auto"}} />
); }; export default PieChart; ================================================ FILE: ui/src/components/Chart/Table/Table.jsx ================================================ import style from "../style.module.css" const Table = ({data = [], dataLength = 10})=>{ let tableHeader = []; const getTableHeader = ()=>{ if(data.length > 0){ let tempData = data[0]; let keys = Object.keys(tempData).map(item=>item.replaceAll("_", " ")); tableHeader = keys } } getTableHeader() return( <>
{tableHeader.map((item, index)=>)} {data?.slice(0, dataLength)?.map((item, dIndex)=>{ return( { Object.values((item)).map(value=>) } ) })}
{item}
{value}
) } export default Table ================================================ FILE: ui/src/components/Chart/style.module.css ================================================ .ChartContainer{ padding: 24px 24px; border-radius: 10px; background: #F5FAFF; width: fit-content; } .ChartTitle { display: block; color: #1C1C1C; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 500; line-height: 20px; margin-bottom: 20px; } .BarChartResponsive { margin-left: -25px; } .PieChartContainer{ padding: 24px; width: fit-content; height: auto; flex-shrink: 0; border-radius: 10px; background: #F5FAFF; } .PieChartTitle{ color: #1C1C1C; font-feature-settings: 'ss01' on, 'cv01' on, 'cv11' on; font-family: Inter; font-size: 18px; font-style: normal; font-weight: 400; line-height: 20px; /* 142.857% */ } .PieLegend{ display: flex; color: #888787; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: 20px; /* 166.667% */ margin-right: 100px; margin-bottom: 10px; } /* table style */ .ChartTableContainer { width: 500px; overflow: scroll; } .ChatTable tr th, .ChatTable tr th td{ padding: 5.5px 12px; font-family: Inter; font-size: 11px; font-style: normal; font-weight: 600; } .ChatTable tr th{ background: #84BCFF; color: #FFFFFF; text-transform: uppercase; } .ChatTable tr th:nth-child(1) { border-radius: 10px 0px 0px 0px; } .ChatTable, tr th:last-child { border-radius: 0px 10px 0px 0px; } .ChatTable tr td { background-color: #F5FAFF; color: #323232; padding-left: 10px; border-bottom: 1px #EFEFEF solid; padding: 9px 10px; } .ChatTable tr:last-child td { border-bottom: 0px; } ================================================ FILE: ui/src/components/ChatBox/ChatBox.jsx ================================================ import { forwardRef, useEffect, useRef } from "react" import style from "./ChatBox.module.css" import Message from "./Message" import Loader from "./Loader" import ChatHistorySideBar from "./ChatHistorySideBar" const ChatBox = forwardRef(({messageBoxRef = null, handleNavigateChatContext=()=>{}, onCreateNewChat=()=>{}, chatHistory=[], isLoading = false, onFeedBackSubmit=()=>{}, conversations = [], onKeyDown = ()=>{}, onKeyUp = ()=>{}, onSendClick = ()=>{}, onLike = ()=>{} , onDisLike = ()=>{} }, ref)=>{ const chatListRef = useRef(null) const handleOnLikeClick = (e, feedbackStatus, feedbackMessage, message)=>{ onLike(e, feedbackStatus, feedbackMessage, message) } const handleOnDisLikeClick = (e,message)=>{ onDisLike(message) } const toggleContainer = (e, setIsHidden) => { setIsHidden(prev => !prev); }; useEffect(()=>{ document.querySelector("#messageBody").scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" }); },[conversations]) return( <>
{ conversations.map((message, index) => { return }) } {isLoading && }

RAG Builder may display inaccurate info, including about people, so double-check its responses.

toggleContainer(e, setIsHidden)}/>
) }) export default ChatBox ================================================ FILE: ui/src/components/ChatBox/ChatBox.module.css ================================================ /* Chatbox.jsx */ .ChatBoxContainer { display: flex; height: 100%; overflow: hidden; /* background-color: red; */ } .ChatMessagesContainer{ flex-grow: 1; padding-left: 39px; padding-right: 39px; display: flex; flex-direction: column; height: 100%; } .ChatMessageContainer { flex-grow: 1; /* background-color: blue; */ overflow: scroll; } .ChatMessageContainer p { margin: 0px; } .ChatMessageContainer::-webkit-scrollbar { display: none; } .ChatMessageContainer { -ms-overflow-style: none; scrollbar-width: none; } .ChatBoxTextContainer { display: flex; padding: 8px 8px; align-items: center; gap: 16px; flex-shrink: 0; border-radius: 180px; border: 1px solid #E0E0E0; background: #FFF; outline: none; margin-bottom: 22px; } .ChatBoxTextBox { flex-grow: 1; padding: 0px 10px; max-height: 54px; overflow: scroll; overflow: hidden; color: #888787; text-overflow: ellipsis; font-family: Inter; font-size: 16px; font-style: normal; font-weight: 400; line-height: 24px; } .ChatBoxTextBox::-webkit-scrollbar { display: none; } .ChatBoxTextBox { -ms-overflow-style: none; scrollbar-width: none; } .ChatBoxTextBox:focus{ outline: none; } .ChatBoxTextContainer:has(.ChatBoxTextBox:hover) { border-color: #3893FF; } .ChatBoxSendIcon { background: url(/src/components/ChatBox/assets/send-icon.svg); width: 42px; height: 42px; background-repeat: no-repeat; background-color: #F9F9F9; border-radius: 180px; background-position: 12px 10px; cursor: pointer; } .ChatBoxTextBox:hover + div .ChatBoxSendIcon{ background-color: #ECF5FF !important; background: url(/src/components/ChatBox/assets/send-icon-active.svg); background-repeat: no-repeat; background-position: 12px 10px; } .ChatBottomMessage { text-align:center; margin-bottom: 29px; } /* Message.jsx */ .MessageContainer { border-radius: 10px; padding: 12px 16px; margin: 15px 0px; color: #151414; font-family: Inter; font-size: 16px; font-style: normal; font-weight: 400; line-height: 150%; } .UserMessageContainer { display: flex; justify-content: end; gap: 12px; } .BotMessageContainer { display: flex; justify-content: start; gap: 8px; } .UserMessage { border-radius: 10px; background: #F1F1F1;; color: #323232; } .BotMessage { border-radius: 10px; } .BotMessage p { color: #323232; font-size: 14px; } .MessageAvatar { margin-top: 20px; } /* loader */ .Loader { text-align: center; width: fit-content; margin-left: 10px; padding-bottom: 10px; } .Loader span { display: inline-block; vertical-align: middle; width: 10px; height: 10px; background: grey; border-radius: 50px; -webkit-animation: loader 0.5s infinite alternate; -moz-animation: loader 0.5s infinite alternate; margin-right: 4px; } .Loader span:nth-of-type(2) { -webkit-animation-delay: 0.2s; -moz-animation-delay: 0.2s; } .Loader span:nth-of-type(3) { -webkit-animation-delay: 0.3s; -moz-animation-delay: 0.3s; } @-webkit-keyframes loader { 0% { height: 10px; opacity: 0.9; -webkit-transform: translateY(0); } 100% { opacity: 0.3; -webkit-transform: translateY(-11px); } } @-moz-keyframes loader { 0% { width: 10px; height: 10px; opacity: 0.9; -moz-transform: translateY(0); } 100% { width: 24px; height: 24px; opacity: 0.3; -moz-transform: translateY(-11px); } } /* Time CSS */ .MessageExtraInfo{ margin-top: 3px; margin-left: 0px; } .Timelabel{ font-family: Inter; font-size: 12px; font-weight: 400; line-height: 18px; text-align: left; color: #C8C8C8; width: 87px; height: 18px; gap: 0px; } .Timecontainer{ display: flex; justify-items: center; align-items: center; } .LikeIcon{ display: flex; width: Fixed (18px)px; height: auto; padding: 3px 13px 3px 13px; gap: 6px; border-radius: 4px 0px 0px 0px; opacity: 0px; } .LikeButton { outline: none; display: flex; width: auto; justify-content: center; align-items: center; gap: 6px; padding: 0 3px; border-radius: 4px; background: #F0F0F0; border: none; cursor: pointer; position: relative; } .LikeButton.Activeliked { background: #ECF5FF; } .LikeButton:hover { background: #ECF5FF; } .LikeButton::before { content: url('./assets/like-icon.svg'); transition: content 0.3s; } .LikeButton.Activeliked::before { content: url('./assets/like-hover.svg'); } .LikeButton:hover::before { content: url('./assets/like-hover.svg'); } .DislikeButton { outline: none; display: flex; width: auto; justify-content: center; align-items: center; gap: 6px; padding-left: 3px; padding-right: 3px; border-radius: 4px; background: #F0F0F0; border: none; cursor: pointer; position: relative; } .DislikeButton.ActiveDisliked{ background: #ECF5FF; } .DislikeButton:hover{ background: #ECF5FF; } .DislikeButton::before { content: url('./assets/dislke-icon.svg'); } .DislikeButton:hover::before { content: url('./assets/dislike-hover.svg'); } .DislikeButton.ActiveDisliked::before { content: url('./assets/dislike-hover.svg'); } /* Feedback popup */ .FeedbackCommet{ /* position: absolute; */ display: block; width: 401px; height: auto; padding: 10px; flex-direction: column; align-items: flex-start; gap: 10px; flex-shrink: 0; border-radius: var(--4, 4px); border: 1px solid #F0F0F0; background: var(--white-100, #FFF); margin-top: 20px; } .FeedbackCommetShow { display: block; } .FeedbackCommet h2{ color: #323232; font-family: Lato; font-size: 14px; font-style: normal; font-weight: 500; line-height: normal; font-family: Lato; font-size: 16px; font-style: normal; font-weight: 500; line-height: normal; margin-top: 5px; } .TitleHead{ display: flex; width: 100%; justify-content: space-between; } .imageBgRemove{ backface-visibility: hidden; } .CloseIconBtn{ background: none; outline: none; border: none; outline: navajowhite; cursor: pointer; } .SuggestedComment{ display: flex; gap: 8px; } .SuggestedComment > span{ /* display: flex; */ width: auto; height: 17px; padding: var(--4, 4px) var(--8, 8px); justify-content: center; align-items: center; gap: var(--8, 8px); border-radius: var(--4, 4px); border: 0px solid #64A25E; background: #ECF5FF; color: #74B3FF; font-family: Inter; font-size: 9px; font-style: normal; font-weight: 500; line-height: 20px; /* 222.222% */ cursor: pointer; } .FeedbackTextarea{ margin-top: 11px; margin-bottom: 6px; outline: none; resize: none; } .FeedbackButton { display: inline-flex; padding: 3px 13px; align-items: center; gap: 6px; display: inline-flex; padding: 3px 13px; align-items: center; gap: 6px; border-radius: var(--4, 4px); background: #3893FF; color: var(--white-100, #FFF); font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; line-height: 150%; /* 18px */ border: none; outline: none; } /* =======CHAT HISTORY======= */ .ButtonContainer{ width:auto; cursor: pointer; display: flex; padding: 20px 13px; align-items: center; gap: 6px; flex-shrink: 0; border-radius: var(--12, 12px) 0px 0px var(--12, 12px); background: #3893FF; } .ButtonContainer:hover{ background: #84BCFF; color: var(--white-100, #FFF); } .BotMessageContainer:focus{ background: #84BCFF; } .ChatHistoryText{ display: none; color: #FFF; /* Small text */ font-family: Inter; font-size: 16px; font-style: normal; font-weight: 500; line-height: 150%; /* 24px */ } .ButtonContainer:hover .ChatHistoryText{ display: flex; } .ButtonContainer:hover .ChatHistoryIcon { animation: rotateIcon 1s ease-in-out forwards; } @keyframes rotateIcon { 0% { transform: rotate(0deg); } 50% { transform: rotate(20deg); } 100% { transform: rotate(0deg); } } .ChatHistoryIcon{ margin-top: 5px; } /* ===========CHAT HISTORY SIDEBAR=========== */ .chatHistoryContainer { width: 356px; /* Start with the sidebar visible */ padding-right: 16px; /* Adjust padding as needed */ position: relative; box-sizing: border-box; background-color: #FFFFFF; border-left: 1px solid #F0F0F0; } .toggleContainer { animation: toggleDiv 0.8s forwards; } @keyframes toggleDiv { from { min-width: 356px; padding-right: 16px; } to { width: 0; padding-right: 0; } } .ChatNavBar { padding-right: 20px; padding-left: 20px; padding-top: 14px; padding-bottom: 14px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #F0F0F0; } .ChatNavBar h3 { color: #000; font-family: Inter; font-size: 16px; font-style: normal; font-weight: 500; line-height: 150%; /* 24px */ } .ChatNavBar button:last-child { cursor: pointer; border-radius: var(--4, 4px); background: #ECF5FF; padding: 3px 13px; display: inline-flex; align-items: center; gap: 6px; outline: none; border: none; border-radius: var(--4, 4px); background: #ECF5FF; color: #3893FF; /* Small text */ font-family: Inter; font-size: 16px; font-style: normal; font-weight: 500; line-height: 150%; /* 24px */ } .ChatNavBar button:last-child:hover { background-color: #CDE5FF; color: #3893FF; } .ChatNavBar button:last-child img { margin-top: 7px; } .ChatBarStyle { background-color: #FFFFFF; } .ChatHistoryContent { min-width: 93%; height: calc(100vh - 150px); overflow-y: scroll; padding: 27px 20px 20px 20px; } .ChatHistoryHeading { color: #5B5B5B; font-family: Inter; font-size: 16px; font-style: normal; font-weight: 500; line-height: 150%; /* 24px */ margin-bottom: 18px; } .RecentChats{ background: #FFF; display: inline-flex; width: 100%; gap: 10px; } .RecentMessage { color: #858585; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: 150%; } .HistoryArrowButton{ width: 20px; padding-top: 3px; padding-left: 2px; border-radius: 40px; text-align: center; height: 20px; cursor: pointer; border: 1px #84BCFF; background: #84BCFF; position: absolute; left: -12px; } .HistoryArrowButton:hover{ border: 1px #3893FF; background: #3893FF; } .HistoryArrowButton img{ width: 16px; } /* Chat Summary */ .SummaryContainer{ display: flex; flex-direction: column ; width: 401px; height: 20px; padding: 12px 13px; margin-top: 20px; border-radius: 8px; background: #F1F1F1; margin-bottom: 20px; overflow: hidden; } .SummaryContainer.SummaryContainerOpen { height: auto; } .SummartyHeader { display: flex; flex-direction: row; align-items: center; gap: 13px; cursor: pointer; } .SummaryToggleButton { border-radius: 4px; border: 0px; background: #F9F9F9; width: 18px; height: 18px; padding: 0px; cursor: pointer; padding-top: 3px; } .SummaryToggleIconOpen { content: url('./assets/summary-up.svg'); } .SummaryToggleIconClose { content: url('./assets/summary-down.svg'); } .SummaryHeaderTitle { color: #888787; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; margin: 0px; } .ChatSummayContainer { display: flex; flex-direction: column; margin: 20px 5px; margin-top: 25px; cursor: pointer; margin-bottom: 0px; } .ChatSQLSummary { color: #9EA1A4; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; line-height: normal; } .QueryTitle { color: #888787; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; line-height: 150%; margin-top: 25px; margin-bottom: 12px; } .QueryTitle::before, .QueryTitle::after { display: inline-block; content: ""; border-top: 1px solid #F9F9F9;; width: 38%; transform: translateY(-6px); } .QueryTitle::before { margin-right: 10px; } .QueryTitle::after { margin-left: 10px; } .QueryInnerTitle{ display: inline-flex; align-items: center; gap: 7px; } .SQLQueryOpen { margin-bottom: 12px; } .SQLQueryClose { display: none; } /* Chat Summary */ /* Error Message Style */ .ErrorContainer { width: 401px; border-radius: 4px; border: 1px solid #F0F0F0; background: #FFF; padding: 10px; } .ErrorHeaderContainer { display: flex; } .ErrorHeadingContainer{ flex-grow: 1; } .ErrorHeading { color: #323232; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 500; line-height: normal; margin: 0px; margin-bottom: 10px; } .ErrorCloseIcon { cursor: pointer; } .ErrorDescription { color: #858585; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; line-height: normal; margin-bottom: 23px !important; } .ErrorButtonAnchor { text-decoration: none; } .ErrorActionButton { border-radius: 4px; background: #ECF5FF; border: 0px; padding: 6px 13px; display: flex; align-items: center; gap: 8px; cursor: pointer; } .ErrorExpandButton { color: #323232; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 500; line-height: 140%; text-decoration-line: underline; cursor: pointer; } .MessageContainer p:has(+ .ErrorExpandButton){ display: inline-block; color: #FF7F6D; } .MessageContainer:has(> .ErrorExpandButton){ margin-top: 10px; } /* Error Message Style */ ================================================ FILE: ui/src/components/ChatBox/ChatDropdownMenu/ChatDropdownMenu.jsx ================================================ import {useEffect, useState } from 'react'; import style from './ChatDropdownMenu.module.css'; import arrowDown from '../assets/arrow-down.svg'; import arrowUp from '../assets/arrow-up.svg'; export default function ChatDropdownMenu({ handleNavigateChatContext = () => {}, data = [], showDropdownArrow = true }) { const [openDropdown, setOpenDropdown] = useState([]); const [showUpto, setShowUpto] = useState(4); // Start with 4 items visible const [isExpanded, setIsExpanded] = useState(false); // Track expansion const toggleDropdown = (index) => { if (index === 0) return; // Prevent toggling for index 0 setOpenDropdown((prevState) => prevState.includes(index) ? prevState.filter((i) => i !== index) : [...prevState, index] ); }; useEffect(() => { // Open all dropdowns except for index 0 on initial load const allIndexes = data.map((_, index) => index).filter((index) => index !== 0); setOpenDropdown([0, ...allIndexes]); }, [data]); if (data.length > 0) { data[0].title = 'Recent Chat'; } const toggleVisibility = (index, chatQuery = []) => { if (index === 0) { if (isExpanded) { setShowUpto(4); } else { setShowUpto(chatQuery.length); // Show all items on "See More" } setIsExpanded(!isExpanded); // Toggle expansion state } }; return (
{data.map((item, index) => (
toggleDropdown(index)} >

{item.title}

{index !== 0 && showDropdownArrow && (
arrowIcon
)}
    {item.chatQuery.slice(0, showUpto).map((chat, chatIndex) => (
  • handleNavigateChatContext(e, chat.contextId, chat.configId)}> {chat?.message}
  • ))}
{Array.isArray(item.chatQuery) && item.chatQuery.length > 4 && index === 0 && ( )}
))}
); } ================================================ FILE: ui/src/components/ChatBox/ChatDropdownMenu/ChatDropdownMenu.module.css ================================================ .ChatDropDown { display: flex; flex-direction: column; } .ChatDropDown h3 { flex-grow: 1; margin: 0; color: #5B5B5B; font-family: Inter; font-size: 16px; margin-bottom: 18px; font-style: normal; font-weight: 600; line-height: 150%; /* 24px */ } .ChatDropDown li { cursor: pointer; display: block; color: #858585; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: 150%; position: relative; padding-left: 36px; padding-right: 6px; padding-top: 9px; border-radius: 4px; padding-bottom: 9px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-bottom: 9px; } .ChatDropDown li:hover{ border-radius: 4px; background: #F0F0F0; } .ChatDropDown li:focus{ background: #D8D8D8; } .ChatDropDown li div { margin: 0; width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ChatDropDown ul { padding: 0; margin-top: 0; margin-left: 10px; width: 300px; } .ListOptions{ width: 100%; } .ChatDropDown li::before { content: ""; position: absolute; left: 6px; top: 56%; width: 20px; height: 20px; /* Adjust based on the size of the image */ background-image: url(../assets/message-history.svg); background-size: contain; background-repeat: no-repeat; background-position: center; transform: translateY(-50%); /* Centers the image vertically */ } .ChatHistoryHeadWithArrow { cursor: pointer; display: flex; gap: 8px; } .ChatHistoryHeadWithArrow img { padding-top: 2px; } .ActiveDropDown { height: auto; display: block; animation: slideUp 0.5s ease-in-out forwards; overflow: hidden; } .InActiveDropDown { overflow: hidden; animation: slideDown 0.5s ease-in-out forwards; /* Adjust duration and easing as needed */ } .SeeMoreDropDown{ display: flex; min-width: 295px; padding: var(--12, 12px) 6px; align-items: center; gap: 10px; border-radius: var(--4, 4px); border: 1px solid var(--white-100, #FFF); background: #ffffff; color: #858585; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; width: 295px; height: 30px; line-height: 150%; cursor: pointer; margin-bottom: 18px; /* 18px */ } .SeeMoreDropDown:hover{ background: #F0F0F0; } @keyframes slideDown { 0% { min-height:fit-content; opacity: 1; } 100% { max-height: 0; opacity: 0; } } @keyframes slideUp { 0% { min-height: 0; opacity: 0; } 100% { min-height:fit-content; opacity: 1; } } ================================================ FILE: ui/src/components/ChatBox/ChatHistoryButton.jsx ================================================ import style from './ChatBox.module.css' function ChatHistoryButton({icon,text, onClick = ()=>{}}) { return (
{text}
) } export default ChatHistoryButton ================================================ FILE: ui/src/components/ChatBox/ChatHistorySideBar.jsx ================================================ import { useRef, useState } from 'react' import style from "./ChatBox.module.css" import plusIcon from "./assets/plus-image.svg" import arrowRight from "./assets/arrow-right.svg" import ChatHistoryButton from "src/components/ChatBox/ChatHistoryButton" import Clock from "./assets/time-lap.svg" import ChatDropdownMenu from './ChatDropdownMenu/ChatDropdownMenu' function ChatHistorySideBar({handleNavigateChatContext=()=>{}, onCreateNewChat=()=>{}, onClick=()=> {}, chatHistory }) { const toggleHistoryRef = useRef(null) const [isHidden, setIsHidden] = useState(false); const showHideSideHistory = (e) => { onClick(e, setIsHidden) } const formatDate = (date) => { const options = { year: 'numeric', month: 'long' }; return new Date(date).toLocaleDateString('en-US', options); }; const formattedData = chatHistory.reduce((acc, chat) => { const { chatContextId, chatQuery, date, chatConfigurationId } = chat; // Format the date to "MONTH YEAR" const formattedDate = formatDate(date); // Initialize the entry if it doesn't exist if (!acc[formattedDate]) { acc[formattedDate] = { title: formattedDate, chatQuery: [] }; } // Add the message to the appropriate date group acc[formattedDate].chatQuery.push({ contextId: chatContextId, configId: chatConfigurationId, message: chatQuery }); return acc; }, {}); const resultArray = Object.values(formattedData); return ( <>
{isHidden ? <> : (
{showHideSideHistory(e) }}>
)}

Chat History

{isHidden ? ( { setIsHidden(!isHidden) }} icon={Clock} text={"History"} />) : null} ) } export default ChatHistorySideBar ================================================ FILE: ui/src/components/ChatBox/ErrorMessage.jsx ================================================ import { SLACK_URL } from "src/config/const" import slackIcon from "./assets/slack-icon.svg" import closeIcon from "./assets/error-close.svg" import style from './ChatBox.module.css' const ErrorMessage = ({ error = "", onClose = ()=>{}})=>{ return(

An unexpected error has occurred

{error}

) } export default ErrorMessage ================================================ FILE: ui/src/components/ChatBox/Feedback.jsx ================================================ import { useState } from 'react' import close from './assets/close-modal-icon.svg' import style from './ChatBox.module.css' function Feedback({ onSubmit=()=>{}, message={}, onFeedBackClose = ()=>{}}) { const [inputValue,setInputValue] = useState() const feedBackPredefinedComment = ["Incorrect", "Confusing", "Incomplete", "Unclear"] const handleSuggestClick = (e, item) => { setInputValue(item) } return ( <>

Why did you choose this rating?

{feedBackPredefinedComment.map((item) => { handleSuggestClick(e, item) }}>{item})}