[
  {
    "path": ".dockerignore",
    "content": "./github\r\n.gitignore\r\npoetry.lock\r\nREADME.md\r\nCODE_OF_CONDUCT.md\r\npyproject.toml\r\nCONTRIBUTING.md\r\n.flake8\r\nLICENSE\r\nsetup.py\r\nMakefile\r\n.pre-commit-config.yaml\r\n.env.example\r\nui/node_modules\r\npgdata"
  },
  {
    "path": ".flake8",
    "content": "[flake8]\nmax-line-length = 88\nenable-extensions = N, F, C, W, E # Enable naming checks\nselect = E201, E202, E204, E999, N801, N802, N803, N806, F401, F405, F811, F821, F823, F841, C901, W503, W504, E741, T001\nexclude = .git, __pycache__, build, dist, venv\n\n# Naming and Style Checks\n#N801: Class names should use CamelCase\n#N802: Function names should be snake_case\n#N803: Argument names should be snake_case\n#N806: Variable in function should be snake_case\n\n# Functionality Checks\n#F405: Name may be undefined, or defined from star imports: module\n#F401: Module imported but unused\n#F811: Redefinition of unused name from line n\n#F823: Local variable name ... referenced before assignment\n#F841: Local variable name is assigned to but never used\n#F821: Undefined name\n\n# Performance & Efficiency\n# E741: Do not use ambiguous variable names like 'l', 'O', or 'I'\n\n# Code Complexity\n#C901: Function is too complex (cyclomatic complexity)\n\n# Line Breaks\n#W503: Line break before binary operator\n#W504: Line break after binary operator\n\n#T001: Print statements found\n\n\n#E201: Whitespace after '('\n#E202: Whitespace before ')'\n#E203: Whitespace before ':'\n#E211: Whitespace before '('"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/static.yml",
    "content": "# Simple workflow for deploying static content to GitHub Pages\nname: Deploy static content to Pages\n\non:\n  # Runs on pushes targeting the default branch\n  push:\n    branches: [\"main\"]\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\n# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.\n# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.\nconcurrency:\n  group: \"pages\"\n  cancel-in-progress: false\n\njobs:\n  buid_and_deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          sparse-checkout: 'documents'\n          sparse-checkout-cone-mode: false\n      - name: Setup Pages\n        uses: actions/configure-pages@v5\n      # Set up Node.js and install dependencies with npm\n      - name: Set up Node.js\n        uses: actions/setup-node@v3\n        with:\n          node-version: 18.0.x\n\n      - name: Install docusaurus\n        run: npm install\n        working-directory: documents\n      - name: Build documents\n        run: npm run build\n        working-directory: documents\n\n      \n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: documents/build\n\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n__pycache__\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\ncover/\n\n\n# Environments\n\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n.DS_STORE\n\n# Default vector db path\nvector_db\nchromadb\n\n#assets files\nassets/datasource\n\n# Default log file\n.cache\n\n# Default databases\ncontext_store.db\nraggenie.db\ntest_db.db\ncsv_db.sqlite\n\n# node_modules folder\nui/node_modules\nui/dist-library\n\n#zitadel\npgdata\nmachinekey\n\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v4.6.0  # Use the latest version\n    hooks:\n      - id: check-yaml\n      - id: check-added-large-files\n      - id: check-case-conflict\n      - id: check-docstring-first\n      - id: check-merge-conflict\n      - id: trailing-whitespace"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\nslack : https://join.slack.com/t/theailounge/shared_invite/zt-2ogkrruyf-FPOHuPr5hdqXl34bDWjHjw.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing Guidelines for RAGGENIE\r\n\r\n## 🪜 Steps to Contribute\r\n\r\nTo contribute to this project, please follow these steps:\r\n\r\n1. Fork and clone this repository\r\n2. Make your changes on your fork.\r\n3. If you modify the code (for a new feature or bug fix), please add corresponding tests.\r\n4. Check for linting issues [see below](https://github.com/sirocco-ventures/raggenie/blob/main/CONTRIBUTING.md#-Linting)\r\n5. Ensure all tests pass [see below](https://github.com/sirocco-ventures/raggenie/blob/main/CONTRIBUTING.md#-Testing)\r\n6. Submit a pull request\r\n\r\nFor 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).\r\n\r\n## 📦 Package manager\r\n\r\nAt 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.\r\n\r\n## 📌 Pre-commit\r\n\r\nTo ensure our standards, make sure to install pre-commit before starting to contribute.\r\n\r\n```bash\r\npre-commit install\r\n```\r\n\r\n## 🧹 Linting\r\nWe use `Flake8` for linting our code. You can use the linter by running the following code.\r\n```bash\r\nmake linting\r\n```\r\n\r\n## 📝 Code formatting\r\nWe use `Flake8` as our code formatter. You can format the code using the following code.\r\n```bash\r\nmake formatting\r\n```\r\n\r\n## 🗒 Spellcheck\r\nWe use `codespell` for spell checking our code. For running the spellchecker run the following code.\r\n```bash\r\nmake spellcheck\r\n```\r\n\r\n## 🧪 Testing\r\nwe use `pytest` for integration testing the RAGGENIE. and `unittest` for unit testing individual components.\r\nfor unit testing run the following code\r\n```bash\r\nmake unit-test\r\n```\r\n\r\nfor integration testing run the following code\r\n```bash\r\nmake integration-test\r\n```\r\n"
  },
  {
    "path": "Dockerfile",
    "content": "# Stage 1: UI Build\r\nFROM node:20-alpine AS ui-build\r\n\r\nARG BACKEND_URL\r\n\r\nWORKDIR /app/ui\r\n\r\n# Copy package files first for better caching\r\nCOPY ./ui/package.json ./ui/package-lock.json ./\r\n\r\n# Install dependencies\r\nRUN npm install\r\n\r\n# Copy the rest of the UI source code\r\nCOPY ./ui/ .\r\n\r\n# Set environment variable and build\r\nENV VITE_BACKEND_URL=$BACKEND_URL\r\nRUN npm run build\r\n\r\n# Stage 2: Python Builder\r\nFROM python:3.11 AS python-builder\r\n\r\n# Improve performance and prevent generation of .pyc files\r\nENV PYTHONDONTWRITEBYTECODE=1\r\nENV PYTHONUNBUFFERED=1\r\n\r\n# Set the working directory in the container\r\nWORKDIR /app\r\n\r\n# Copy the requirements file into the container\r\nCOPY requirements.txt .\r\n\r\n# Create and activate a virtual environment, then install the dependencies\r\nRUN pip install virtualenv && \\\r\n    virtualenv /opt/venv && \\\r\n    . /opt/venv/bin/activate && \\\r\n    pip install -r requirements.txt\r\n\r\n# Stage 3: Final Deployer\r\nFROM python:3.11 AS deployer\r\n\r\n# Copy the virtual environment from the builder stage\r\nCOPY --from=python-builder /opt/venv /opt/venv\r\nENV PATH=\"/opt/venv/bin:$PATH\"\r\n\r\n# Install system dependencies\r\nRUN apt-get update && \\\r\n    apt-get install -y unixodbc-dev libgl1 && \\\r\n    rm -rf /var/lib/apt/lists/*\r\n\r\n# Set the working directory\r\nWORKDIR /app\r\n\r\n# Copy the rest of the application code\r\nCOPY . .\r\n\r\n# Copy the built UI files from the UI build stage\r\nCOPY --from=ui-build /app/ui/dist ./ui/dist\r\nCOPY --from=ui-build /app/ui/dist-library ./ui/dist-library\r\n\r\n\r\nEXPOSE 8001\r\n\r\nCMD [\"python3\", \"main.py\", \"--config\", \"./config.yaml\", \"llm\"]"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2024 sirocco ventures\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "# Define variables\nPOETRY = poetry\nPYTHON = $(POETRY) run python\nPOETRY_VENV = .venv\nPROJECT_DIR=./app\n\n# Specify the directories or files to spell check\nSPELLCHECK_FILES := **/*.py\n\n\n# Default target\n.PHONY: help\nhelp:\n\t@echo \"Available commands:\"\n\t@echo \"  make install       Install dependencies\"\n\n\n# Install dependencies\n.PHONY: install\ninstall:\n\t$(POETRY) install\n\n# Spellcheck target\n.PHONY: spellcheck\nspellcheck:\n\t- codespell $(shell find ./app -name \"*.py\")\n\n# lint check\n.PHONY: lint\nlint:\n\t@echo \"Running flake8...\"\n\tflake8 $(PROJECT_DIR)"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\r\n  <a href=\"https://www.raggenie.com/\">\r\n    <img src=\"https://cdn.prod.website-files.com/664e485574efd184749b7301/6658314c55210573e334ac1b_Group%2042.png\" width=\"150\" alt=\"RAGGENIE Logo\">\r\n  </a>\r\n</p>\r\n\r\n<h1 align=\"center\">\r\nRAGGENIE\r\n</h1>\r\n\r\n\r\n## What is RAGGENIE\r\nRAGGENIE 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.\r\n\r\nThe project is in its early stages, and we are working on adding more capabilities soon.\r\n\r\n• 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.\r\n\r\n• 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.\r\n\r\n### RAGGENIE Demo\r\n1. Demo with database -    [![Demo with database](https://img.youtube.com/vi/7wBO6g4rj3U/0.jpg)](https://www.youtube.com/watch?v=7wBO6g4rj3U)\r\n2. Demo with website data -    [![Demo with website data](https://img.youtube.com/vi/8h4bqqs5S3U/0.jpg)](https://www.youtube.com/watch?v=8h4bqqs5S3U)\r\n\r\n## 🌎 Communities\r\n\r\nJoin our communities for product updates, support, and to stay connected with the latest from RAGGENIE!\r\n*  Join our [Slack community](https://join.slack.com/t/theailounge/shared_invite/zt-2ogkrruyf-FPOHuPr5hdqXl34bDWjHjw) <img src=\"https://cdn.prod.website-files.com/634fa785d369cb60d80b6dd1/6375e1774613600a91630a78_Slack_icon_2019.svg.png\" width=\"15\" alt=\"RAGGENIE Logo\">\r\n*  Leave a star on our [GitHub](https://github.com/sirocco-ventures/raggenie) 🌟\r\n*  Report bugs with [GitHub Issues](https://github.com/sirocco-ventures/raggenie/issues) 🐞\r\n\r\n## 📐 Architecture\r\n\r\n![picture of Architecture flow]()\r\n\r\n### 🔮 Supported LLM Inferences\r\nRaggenie supports inference APIs to different LLM providers to run your model. The are the inference APIs currently supported by us:\r\n* [OpenAI](https://openai.com/index/openai-api/)\r\n* [Together.ai](https://www.together.ai/)\r\n* [Ollama] (https://ollama.com/)\r\n* [AI71] (https://ai71.ai/)\r\n\r\n### 🗃️ Data Sources\r\nThese 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.\r\n* Structured Datasources(airtable):<br />\r\nYou 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:\r\n    * [MySQL](https://www.mysql.com/)\r\n    * [PostgreSQL](https://www.postgresql.org/)\r\n    * [Bigquery](https://cloud.google.com/bigquery)\r\n    * [Airtable] (https://www.airtable.com/)\r\n    * [MariaDB](https://mariadb.org/)\r\n    * [MSSQL] (https://www.microsoft.com/en-in/sql-server)\r\n    * [SQLite] (https://www.sqlite.org/)\r\n\r\n\r\n* Document based sources(default):<br />\r\nThese 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:\r\n    * Document loader\r\n    * CSV loader\r\n    * Website loader\r\n\r\n### 💡Capabilities\r\nyou 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.\r\n\r\nCapabilities of the chatbot are defined by the user at the time of configuration. You can setup parameters required for each capability.\r\n* RAGGENIE can make sure that all the parameters are obtained for executing the capability.\r\n* RAGGENIE uses intent extraction to decide which of its defined capabilities should be used.\r\n* Capabilities can be used to trigger different actions.\r\n\r\n### 🤖 Agents/Actions\r\nRAGGENIE 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.\r\n* Fetch data from a database\r\n* Insert data into database\r\n\r\n### 🖼️ UI Plugin\r\nThis 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\r\n\r\n## 🛠️ Getting Started\r\nYou 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.\r\n\r\n### How to run Video\r\n[![Setting up RAGGENIE](https://img.youtube.com/vi/LfCqiToOCvI/0.jpg)](https://www.youtube.com/watch?v=LfCqiToOCvI)\r\n\r\n### 📄 Documentation\r\nComprehensive documentation is available to help you get the most out of RAGGENIE. The full documentation for RAGGENIE can be found [here]()\r\n\r\n### 📦 Installation and running\r\n\r\n#### Raggenie Backend\r\n\r\n* Installing dependencies\r\n\r\n  * **Using `requirements.txt`**\r\n\r\n    To install the required dependencies with `pip`, run:\r\n    \r\n    ```bash\r\n    pip install -r requirements.txt\r\n    ```\r\n\r\n  * **Using Poetry**\r\n\r\n    First, install Poetry:\r\n    \r\n    ```bash\r\n    curl -sSL https://install.python-poetry.org | python3 -\r\n    ```\r\n    \r\n    Then, to install the dependencies, run:\r\n    \r\n    ```bash\r\n    poetry install\r\n    ```\r\n\r\n* Running Zitadel Container and Initial Setup\r\n\r\n     * **Prerequisities**\r\n          * **Docker** installed on your system.\r\n          * **Docker Compose** installed on your system.\r\n\r\n    1. Start the Zitadel container using Docker Compose:\r\n    \r\n    ```bash\r\n    docker-compose -f zitadel-docker-compose.yaml up -d\r\n    ```\r\n    \r\n    2. Once the container is running, open your browser and go to: http://localhost:8080\r\n    \r\n    \r\n    3. Log in using the default credentials:\r\n    \r\n        - **Username:** `zitadel-admin@zitadel.localhost`\r\n        - **Password:** `Password1!`\r\n        \r\n    4. Creating a Service User and downloading key file\r\n    \r\n        1. Navigate to the **Users** tab.\r\n        2. Select **Service Users** and create a new service user.\r\n        3. Provide a username and name of your choice.\r\n        4. Set the **Access Token Type** to **JWT**.\r\n        5. Go to the **Keys** section and create a new key:\r\n            - Click **New**, then **Add**, and finally **Download** the key file.\r\n\r\n    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**.\r\n\r\n    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.\r\n        \r\n     * #### Configuring Environment Variables\r\n     \r\n        After downloading the key file, create an `.env` file and set the following variables:\r\n\r\n        ```env\r\n        CLIENT_PRIVATE_KEY_FILE_PATH=\"./path/to/downloaded/key.json\"\r\n        ZITADEL_TOKEN_URL=\"http://localhost:8080/oauth/v2/token\"\r\n        ZITADEL_DOMAIN=\"http://localhost:8080\"\r\n        ```\r\n\r\n\r\n\r\n* Running RAGGENIE backend\r\n\r\n  To run **RAGGENIE** in API mode, specify the config file to use by running the following command:\r\n\r\n  ```bash\r\n  python main.py --config ./config.yaml llm\r\n  ```\r\n\r\n  Below is a sample configuration for the vector database setup in `config.yaml`:\r\n\r\n  ```yaml\r\n  vector_db:\r\n    name: \"chroma\"\r\n    params:\r\n      path: \"./vector_db\"\r\n      embeddings:\r\n        provider: \"chroma_default\"\r\n  ```\r\n\r\nThis configuration ensures that the RAGGENIE system connects to the `chroma` vector database and uses the default embeddings provided by Chroma.\r\n\r\n#### Raggenie Frontend\r\n\r\n* Move into the ui folder\r\n  ```\r\n  cd ./ui\r\n  ```\r\n\r\n* Install dependencies\r\n  ```bash\r\n  npm install\r\n  ```\r\n\r\n* Running RAGGENIE Frontend\r\n\r\n  * To run **RAGGENIE** frontend, create a .env file and add the URL to backend as env variables\r\n    ```env\r\n    VITE_BACKEND_URL=${BACKEND_URL}\r\n    ```\r\n\r\n  * To start the server, run\r\n    ```bash\r\n    npm run dev\r\n    ```\r\n  * Running RAGGENIE Frontend using fast api\r\n\r\n    * Update .env file inside `./ui` folder\r\n      ```env\r\n      VITE_BACKEND_URL=\"\"\r\n      ```\r\n    * To serve UI using python server first build the UI \r\n      ```bash\r\n      npm run build\r\n      ```\r\n    * Stop and start python server\r\n\r\n      ```bash\r\n      python main.py --config ./config.yaml llm\r\n      ```\r\n\r\nfor more details visit [frontend readme](./ui/README.md)\r\n\r\n## ⛔️ Troubleshooting\r\n\r\nIf you encounter an error while running Python, please check the following\r\n\r\n- `Your system has an unsupported version of sqlite3. Chroma requires sqlite3 >= 3.35.0`\r\n    \r\n    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.\r\n   \r\n   Please use the following links for suggested solutions\r\n\r\n   - https://docs.trychroma.com/troubleshooting#sqlite\r\n   - https://discuss.streamlit.io/t/issues-with-chroma-and-sqlite/47950/4\r\n   - https://gist.github.com/defulmere/8b9695e415a44271061cc8e272f3c300\r\n\r\n   \r\n\r\n## 🚧 Feature Pipeline\r\nThese are the planned features and improvements that are in the pipeline for future releases.\r\n* REST API Requests for actions\r\n* Web hooks for actions\r\n\r\n## 📜 License\r\nRagGenie 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.\r\n\r\n## 🤝 Contributing\r\nContributions 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).\r\n"
  },
  {
    "path": "app/__init__.py",
    "content": ""
  },
  {
    "path": "app/api/v1/auth.py",
    "content": "import json\nimport requests\nfrom app.schemas.common import LoginData\nfrom fastapi import APIRouter, Depends, Response, Request, HTTPException, status\nfrom fastapi.responses import RedirectResponse, JSONResponse\nfrom app.providers.config import configs\nfrom app.providers.zitadel import Zitadel\nfrom app.schemas.common import CommonResponse\nfrom app.providers.middleware import verify_token\nimport app.services.user as svc\nimport app.schemas.user as schemas\nfrom app.utils.database import get_db\nfrom sqlalchemy.orm import Session\nimport app.api.v1.commons as commons\n\nlogin = APIRouter()\nif configs.auth_enabled:\n    zitadel = Zitadel()\n\n@login.post(\"/login\")\ndef login_user(response: Response, user: LoginData, db: Session = Depends(get_db)):\n    login_response = zitadel.login_with_username_password(user.username, user.password)\n    \n    # Extract user_id from the respons e\n    if login_response.status_code == 201:\n        response_data = login_response.body.decode(\"utf-8\")\n        response_json = json.loads(response_data)\n        user_id = response_json.get(\"user_id\")\n        username = response_json.get(\"username\")\n        user, error = svc.get_or_create_user(schemas.UserCreate(id=int(user_id), username=username), db)\n        if error:\n            return commons.is_error_response(\"DB Error\", error, {\"user\": {}})\n        \n    return login_response\n\n# will redirect to idp when called with ipdId\n# need to set successurl and failureUrl dynamically *****\n@login.get(\"/login/idp/{idp_id}\")\ndef idp_login(response: Response, idp_id : int):\n    return zitadel.redirect_to_idp(idp_id)\n\n# if idp login is success then is redirected to this endpoint with which we get the user\n# details from the idp (currently only tested with google)\n@login.get(\"/idp/success\")\ndef idp_success(request: Request,db: Session = Depends(get_db)):\n    query_params = request.query_params\n    idp_intent_id = query_params.get(\"id\")\n    idp_token = query_params.get(\"token\")\n    if not idp_intent_id or not idp_token:\n        return commons.is_error_response(\"Missing required parameters\", {}, {\"user\": {}})\n    user_id = query_params.get(\"user\")\n    try:\n        response = zitadel.get_idp_intent_data(idp_intent_id, idp_token)\n        user_data = response.json()\n        username = user_data.get(\"idpInformation\", {}).get(\"rawInformation\", {}).get(\"User\", {}).get(\"name\", \"\")\n        if(user_id):\n            user, error = svc.get_or_create_user(schemas.UserCreate(id=int(user_id), username=username), db)\n            session_response = zitadel.create_user_session(user_id, idp_intent_id, idp_token)\n        else:\n            session_response = zitadel.create_user(user_data, idp_intent_id, idp_token)\n            if session_response.status_code != 201:\n                return commons.is_error_response(\"Failed to create Zitadel user\", session_response.body.decode(\"utf-8\"), {\"user\": {}})\n            response_data = json.loads(session_response.body.decode(\"utf-8\"))\n            zitadel_user_id = response_data.get(\"user_id\")\n            new_user = schemas.UserCreate(\n                                    id=int(zitadel_user_id),\n                                    username=username,\n                                )\n            result, error = svc.get_or_create_user(new_user, db)\n            if error:\n                return commons.is_error_response(\"DB Error\", error, {\"user\": {}})\n\n            if not result:\n                return commons.is_none_reponse(\"User Not Created\", {\"user\": {}})\n\n        if session_response.status_code == 201:\n            redirect_response = RedirectResponse(url=\"/ui\", status_code=303)\n\n            # Copy cookies from session_response to redirect_response\n            for cookie in session_response.headers.getlist(\"set-cookie\"):\n                redirect_response.headers.append(\"set-cookie\", cookie)\n\n            return redirect_response\n\n        return session_response\n    except (requests.exceptions.RequestException, json.JSONDecodeError, AttributeError) as e:\n        return {\"error\": \"Failed to create session\", \"details\": str(e)}, 500\n\n\n\n# endpoint to retreive all the available idp providers that is setup in Zitadel\n@login.get(\"/idp/list\")\ndef list_idp(response: Response):\n    return zitadel.list_idp_providers()\n\n\n@login.get(\"/user_info\", dependencies=[Depends(verify_token)])\ndef get_user_info(request: Request, db: Session = Depends(get_db), user_data: dict = Depends(verify_token)):\n    if user_data.get(\"username\") == 'Admin':\n        new_user = schemas.UserCreate(\n                                id=int(user_data.get(\"user_id\")),\n                                username=user_data.get(\"username\"),\n                            )\n        result, error = svc.get_or_create_user(new_user, db)\n        if error:\n            return commons.is_error_response(\"DB Error\", error, {\"user\": {}})\n\n        if not result:\n            return commons.is_none_reponse(\"User Not Created\", {\"user\": {}})\n        env_id, error = svc.get_users_active_env(user_data.get(\"user_id\"), db)\n        if error:\n            return commons.is_error_response(\"DB Error\", error, {\"env\": {}})\n        return CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"User info retrieved successfully\",\n        data={ \"username\": user_data['username'], \"auth_enabled\": configs.auth_enabled, \"env_id\": env_id },\n        error=None\n    )\n         \n    session_id = user_data[\"session_id\"]\n    user_info = zitadel.get_user_info(session_id)\n    username = user_info.get(\"session\").get(\"factors\").get(\"user\").get(\"displayName\")\n    user_id = user_info.get(\"session\").get(\"factors\").get(\"user\").get(\"id\")\n    env_id, error = svc.get_users_active_env(user_id, db)\n    if error:\n        return commons.is_error_response(\"DB Error\", error, {\"env\": {}})\n    return CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"User info retrieved successfully\",\n        data={ \"username\": username, \"auth_enabled\": configs.auth_enabled, \"env_id\": env_id },\n        error=None\n    )\n\n\n# change to get user info from raggenie.db\n@login.post(\"/logout\",dependencies=[Depends(verify_token)])\ndef logout_user(response: Response, user_data: dict = Depends(verify_token)):\n    session_id = user_data[\"session_id\"]\n    res = zitadel.logout_user(session_id)\n    if res.status_code == 200:\n        response.delete_cookie(\"session_data\")\n    return res\n\n"
  },
  {
    "path": "app/api/v1/commons.py",
    "content": "import app.schemas.common as resp_schemas\n\ndef is_error_response(message:str, err:str, data:dict):\n    return resp_schemas.CommonResponse(\n            status= False,\n            status_code=422,\n            message=message,\n            data=data,\n            error=err\n        )\n\ndef is_none_reponse(message:str, data:dict):\n    return resp_schemas.CommonResponse(\n            status= True,\n            status_code=200,\n            message=message,\n            data=data,\n            error=\"Not Found\"\n        )"
  },
  {
    "path": "app/api/v1/connector.py",
    "content": "from typing import List, Optional\nfrom app.providers.cache_manager import cache_manager\nfrom fastapi import APIRouter, Depends\nfrom sqlalchemy.orm import Session\nimport app.schemas.connector as schemas\nimport app.schemas.common as resp_schemas\nfrom app.utils.database import get_db\nimport app.services.connector as svc\nimport app.services.provider as provider_svc\nfrom starlette.requests import Request\nfrom fastapi import APIRouter, UploadFile, File\n\nfrom app.chain.chains.capability_chain import CapabilityChain\nfrom app.chain.chains.metadata_chain import MetadataChain\nfrom app.chain.chains.query_chain import QueryChain\nfrom app.chain.chains.intent_chain import IntentChain\nfrom app.chain.chains.general_chain import GeneralChain\n\nimport app.api.v1.commons as commons\nfrom loguru import logger\nfrom app.providers.config import configs\nfrom app.providers.middleware import verify_token\nimport copy\n\n\nrouter = APIRouter()\ncap_router = APIRouter()\ninference_router = APIRouter()\nactions = APIRouter()\n\n@router.get(\"/list\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef list_connectors(db: Session = Depends(get_db), provider_category_ids:  Optional[List[int]] = None, user_data: dict = Depends(verify_token)):\n\n    \"\"\"\n    Retrieves a list of all connectors from the database. If a provider category ID is provided, only connectors from that category are returned.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing either the list of connectors or an error message.\n    \"\"\"\n    user_id = user_data[\"user_id\"]\n    if provider_category_ids:\n        result, error = svc.list_connectors_by_provider_category(provider_category_ids, db, user_id)\n    else:\n        result, error = svc.list_connectors(db, user_id)\n\n    if error:\n        return commons.is_error_response(\"DB Error\", result, {\"connectors\": []})\n\n    if not result:\n        return commons.is_none_reponse(\"Connector Not Found\", {\"connectors\": []})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"connectors\": result},\n        message=\"Connectors Found\",\n        error=None\n    )\n\n@router.get(\"/get/{connector_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_connector(connector_id: int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves a specific connector by its ID from the database.\n\n    Args:\n        connector_id (int): The ID of the connector.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing either the connector details or an error message.\n    \"\"\"\n\n    result, error = svc.get_connector(connector_id, db)\n\n    if error:\n        return commons.is_error_response(\"DB Error\", result, {\"connector\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Connector Not Found\", {\"connector\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"connector\": result},\n        message=\"Connector Found\",\n        error=None\n    )\n\n@router.post(\"/upload/datasource\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\nasync def upload_document_datsource(\n    file: UploadFile = File(...)\n):\n\n    \"\"\"\n    Uploads an document data source file to the server.\n\n    Args:\n        file (UploadFile): The uploaded document file. Accepted formats are .pdf, .txt, .yaml, and .docx.\n\n    Returns:\n        CommonResponse: A response containing the file upload status, file details, or an error message.\n    \"\"\"\n\n    error, size = await svc.fileValidation(file)\n\n    if error:\n        return commons.is_error_response(\"Invalid File\", error, {\"file_path\": None})\n\n    result, error = await svc.upload_pdf(file)\n\n    if error:\n        return commons.is_error_response(\"document not uploaded\", error, {\"file_path\": None})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        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\"]}},\n        message=\"File Uploaded Success\",\n        error=None\n    )\n\n@router.post(\"/create\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef create_connector(connector: schemas.ConnectorBase, db: Session = Depends(get_db), user_data: dict = Depends(verify_token)):\n\n    \"\"\"\n    Creates a new connector in the database.\n\n    Args:\n        connector (ConnectorBase): The data for the new connector.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating success or failure of the connector creation process.\n    \"\"\"\n    user_id = user_data[\"user_id\"]\n    result, error = svc.create_connector(connector, db, user_id)\n    if error:\n        return commons.is_error_response(\"Connector Not Created\", error, {\"connector\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        data={\"connector\": result},\n        message=\"Connector Created\",\n        error=None\n    )\n\n@router.post(\"/update/{connector_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef update_connector(connector_id: int, connector: schemas.ConnectorUpdate, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Updates an existing connector based on its ID.\n\n    Args:\n        connector_id (int): The ID of the connector to update.\n        connector (ConnectorUpdate): The updated data for the connector.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating success or failure of the update process.\n    \"\"\"\n\n    result, error = svc.update_connector(connector_id, connector, db)\n\n    if error:\n        return commons.is_error_response(\"DB Error\", result, {\"connector\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Connector Not Found\", {\"connector\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"connector\": result},\n        message=\"Connector Updated\",\n        error=None\n    )\n\n@router.post(\"/delete/{connector_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef delete_connector(connector_id: int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Deletes a connector from the database based on its ID.\n\n    Args:\n        connector_id (int): The ID of the connector to delete.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating success or failure of the deletion process.\n    \"\"\"\n\n    result, error = svc.delete_connector(connector_id, db)\n\n    if error:\n        return commons.is_error_response(\"DB Error\", result, {\"connector\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Connector Not Found\", {\"connector\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"connector\": result},\n        message=\"Connector Deleted\",\n        error=None\n    )\n\n@router.post(\"/schema/update/{connector_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef updateschemas(connector_id: int, connector: schemas.SchemaUpdate, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Updates the schema details of a connector based on its ID.\n\n    Args:\n        connector_id (int): The ID of the connector whose schema is being updated.\n        connector (SchemaUpdate): The schema update data for the connector.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating success or failure of the schema update.\n    \"\"\"\n\n    result, error = svc.updateschemas(connector_id, connector, db)\n\n    if error:\n        return commons.is_error_response(\"DB Error\", result, {\"schemas\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Connector Not Found\", {\"schemas\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"schemas\": result},\n        message=\"Schema Updated\",\n        error=None\n    )\n\n\n\n@router.get(\"/configuration/list\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef list_configurations(db: Session = Depends(get_db), user_data: dict = Depends(verify_token)):\n\n    \"\"\"\n    Lists all available configurations from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing the list of configurations or an error message.\n    \"\"\"\n    user_id = user_data[\"user_id\"]\n    result, error = svc.list_configurations(db, user_id)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"configurations\": []})\n\n    if not result:\n        return commons.is_none_reponse(\"Configurations Not Found\", {\"configurations\": []})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Configurations retrieved successfully\",\n        error=None,\n        data={\"configurations\": result}\n    )\n    \n@router.get(\"/configuration/{config_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_configuration(config_id: int, db: Session = Depends(get_db)):\n    \"\"\"\n    Retrieves a configuration by its ID.\n\n    Args:\n        config_id (int): ID of the configuration to retrieve.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing the configuration or an error message.\n    \"\"\"\n    result, error = svc.get_configuration(db, config_id)\n\n    if error == \"DB Error\":\n        return commons.is_error_response(\"DB error\", result, {\"configuration\": None})\n\n    if error == \"Configuration not found\":\n        return commons.is_none_reponse(\"Configuration Not Found\", {\"configuration\": None})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Configuration retrieved successfully\",\n        error=None,\n        data={\"configuration\": result}\n    )\n    \n@router.delete(\"/configuration/{config_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_configuration(config_id: int, db: Session = Depends(get_db)):\n    \"\"\"\n    Retrieves a configuration by its ID.\n\n    Args:\n        config_id (int): ID of the configuration to retrieve.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing the configuration or an error message.\n    \"\"\"\n    result, error = svc.delete_configuration(db, config_id)\n\n    if error == \"DB Error\":\n        return commons.is_error_response(\"DB error\", result, {\"configuration\": None})\n\n    if error == \"Configuration not found\":\n        return commons.is_none_reponse(\"Configuration Not Found\", {\"configuration\": None})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Configuration deleted successfully\",\n        error=None,\n        data={\"configuration\": result}\n    )\n\n\n@router.post(\"/configuration/create\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef create_configuration(configuration: schemas.ConfigurationCreation, db: Session = Depends(get_db), user_data: dict = Depends(verify_token)):\n\n    \"\"\"\n    Creates a new configuration and stores it in the database.\n\n    Args:\n        configuration (ConfigurationCreation): The new configuration details.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the configuration creation.\n    \"\"\"\n    user_id = user_data[\"user_id\"]\n    result, error = svc.create_configuration(configuration, db, user_id)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"configuration\": []})\n\n\n    if not result:\n        return commons.is_none_reponse(\"Configuration Not Found\", {\"configuration\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        message=\"Configuration created successfully\",\n        error=None,\n        data={\"configuration\": result}\n    )\n\n@router.post(\"/configuration/update/{config_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef update_configuration(config_id: int, configuration: schemas.ConfigurationUpdate, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Updates an existing configuration in the database.\n\n    Args:\n        config_id (int): The ID of the configuration to update.\n        configuration (ConfigurationUpdate): The updated configuration details.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the configuration update.\n    \"\"\"\n\n    result, error = svc.update_configuration(config_id, configuration, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"configuration\": []})\n\n\n    if not result:\n        return commons.is_none_reponse(\"Configuration Not Found\", {\"configuration\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Configuration updated successfully\",\n        error=None,\n        data={\"configuration\": result}\n    )\n\n\n\n\n@cap_router.post(\"/create\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef create_capability(capability: schemas.CapabilitiesBase, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Creates a new capability in the database.\n\n    Args:\n        capability (CapabilitiesBase): The new capability details.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the capability creation.\n    \"\"\"\n\n    result, error = svc.create_capabilities(capability, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"capability\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        message=\"Capabilities created successfully\",\n        error=None,\n        data={\"capability\": result}\n    )\n\n@cap_router.get(\"/all\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_all_capabilities(db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves all capabilities from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing the list of capabilities or an error message.\n    \"\"\"\n\n    result, error = svc.get_all_capabilities(db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"capabilities\": []})\n\n\n    if not result:\n        return commons.is_none_reponse(\"Capabilities Not Found\", {\"capabilities\": []})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Capabilities retrieved successfully\",\n        error=None,\n        data={\"capabilities\": result}\n    )\n\n\n@cap_router.post(\"/update/{cap_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef update_capability(cap_id: int, capability: schemas.CapabilitiesUpdateBase, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Updates an existing capability in the database.\n\n    Args:\n        cap_id (int): The ID of the capability to update.\n        capability (CapabilitiesUpdateBase): The updated capability details.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the capability update.\n    \"\"\"\n\n    result, error = svc.update_capability(cap_id, capability, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"capability\": {}})\n\n\n    if not result:\n        return commons.is_none_reponse(\"Capability Not Found\", {\"capability\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Capability updated successfully\",\n        error=None,\n        data={\"capability\": result}\n    )\n\n@cap_router.delete(\"/delete/{cap_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef delete_capability(cap_id: int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Deletes an existing capability from the database.\n\n    Args:\n        cap_id (int): The ID of the capability to delete.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the capability deletion.\n    \"\"\"\n\n    result, error = svc.delete_capability(cap_id, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"capability\": {}})\n\n\n    if not result:\n        return commons.is_none_reponse(\"Capability Not Found\", {\"capability\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Capability deleted successfully\",\n        error=None,\n        data={\"capability\": {}}\n    )\n\n\n\n@router.post(\"/createyaml/{config_id}\", dependencies=[Depends(verify_token)])\ndef create_yaml(request: Request, config_id: int, db: Session = Depends(get_db), index: Optional[bool] = True):\n\n    \"\"\"\n    Creates a YAML configuration file and initializes processing chains for the specified configuration.\n\n    Args:\n        request (Request): The request object containing the data for YAML creation.\n        config_id (int): The ID of the configuration to use.\n        db (Session): The database session dependency.\n\n    Returns:\n        dict: A dictionary with success status and error message, if any.\n    \"\"\"\n\n    documentations, use_case, is_error = svc.create_yaml_file(request,config_id, db)\n\n    if is_error:\n        return {\n            \"success\":False,\n            \"error\":is_error\n        }\n\n    inference_config, is_error = svc.create_inference_yaml(config_id,db)\n\n    if is_error and not inference_config:\n        return {\n            \"success\":False,\n            \"error\":is_error\n        }\n\n\n    combined_yaml_content = {\n        'datasources': documentations if documentations != None else [],\n        'use_case': use_case\n    }\n\n    configs.inference_llm_model=inference_config[0][\"unique_name\"]\n\n    config = copy.deepcopy(request.app.config)\n    vector_store, is_error = provider_svc.create_vectorstore_instance(db, config_id)\n    if vector_store:\n        vector_store.connect()\n    context_storage = request.app.context_storage\n\n    data_sources = combined_yaml_content[\"datasources\"]\n    use_case = combined_yaml_content[\"use_case\"]\n\n    config[\"use_case\"] = use_case\n    config[\"datasources\"] = data_sources\n    config[\"models\"] = inference_config\n\n    confyaml = svc.get_inference_and_plugin_configurations(db, config_id)\n    request.app.container.config.from_dict(confyaml)\n    datasources = request.app.container.datasources()\n\n    mappings = confyaml.get(\"mappings\",{})\n    datasources, err = svc.update_datasource_documentations(db, vector_store, datasources, mappings, config_id, index)\n    if err:\n        logger.error(\"Error updating\")\n\n    query_chain = QueryChain(config, vector_store, datasources, context_storage)\n    general_chain = GeneralChain(config, vector_store, datasources, context_storage)\n    capability_chain = CapabilityChain(config, context_storage, query_chain)\n    metedata_chain = MetadataChain(config, vector_store, datasources, context_storage)\n\n    chain = IntentChain(config, vector_store, datasources, context_storage, query_chain, general_chain, capability_chain, metedata_chain)\n\n    cache_manager.set(config_id, {\n        \"chain\": chain,\n        \"config\": config,\n        \"vector_store\": vector_store,\n        \"datasources\": datasources,\n        \"context_storage\": context_storage\n    })\n    \n    \n\n    return {\n        \"success\": True,\n        \"error\":None\n    }\n\n@inference_router.post(\"/get/models\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_llm_provider_models(llm_provider: schemas.LLMProviderBase):\n    \"\"\"\n    Retrieves the models associated with the specified LLM provider.\n    Args:\n        llm_provider (schemas.LLMProviderBase): The details of the LLM provider.\n        db (Session): The database session dependency.\n    Returns:\n        CommonResponse: A response containing the list of LLM provider models or an error message.\n    \"\"\"\n    data, is_error = svc.get_llm_provider_models(llm_provider)\n    if is_error:\n        return commons.is_error_response(\"LLM Provider Models Not Found\", data, {\"provider_models\": []})\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"LLM Provider Models Found\",\n        error=None,\n        data={\"provider_models\": [data]}\n    )\n\n@inference_router.get(\"/get/{inference_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_inference(inference_id: int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves an inference record from the database using the given inference ID.\n\n    Args:\n        inference_id (int): The ID of the inference record to retrieve.\n        db (Session): The database session dependency.\n\n    Returns:\n        dict: A dictionary with the inference details or error message, if any.\n    \"\"\"\n\n    result, error = svc.get_inference(inference_id, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"inference\": {}})\n\n\n    if not result:\n        return commons.is_none_reponse(\"Inference Not Found\", {\"inference\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Inference Found\",\n        error=None,\n        data={\"inference\": result}\n    )\n\n@inference_router.post(\"/create\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef create_inference(inference: schemas.InferenceBase, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Creates a new inference record in the database.\n\n    Args:\n        inference (schemas.InferenceBase): The details of the inference to be created.\n        db (Session): The database session dependency.\n\n    Returns:\n        dict: A dictionary indicating the success of the operation and the created inference details or error message.\n    \"\"\"\n    success, message = provider_svc.test_inference_credentials(inference)\n    if not success:\n        return commons.is_error_response(\"Test Credentials Failed\", message, {\"inference\": {}})\n\n    result, error = svc.create_inference(inference, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"inference\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        message=\"Inference Created Successfully\",\n        error=None,\n        data={\"inference\": result}\n    )\n\n@inference_router.post(\"/update/{inference_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef update_inference(inference_id: int, inference: schemas.InferenceBaseUpdate, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Updates an existing inference record in the database.\n\n    Args:\n        inference_id (int): The ID of the inference record to update.\n        inference (schemas.InferenceBaseUpdate): The updated details of the inference.\n        db (Session): The database session dependency.\n\n    Returns:\n        dict: A dictionary with the status of the update operation and the updated inference details or error message, if any.\n    \"\"\"\n    success, message = provider_svc.test_inference_credentials(inference)\n    if not success:\n        return commons.is_error_response(\"Test Credentials Failed\", message, {\"inference\": {}})\n\n    result, error = svc.update_inference(inference_id, inference, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"inference\": {}})\n\n\n    if not result:\n        return commons.is_none_reponse(\"Inference Not Found\", {\"inference\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Inference Updated Successfully\",\n        error=None,\n        data={\"inference\": result}\n    )\n\n\n\n@actions.get(\"/list\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef list_actions(db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves all actions from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing the list of actions or an error message.\n    \"\"\"\n\n    result, error = svc.list_actions(db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"actions\": []})\n\n    if not result:\n        return commons.is_none_reponse(\"Actions Not Found\", {\"actions\": []})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"actions\": result},\n        message=\"Actions Found\",\n        error=None\n    )\n\n@actions.get(\"/get/{action_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_action(action_id:int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves a specific action by its ID.\n\n    Args:\n        action_id (int): The unique identifier of the action to retrieve.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing the action details or an error message.\n    \"\"\"\n\n    result, error = svc.get_actions(action_id,db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"action\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Action Not Found\", {\"action\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"action\": result},\n        message=\"Action Found\",\n        error=None\n    )\n\n@actions.get(\"/{connector_id}/list\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_actions_by_connector(connector_id:int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves all actions related to a specific connector by its ID.\n\n    Args:\n        connector_id (int): The unique identifier of the connector.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing the list of actions or an error message.\n    \"\"\"\n\n    result, error = svc.get_actions_by_connector(connector_id,db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"actions\": []})\n\n    if not result:\n        return commons.is_none_reponse(\"Actions Not Found\", {\"actions\": []})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"actions\": result},\n        message=\"Action Found\",\n        error=None\n    )\n\n@actions.post(\"/create\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef create_action(action: schemas.Actions, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Creates a new action in the database.\n\n    Args:\n        action (Actions): The schema containing action details to create.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the action creation.\n    \"\"\"\n\n    result, error = svc.create_action(action, db)\n\n    if error:\n        return commons.is_error_response(\"Action Not Created\", result, {\"action\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        data={\"action\": result},\n        message=\"Action Created\",\n        error=None\n    )\n\n@actions.post(\"/update/{action_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef update_action(action_id: int, action: schemas.ActionsUpdate, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Updates an existing action in the database by its ID.\n\n    Args:\n        action_id (int): The unique identifier of the action to update.\n        action (ActionsUpdate): The schema containing updated action details.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the action update.\n    \"\"\"\n\n    result, error = svc.update_action(action_id, action, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"action\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Action Not Found\", {\"action\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"action\": result},\n        message=\"Action Updated\",\n        error=None\n    )\n\n@actions.post(\"/{action_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef delete_action(action_id: int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Deletes an action by its ID from the database.\n\n    Args:\n        action_id (int): The unique identifier of the action to delete.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the action deletion.\n    \"\"\"\n\n    result, error = svc.delete_action(action_id, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"action\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Action Not Found\", {\"action\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"action\": result},\n        message=\"Action Deleted\",\n        error=None\n    )\n"
  },
  {
    "path": "app/api/v1/llmchat.py",
    "content": "# src/endpoints/chat.py\n\nfrom fastapi import APIRouter, Depends\nfrom sqlalchemy.orm import Session\nimport app.schemas.common as resp_schemas\nfrom app.schemas import llmchat as schemas\nfrom app.utils.database import get_db\nfrom app.services import llmchat as svc\nimport app.api.v1.commons as commons\n\nchat_router = APIRouter()\n\n# Create a new chat\n@chat_router.post(\"/create\", response_model=resp_schemas.CommonResponse)\ndef create_chat(chat: schemas.ChatHistoryCreate, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Creates a new chat record in the database.\n\n    Args:\n        chat (ChatHistoryCreate): The data for the new chat entry.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating success or failure of the chat creation process.\n    \"\"\"\n\n    result, error = svc.create_chat(chat, db)\n\n    if error:\n        return commons.is_error_response(\"DB Error\", result, {\"chat\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        data={\"chat\": result},\n        message=\"Chat created successfully\",\n        error=None\n    )\n\n# Create feedback for a chat\n@chat_router.post(\"/feedback/create\", response_model=resp_schemas.CommonResponse)\ndef create_feedback(feedback: schemas.FeedbackCreate, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Creates feedback for an existing chat record.\n\n    Args:\n        feedback (FeedbackCreate): The feedback data to be added to the chat.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating success or failure of the feedback creation process.\n    \"\"\"\n\n    result, error = svc.create_feedback(feedback, db)\n\n    if error:\n        return commons.is_error_response(\"DB Error\", result, {\"chat\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Chat Not Found\", {\"chat\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"chat\": result},\n        message=\"Feedback updated successfully\",\n        error=None\n    )\n\n# List the primary chat based on context\n@chat_router.get(\"/list/context/all/{env_id}\", response_model=resp_schemas.CommonResponse)\ndef list_chat_by_context(env_id: int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves all the primary chats based on context from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing either the list of primary chats or an error message.\n    \"\"\"\n\n    result, error = svc.list_chats_by_context(env_id, db)\n\n    if error:\n        return commons.is_error_response(\"DB Error\", error, {\"chats\": []})\n\n    if not result:\n        return commons.is_none_reponse(\"Context Not found\", {\"chats\": []})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"chats\": result},\n        message=\"Primary chats found\",\n        error=None\n    )\n\n# Get a specific chat by context ID\n@chat_router.get(\"/get/{context_id}\", response_model=resp_schemas.CommonResponse)\ndef get_chat_by_context(context_id: str, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves a specific chat by context ID from the database.\n\n    Args:\n        context_id (str): The ID of the context to retrieve the chat for.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing either the chat data or an error message.\n    \"\"\"\n\n    result, error = svc.list_all_chats_by_context_id(context_id, db)\n\n    if error:\n        return commons.is_error_response(\"DB Error\", error, {\"chats\": []})\n\n    if not result:\n        return commons.is_none_reponse(\"Chat not found\", {\"chats\": []})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"chats\": result},\n        message=\"Chat found\",\n        error=None\n    )\n"
  },
  {
    "path": "app/api/v1/main_router.py",
    "content": "from app.providers.cache_manager import cache_manager\nfrom fastapi import APIRouter, Depends, status, Query\nfrom fastapi.encoders import jsonable_encoder\nfrom app.models.request import Chat, FeedbackCorrectionRequest\nfrom starlette.requests import Request\nfrom loguru import logger\nfrom app.schemas import llmchat as schemas\nfrom app.api.v1 import llmchat\nfrom app.api.v1 import connector\nfrom sqlalchemy.orm import Session\nfrom app.utils.database import get_db\n\n\nMainRouter = APIRouter()\n\n\n@MainRouter.post(\"/query\", status_code=status.HTTP_201_CREATED)\n\nasync def qna(\n    query: Chat,\n    request: Request,\n    context_id: str = Query(..., alias=\"contextId\"),\n    config_id: str = Query(..., alias=\"configId\"),\n    env_id: str = Query(..., alias=\"envId\"),\n    db: Session = Depends(get_db)\n):\n\n    \"\"\"\n    Handles user queries and invokes the chain to get an answer from the LLM.\n\n    Args:\n        query (Chat): User query as a Chat model.\n        request (Request): FastAPI request object containing context and app-level dependencies.\n        background_tasks (BackgroundTasks): Background task for asynchronous logging.\n        db (Session): Database session dependency.\n\n    Returns:\n        dict: Response containing the answer to the user's query and the original query text.\n    \"\"\"\n    \n    logger.info(f\"{context_id} - {config_id} - query: {query.content}\")\n    cached_data = cache_manager.get(int(config_id))\n    if not cached_data:\n        logger.info(\"configuration was not found in the cache\")\n        response = connector.create_yaml(request, int(config_id), db, False)\n        if response['success'] == True:\n            cached_data = cache_manager.get(int(config_id))\n        else:\n            return\n        \n    chain = cached_data[\"chain\"]\n    vector_store = cached_data['vector_store']\n    request.app.chain = chain\n    request.app.vector_store = vector_store\n    \n    out = await chain.invoke({\n        \"question\": query.content,\n        \"context_id\": context_id,\n    })\n\n    resp = llmchat.create_chat(\n        schemas.ChatHistoryCreate(\n            chat_context_id=context_id,\n            chat_query=query.content,\n            chat_answer= jsonable_encoder(out),\n            chat_summary=out.get(\"summary\", query.content),\n            configuration_id=config_id,\n            environment_id=env_id\n        ),\n        db\n    )\n\n    if resp.status:\n        out[\"chat_id\"] = resp.data[\"chat\"].chat_id\n\n\n    return {\n        \"response\": out,\n        \"query\": query.content,\n    }\n\n\n#! This api is not in use right now, instead we are using a scheduler for the feedback_correction job\n@MainRouter.post(\"/feedback_correction\", status_code=status.HTTP_201_CREATED)\ndef feedback_correction(request: Request, body: FeedbackCorrectionRequest):\n\n    \"\"\"\n    Processes feedback from LLM responses and updates the vector store accordingly.\n\n    Args:\n        request (Request): FastAPI request object containing the app's vector store.\n        body (FeedbackCorrectionRequest): Request body containing user feedback to be processed.\n\n    Returns:\n        str: Success message indicating the feedback processing outcome.\n\n    \"\"\"\n\n    store = request.app.vector_store\n\n    if body.responses:\n        for response in body.responses:\n            similar_sample = store.find_similar_samples(response.description)\n            if len(similar_sample) > 0 and similar_sample[0]['distances'] < 0.3:\n                store.update_store(similar_sample[0]['id'],response.metadata,response.description)\n            else:\n                store.update_store(metadatas = response.metadata,documents = response.description)\n        return \"Success: Feedback received and processed.\"\n\n    else:\n        return \"Success: No Feedback received and processed.\"\n\n\n"
  },
  {
    "path": "app/api/v1/provider.py",
    "content": "from fastapi import APIRouter, Depends\nfrom sqlalchemy.orm import Session\nimport app.schemas.common as resp_schemas\nimport app.schemas.provider as schemas\nfrom app.utils.database import get_db\nimport app.services.provider as svc\nimport app.api.v1.commons as commons\nimport app.schemas.connector as conn_schemas\nfrom fastapi import Request\nfrom app.providers.middleware import verify_token\n\n\nrouter = APIRouter()\nsample = APIRouter()\nvectordb = APIRouter()\n\n\n@router.get(\"/list\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef list_providers(db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves a list of providers (plugins) from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing either the list of providers or an error message.\n    \"\"\"\n\n    result, error = svc.list_providers(db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"providers\": []})\n\n    if not result:\n        return commons.is_none_reponse(\"Providers Not Found\", {\"providers\": []})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"providers\": result},\n        message=\"Providers Found\",\n        error=None\n    )\n\n@router.get(\"/get/{provider_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_provider(provider_id: int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves a specific provider (plugin) by its ID.\n\n    Args:\n        provider_id (int): The ID of the provider to retrieve.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing either the provider details or an error message.\n    \"\"\"\n\n    result, error=svc.get_provider(provider_id, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"provider\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Providers Not Found\", {\"provider\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"provider\": result},\n        message=\"Provider Found\",\n        error=None\n    )\n\n@router.post(\"/{provider_id}/test-credentials\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef test_connections(provider_id: int, config: schemas.TestCredentials, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Tests the credentials for a specific provider (plugin) by its ID.\n\n    Args:\n        provider_id (int): The ID of the provider for which to test credentials.\n        config (TestCredentials): The credentials to test.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the credential test.\n    \"\"\"\n\n    success, message = svc.test_credentials(provider_id, config, db)\n\n    if not success:\n        return resp_schemas.CommonResponse(\n            status=False,\n            status_code=422,\n            message=message,\n            error=message,\n        )\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=message,\n        error=None,\n    )\n\n@vectordb.post(\"/test_credentials\", response_model=resp_schemas.CommonResponse)\ndef test_vectordb_credentials(config: schemas.TestVectorDBCredentials, db: Session = Depends(get_db)):\n    \"\"\"\n    Tests the credentials for a VectorDB provider.\n\n    Args:\n        config (TestVectorDBCredentials): The credentials to test.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the credential test.\n    \"\"\"\n    message, is_error = svc.test_vectordb_credentials(config, db)\n\n    if is_error:\n        return resp_schemas.CommonResponse(\n            status=False,\n            status_code=422,\n            message=\"Test credentials Failed\",\n            error=message,\n        )\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=message,\n        error=None,\n    )\n\n\n@vectordb.get(\"/list/all\",response_model= resp_schemas.CommonResponse)\ndef getvectordbs(db: Session = Depends(get_db)):\n    \"\"\"\n    Retrieves a list of available VectorDB providers.\n\n    Args:\n        request (Request): The HTTP request object.\n\n    Returns:\n        CommonResponse: A response containing either the list of VectorDB providers or an error message.\n    \"\"\"\n\n    result, is_error = svc.getvectordbs(db)\n\n\n    if is_error:\n        return commons.is_error_response(\"DB error\", result, {\"vectordbs\": []})\n\n    if not result:\n        return commons.is_none_reponse(\"Sample SQL Not Found\", {\"vectordbs\": []})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"VectorDB providers found\",\n        data={\"vectordbs\":result},\n        error=None,\n    )\n\n@router.get(\"/llmproviders\", response_model=resp_schemas.CommonResponse)\ndef getllmproviders(request: Request):\n\n    \"\"\"\n    Retrieves a list of available LLM (Large Language Model) providers.\n\n    Args:\n        request (Request): The HTTP request object.\n\n    Returns:\n        CommonResponse: A response containing either the list of LLM providers or an error message.\n    \"\"\"\n\n    result, is_error = svc.getllmproviders(request)\n\n    if is_error:\n        return resp_schemas.CommonResponse(\n            status=False,\n            status_code=422,\n            message=\"LLM providers not found\",\n            error=None,\n        )\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"LLM providers found\",\n        data=result,\n        error=None,\n    )\n\n@router.post(\"/test-inference-credentials\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef test_inference_connections(inference: conn_schemas.InferenceBase):\n    \"\"\"\n    Tests the inference connections by validating the credentials for a specific LLM provider.\n\n    Args:\n        inference (conn_schemas.InferenceBase):\n            Configuration object containing the provider details, including model name, API key, and endpoint, for testing the connections.\n\n    Returns:\n        resp_schemas.CommonResponse:\n            - Response object containing:\n                - status (bool): Indicates whether the credentials validation was successful.\n                - status_code (int): HTTP status code (200 for success, 422 for failure).\n                - message (str): A message providing the outcome of the credentials test.\n                - error (Optional[str]): Error message if the credentials test failed, otherwise None.\n    \"\"\"\n\n    success, message = svc.test_inference_credentials(inference)\n    if not success:\n        return resp_schemas.CommonResponse(\n            status=False,\n            status_code=422,\n            message=\"Test Credentials Failed\",\n            error=message,\n        )\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=message,\n        error=None,\n    )\n\n@sample.get(\"/list\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef list_sql(db: Session = Depends(get_db), user_data: dict = Depends(verify_token)):\n\n    \"\"\"\n    Retrieves a list of sample SQL records from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing either the list of sample SQL records or an error message.\n    \"\"\"\n    \n    user_id = user_data[\"user_id\"]\n    result, error = svc.listsql(db, user_id)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"sql\": []})\n\n    if not result:\n        return commons.is_none_reponse(\"Sample SQL Not Found\", {\"sql\": []})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"sql\": result},\n        message=\"Sample SQL Found\",\n        error=None\n    )\n\n@sample.get(\"/{id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_sql(id: int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Retrieves a specific sample SQL record by its ID.\n\n    Args:\n        id (int): The ID of the sample SQL record to retrieve.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing either the SQL record or an error message.\n    \"\"\"\n\n    result, error = svc.getsql(id, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"sql\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Sample SQL Not Found\", {\"sql\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        data={\"sql\": result},\n        message=\"Sample SQL Found\",\n        error=None\n    )\n\n\n\n@sample.post(\"/create\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef create_sql(request:Request,sql: schemas.SampleSQLBase, db: Session = Depends(get_db), user_data: dict = Depends(verify_token)):\n\n    \"\"\"\n    Creates a new sample SQL record in the database.\n\n    Args:\n        request (Request): The HTTP request object.\n        sql (SampleSQLBase): The data for the new SQL record.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the SQL creation process.\n    \"\"\"\n    user_id = user_data[\"user_id\"]\n\n    result, error = svc.create_sql(request, sql, db, user_id)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"sql\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        message=\"Sample SQL Created Successfully\",\n        error=None,\n        data={\"SQL\": result}\n    )\n\n@sample.post(\"/update/{id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef update_sql(id: int, request: Request, sql: schemas.SampleSQLUpdate, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Updates an existing sample SQL record by its ID.\n\n    Args:\n        id (int): The ID of the SQL record to update.\n        request (Request): The HTTP request object.\n        sql (SampleSQLUpdate): The updated SQL data.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the SQL update process.\n    \"\"\"\n\n    result, error = svc.update_sql(request, id, sql, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"sql\": {}})\n\n    if not result:\n        return commons.is_none_reponse(\"Sample SQL Not Found\", {\"sql\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Sample SQL Updated Successfully\",\n        error=None,\n        data={\"sql\": result}\n    )\n\n@sample.post(\"delete/{id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef delete_sql(id: int, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Deletes a sample SQL record by its ID.\n\n    Args:\n        id (int): The ID of the SQL record to delete.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the SQL deletion process.\n    \"\"\"\n\n    result, error = svc.delete_sql(id, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"sql\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Sample SQL Deleted Successfully\",\n        error=None,\n    )\n\n\n@vectordb.post(\"/create\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef create_vectordb_instance(vectordb: schemas.VectorDBBase, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Creates a new VectorDB instance in the database.\n\n    Args:\n        request (Request): The HTTP request object.\n        sql (VectorDBBase): The data for the new VectorDB instance.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the VectorDB instance creation process.\n    \"\"\"\n\n    result, error = svc.create_vectordb_and_embedding(\"create\",0,vectordb, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"vectordb\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        message=\"VectorDB Instance Created Successfully\",\n        error=None,\n        data={\"VectorDB\": result}\n    )\n\n@vectordb.post(\"/update/{id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef update_vectordb_instance(id:int,vectordb: schemas.VectorDBUpdateBase, db: Session = Depends(get_db)):\n\n    \"\"\"\n    Updates VectorDB instance in the database.\n\n    Args:\n        request (Request): The HTTP request object.\n        sql (VectorDBBase): The data for the new VectorDB instance.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the VectorDB instance creation process.\n    \"\"\"\n\n    result, error = svc.create_vectordb_and_embedding(key=\"update\",id=id,vectordb=vectordb, db=db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"vectordb\": {}})\n\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=201,\n        message=\"VectorDB Instance Updated Successfully\",\n        error=None,\n        data={\"VectorDB\": result}\n    )\n\n@vectordb.get(\"/get/{config_id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_vectordb_instance(id: int, db: Session = Depends(get_db)):\n    \"\"\"\n    Retrieves a VectorDB instance by its ID.\n\n    Args:\n        id (int): The ID of the VectorDB instance.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response containing the VectorDB instance or an error message.\n    \"\"\"\n\n    result, error = svc.get_vectordb_instance(id, db)\n\n    if error:\n        return commons.is_error_response(\"DB error\", result, {\"vectordb\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"VectorDB Instance Retrieved Successfully\",\n        error=None,\n        data={\"VectorDB\": result}\n    )\n\n@vectordb.delete(\"/delete/{id}\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef delete_vectordb_instance(id: int, db: Session = Depends(get_db)):\n    \"\"\"\n    Deletes a VectorDB instance by its ID, along with its associated config mapping.\n\n    Args:\n        id (int): The ID of the VectorDB instance to delete.\n        db (Session): Database session dependency.\n\n    Returns:\n        CommonResponse: A response indicating the success or failure of the deletion process.\n    \"\"\"\n\n    result, error = svc.delete_vectordb_instance(id, db)\n\n    if error:\n        return commons.is_error_response(\"DB error or VectorDB not found\", result, {\"vectordb\": {}})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"VectorDB Instance Deleted Successfully\",\n        error=None,\n        data={\"VectorDB\": result}\n    )\n\n@vectordb.get(\"/embedding/all\", response_model=resp_schemas.CommonResponse, dependencies=[Depends(verify_token)])\ndef get_all_embeddings():\n\n    \"\"\"\n    Retrieves all embeddings from module.\n\n    Returns:\n        CommonResponse: A response containing the embeddings or an error message.\n    \"\"\"\n\n    result, error = svc.get_all_embeddings()\n\n    if error:\n        return commons.is_error_response(\"Fetching Error\", result, {\"embeddings\": []})\n\n    return resp_schemas.CommonResponse(\n        status=True,\n        status_code=200,\n        message=\"Embeddings Retrieved Successfully\",\n        error=None,\n        data={\"embeddings\": result}\n    )\n"
  },
  {
    "path": "app/base/abstract_handlers.py",
    "content": "from __future__ import annotations\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Optional\n\n\nclass Handler(ABC):\n    \"\"\"\n    The Handler interface declares a method for building the chain of handlers.\n    It also declares a method for executing a request.\n    \"\"\"\n\n    @abstractmethod\n    def set_next(self, handler: Handler) -> Handler:\n        pass\n\n    @abstractmethod\n    async def handle(self, request) -> Optional[str]:\n        pass\n\nclass AbstractHandler(Handler):\n    \"\"\"\n    The default chaining behavior can be implemented inside a base handler\n    class.\n    \"\"\"\n\n    _next_handler: Handler = None\n\n    def set_next(self, handler: Handler) -> Handler:\n        self._next_handler = handler\n        # Returning a handler from here will let us link handlers in a\n        # convenient way like this:\n        # monkey.set_next(squirrel).set_next(dog)\n        return handler\n\n    @abstractmethod\n    async def handle(self, request: Any) -> str:\n        if self._next_handler:\n            return await self._next_handler.handle(request)\n\n        return None"
  },
  {
    "path": "app/base/base_formatter.py",
    "content": "from abc import ABC, abstractmethod\n\n\nclass BaseFormatter(ABC):\n\n    @abstractmethod\n    def format(self)-> (dict):\n        \"\"\"\n        Abstract method to format data.\n\n        This method should be implemented by subclasses to define\n        specific formatting logic.\n\n        Returns:\n            dict: A dictionary containing the formatted data.\n        \"\"\"\n        pass"
  },
  {
    "path": "app/base/base_llm.py",
    "content": "# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identifier: Apache-2.0\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom typing import List, Optional, Any\nimport requests\nimport json\n\nfrom langchain.callbacks.manager import (\n    AsyncCallbackManagerForLLMRun,\n    CallbackManagerForLLMRun,\n)\nfrom langchain.llms.base import LLM\nfrom loguru import logger\n\n\nclass BaseLLM(LLM):\n\n    temperature: Optional[float] = 0.5\n    url: Any = \"\"\n    headers : Optional[Any]  = {}\n    body : Optional[Any]  = {}\n\n\n    def _call(\n        self,\n        prompt: Optional[str]=\"\",\n        stop: Optional[List[str]] = None,\n        run_manager: Optional[CallbackManagerForLLMRun] = None,\n    ) -> str:\n\n        if prompt != \"\":\n            self.body[\"prompt\"] = prompt\n        try:\n            r = requests.post(self.url,  json=self.body,headers=self.headers)\n            model_out = json.loads(r.content)\n        except Exception as e:\n            logger.error(e)\n            model_out = {}\n\n        return model_out\n\n\n\n    async def _acall(\n        self,\n        prompt: str,\n        stop: Optional[List[str]] = None,\n        run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,\n        **kwargs: Any,\n    ) -> str:\n\n        return \"hi\"\n\n    @property\n    def _llm_type(self) -> str:\n        return \"rest llm\"\n\n    @property\n    def _identifying_params(self) -> dict:\n        return {\n            \"url\": self.url,\n        }\n\n"
  },
  {
    "path": "app/base/base_plugin.py",
    "content": "from abc import ABC, abstractmethod\n\nclass BasePlugin(ABC):\n\n    @abstractmethod\n    def connect(self):\n        pass\n\n    @abstractmethod\n    def healthcheck(self):\n        pass"
  },
  {
    "path": "app/base/base_vectordb.py",
    "content": "from app.embeddings.loader import EmLoader\n\nclass BaseVectorDB():\n\n    def load_embeddings_function(self):\n        return EmLoader(self.embeddings).load_embclass().load_emb()"
  },
  {
    "path": "app/base/document_data_plugin.py",
    "content": "from abc import ABC, abstractmethod\nfrom typing import Dict, Any, Optional\n\nclass DocumentDataPlugin(ABC):\n\n    @abstractmethod\n    def fetch_data(self, params: Optional[Dict[str, Any]] = None) -> list:\n        \"\"\"\n        Fetches data based on the provided parameters.\n\n        :param params: Optional query parameters.\n        :return: a list of strings\n        \"\"\"\n        pass\n"
  },
  {
    "path": "app/base/loader_metadata_mixin.py",
    "content": "import importlib\nfrom loguru import logger\n\nclass LoaderMetadataMixin:\n\n    # plugin default variables\n    __unique_name__ = \"\"\n    __display_name__ = \"\"\n    __icon__ = \"\"\n\n\n    def __init__(self, name):\n        logger.info(\"Initializing mixin class\")\n        self._load_metadata(name.removesuffix('.loader'))\n\n\n    @classmethod\n    def _load_metadata(self, class_path):\n        module = importlib.import_module(class_path)\n\n        try:\n            self.__unique_name__ = getattr(module, '__unique_name__')\n            self.__display_name__ = getattr(module, '__display_name__')\n            self.__icon__ = getattr(module, '__icon__')\n        except Exception as e:\n            raise Exception(e)"
  },
  {
    "path": "app/base/messaging_plugin.py",
    "content": "from abc import ABC, abstractmethod\n\nclass MessagePlugin(ABC):\n\n    @abstractmethod\n    def send(self):\n        pass\n"
  },
  {
    "path": "app/base/model_loader.py",
    "content": "class ModelLoader:\n\n\n    def __init__(self, model_config):\n        self.model_config = model_config\n\n    def load_model(self):\n        raise NotImplementedError(\"load_model method must be implemented in subclass\")\n\n    def get_response(self) -> dict:\n        raise NotImplementedError(\"load_model method must be implemented in subclass\")\n\n    def get_usage(self, prompt, response, out) -> dict:\n        raise NotImplementedError(\"load_model method must be implemented in subclass\")\n\n    def get_models(self):\n        raise NotImplementedError(\"load_model method must be implemented in subclass\")"
  },
  {
    "path": "app/base/plugin_metadata_mixin.py",
    "content": "import importlib\nfrom loguru import logger\n\nclass PluginMetadataMixin:\n\n    # plugin default variables\n    __version__ = \"\"\n    __plugin_name__ = \"\"\n    __description__ = \"\"\n    __icon__ = \"\"\n    __connection_args__= \"\"\n    __category__ = \"\"\n    __prompt__ = \"\"\n\n\n\n    def __init__(self, name):\n        logger.info(\"Initializing mixin class\")\n        self._load_metadata(name.removesuffix('.handler'))\n\n\n    @classmethod\n    def _load_metadata(self, class_path):\n        module = importlib.import_module(class_path)\n\n        try:\n            self.__version__ = getattr(module, '__version__')\n            self.__plugin_name__ = getattr(module, '__plugin_name__')\n            self.__description__ = getattr(module, '__description__')\n            self.__icon__ = getattr(module, '__icon__')\n            self.__connection_args__ = getattr(module, '__connection_args__')\n            self.__category__ = getattr(module, '__category__')\n            self.__prompt__ = getattr(module, '__prompt__')\n        except Exception as e:\n            raise Exception(e)"
  },
  {
    "path": "app/base/query_plugin.py",
    "content": "from abc import ABC, abstractmethod\nfrom typing import Dict, Any, Optional, Tuple\n\nclass QueryPlugin(ABC):\n\n    @abstractmethod\n    def fetch_data(self, query: str, params: Optional[Dict[str, Any]] = None) -> Tuple[Any, Optional[str]]:\n        \"\"\"\n        Fetches data based on the provided query.\n\n        :param query: The query.\n        :param params: Optional query parameters.\n        :return: A tuple containing the fetched data and an optional error message.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def fetch_schema_details(self) -> Tuple[list, list]:\n        \"\"\"\n        Fetches schema details from Airtable.\n\n        :return: A tuple containing schema DDL as a list of strings and table metadata.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def create_ddl_from_metadata(self, table_metadata: list) -> list:\n        \"\"\"\n        Creates DDL from table metadata.\n\n        :param table_metadata: List of table metadata dictionaries.\n        :return: List of schema DDL strings.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def validate(self, formatted_sql: str) -> None:\n        \"\"\"\n        Validates the provided SQL.\n\n        :param formatted_sql: SQL string to validate.\n        \"\"\"\n        pass"
  },
  {
    "path": "app/base/remote_data_plugin.py",
    "content": "from abc import ABC, abstractmethod\nfrom typing import Dict, Any, Optional\n\nclass RemoteDataPlugin(ABC):\n\n    @abstractmethod\n    def fetch_data(self, params: Optional[Dict[str, Any]] = None) -> list:\n        \"\"\"\n        Fetches data based on the provided parameters.\n\n        :param params: Optional query parameters.\n        :return: a list of strings\n        \"\"\"\n        pass\n"
  },
  {
    "path": "app/chain/chains/capability_chain.py",
    "content": "from app.chain.modules.input_formatter import InputFormatter\nfrom app.chain.modules.post_processor import PostProcessor\nfrom app.chain.modules.follow_up_handler import FollowupHandler\nfrom app.chain.modules.context_retreiver import ContextRetreiver\nfrom app.chain.modules.followup_interpreter import FollowupInterpreter\n\n\nfrom loguru import logger\n\nclass CapabilityChain:\n    \"\"\"\n    CapabilityChain class represents the processing chain for handling capability-related requests.\n\n    This class orchestrates various modules to process user input, handle follow-ups,\n    interpret follow-up requests, and manage context across interactions.\n\n    Attributes:\n        common_context (dict): A shared context dictionary used across modules.\n        input_formatter (InputFormatter): Module for formatting user input.\n        context_retriver (ContextRetreiver): Module for retrieving context.\n        followup_handler (FollowupHandler): Module for handling follow-up requests.\n        followup_interpreter (FollowupInterpreter): Module for interpreting follow-up requests.\n        post_processor (PostProcessor): Module for post-processing responses.\n        handler: The first module in the processing chain.\n\n    The CapabilityChain class follows a modular design, where each module is responsible\n    for a specific part of the processing pipeline. This allows for flexibility\n    and easy extension of functionality.\n    \"\"\"\n    def __init__(self, model_configs, context_storage, general_chain):\n\n        logger.info(\"loading modules into capability chain\")\n\n\n        self.common_context = {}\n\n        self.input_formatter = InputFormatter()\n        self.context_retriver = ContextRetreiver(self.common_context, context_storage)\n        self.followup_handler = FollowupHandler(self.common_context, model_configs)\n        self.followup_interpreter = FollowupInterpreter(self.common_context, general_chain)\n        self.post_processor = PostProcessor()\n\n\n\n        logger.info(\"initializing chain\")\n        self.input_formatter.set_next(self.context_retriver).set_next(self.followup_handler).set_next(self.followup_interpreter).set_next(self.post_processor)\n        self.handler =  self.input_formatter\n\n\n    def invoke(self, user_request):\n        logger.info(\"Processing user request\")\n        return self.handler.handle(user_request)\n"
  },
  {
    "path": "app/chain/chains/general_chain.py",
    "content": "from app.chain.modules.input_formatter import InputFormatter\n# from app.chain.modules.guard_rail import GuardRail\nfrom app.chain.modules.prompt_generator import PromptGenerator\nfrom app.chain.modules.general_answer_generator import GeneralAnswerGenerator\nfrom app.chain.modules.ouput_formatter import OutputFormatter\nfrom app.chain.modules.post_processor import PostProcessor\n\nfrom app.chain.modules.context_retreiver import ContextRetreiver\n\n\n\n\nfrom loguru import logger\n\nclass GeneralChain:\n    \"\"\"\n    Chain class represents the main processing chain for handling user requests.\n\n    This class orchestrates various modules to process user input, retrieve context,\n    generate prompts, execute actions, and format output.\n\n    Attributes:\n        vector_store: A storage system for vector embeddings.\n        data_sources: A list of data sources to be used in processing.\n        context_store: A storage system for maintaining context across interactions.\n        common_context (dict): A shared context dictionary used across modules.\n        configs (dict): Configuration settings for the models.\n        input_formatter (InputFormatter): Module for formatting user input.\n        rag_module (RagModule): Module for Retrieval-Augmented Generation.\n        prompt_generator (PromptGenerator): Module for generating prompts.\n        generator (Generator): Module for generating responses.\n        validator (Validator): Module for validating responses.\n        context_retriver (ContextRetreiver): Module for retrieving context.\n        context_storage (ContextStorage): Module for storing context.\n        executer (Executer): Module for executing actions.\n        cache_checker (Cachechecker): Module for checking and managing cache.\n        output_formatter (OutputFormatter): Module for formatting output.\n\n    The Chain class follows a modular design, where each module is responsible\n    for a specific part of the processing pipeline. This allows for flexibility\n    and easy extension of functionality.\n    \"\"\"\n    def __init__(self, model_configs, store, datasource, context_store):\n\n        logger.info(\"loading modules into chain\")\n\n\n        self.vector_store = store\n        self.data_sources = datasource if datasource is not None else []\n        self.context_store = context_store\n\n        self.common_context = {\n            \"chain_retries\" : 0,\n            \"rag\": {\n                \"context\": [],\n                \"schema\" : [],\n            },\n        }\n\n        self.configs = model_configs\n        self.input_formatter = InputFormatter()\n        self.prompt_generator = PromptGenerator(self.common_context, model_configs, self.data_sources)\n        self.generator = GeneralAnswerGenerator(self.common_context, model_configs)\n        self.context_retriver = ContextRetreiver(self.common_context, context_store)\n        self.output_formatter = OutputFormatter(self.common_context,self.data_sources)\n\n        self.post_processor = PostProcessor()\n\n        logger.info(\"initializing chain\")\n\n        self.input_formatter.set_next(self.context_retriver) \\\n        .set_next(self.prompt_generator).set_next(self.generator).set_next(self.output_formatter).set_next(self.post_processor)\n\n        self.handler =  self.input_formatter\n\n\n    def invoke(self, user_request):\n        self.common_context[\"chain_retries\"] = 0\n        self.common_context[\"intent\"] = user_request[\"intent_extractor\"][\"intent\"]\n        self.common_context[\"context_id\"] = user_request[\"context_id\"]\n        self.common_context[\"rag\"].update({\n            \"context\": [],\n            \"schema\" : [],\n        })\n        return self.handler.handle(user_request)\n"
  },
  {
    "path": "app/chain/chains/intent_chain.py",
    "content": "from app.chain.modules.document_retriever import DocumentRetriever\nfrom app.chain.modules.input_formatter import InputFormatter\n\nfrom app.chain.modules.intent_extracter import IntentExtracter\nfrom app.chain.modules.router import Router\nfrom app.chain.modules.post_processor import PostProcessor\nfrom app.chain.formatter.general_response import Formatter\nfrom app.chain.modules.context_retreiver import ContextRetreiver\n\n\nfrom loguru import logger\n\nclass IntentChain:\n    \"\"\"\n    IntentChain class represents the main processing chain for handling user intents.\n\n    This class orchestrates various modules to process user input, extract intents,\n    route requests, and manage context across interactions.\n\n    Attributes:\n        vector_store: A storage system for vector embeddings.\n        data_source: A data source to be used in processing.\n        context_store: A storage system for maintaining context across interactions.\n        common_context (dict): A shared context dictionary used across modules.\n        configs (dict): Configuration settings for the models.\n        input_formatter (InputFormatter): Module for formatting user input.\n        context_retriver (ContextRetreiver): Module for retrieving context.\n        intent_extractor (IntentExtracter): Module for extracting intents from user input.\n        post_processor (PostProcessor): Module for post-processing responses.\n        router (Router): Module for routing requests to appropriate chains.\n        handler: The first module in the processing chain.\n\n    The IntentChain class follows a modular design, where each module is responsible\n    for a specific part of the processing pipeline. This allows for flexibility\n    and easy extension of functionality.\n    \"\"\"\n    def __init__(self, model_configs, store, datasource, context_store, intent_chain, general_chain, capability_chain, metadata_chain):\n        logger.info(\"loading modules into chain\")\n\n        self.vector_store = store\n        self.context_store = context_store\n        self.data_sources = datasource if datasource is not None else {}\n\n        self.common_context = {\n            \"chain_retries\" : 0,\n        }\n\n        self.configs = model_configs\n        self.input_formatter = InputFormatter()\n        self.context_retriver = ContextRetreiver(self.common_context, context_store)\n        self.intent_extractor = IntentExtracter(self.common_context, model_configs, self.data_sources)\n        self.document_retriever = DocumentRetriever(self.vector_store, self.data_sources)\n        self.post_processor = PostProcessor()\n        self.router = Router(self.common_context, self.post_processor, intent_chain, general_chain, capability_chain, metadata_chain)\n\n        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)\n\n        self.handler =  self.input_formatter\n\n\n    def invoke(self, user_request):\n        try:\n            self.common_context[\"chain_retries\"] = 0\n            self.common_context[\"context_id\"] = user_request[\"context_id\"]\n            return self.handler.handle(user_request)\n        except Exception as error:\n            logger.error(f\"An error occurred: {error}\")\n            return Formatter.format(\"Oops! Something went wrong. Try Again!\",error)\n"
  },
  {
    "path": "app/chain/chains/metadata_chain.py",
    "content": "from app.chain.modules.input_formatter import InputFormatter\nfrom app.chain.modules.post_processor import PostProcessor\nfrom app.chain.modules.metadata_generator import MetadataGenerator\nfrom app.chain.modules.context_retreiver import ContextRetreiver\nfrom app.chain.modules.ouput_formatter import OutputFormatter\nfrom app.chain.modules.metadata_ragfilter import MetadataRagFilter\nfrom app.chain.modules.document_retriever import DocumentRetriever\n\nfrom loguru import logger\n\nclass MetadataChain:\n    \"\"\"\n    MetadataChain class represents the processing chain for handling metadata-related requests.\n\n    This class orchestrates various modules to process user input, retrieve context,\n    generate metadata, and format output for metadata-related operations.\n\n    Attributes:\n        vector_store: A storage system for vector embeddings.\n        data_sources: A list of data sources to be used in processing.\n        context_store: A storage system for maintaining context across interactions.\n        common_context (dict): A shared context dictionary used across modules.\n        input_formatter (InputFormatter): Module for formatting user input.\n        context_retriver (ContextRetreiver): Module for retrieving context.\n        document_retriever (DocumentRetriever): Module for retrieving relevant documents.\n        metadata_generator (MetadataGenerator): Module for generating metadata.\n        post_processor (PostProcessor): Module for post-processing responses.\n        metadata_ragfilter (MetadataRagFilter): Module for filtering metadata using RAG.\n        output_formatter (OutputFormatter): Module for formatting output.\n        handler: The first module in the processing chain.\n\n    The MetadataChain class follows a modular design, where each module is responsible\n    for a specific part of the processing pipeline. This allows for flexibility\n    and easy extension of functionality in metadata processing and generation.\n    \"\"\"\n    def __init__(self, model_configs, store, datasource, context_store):\n        logger.info(\"loading modules into metadata chain\")\n        self.vector_store = store\n        self.data_sources = datasource if datasource is not None else []\n        self.context_store = context_store\n\n        self.common_context = {\n            \"chain_retries\" : 0,\n        }\n\n        self.input_formatter = InputFormatter()\n        self.context_retriver = ContextRetreiver(self.common_context, context_store)\n        self.document_retriever = DocumentRetriever(self.vector_store, self.data_sources)\n\n        self.metadata_generator = MetadataGenerator(self.common_context, model_configs, self.data_sources)\n        self.post_processor = PostProcessor()\n        self.metadata_ragfilter = MetadataRagFilter()\n        self.output_formatter = OutputFormatter(self.common_context,self.data_sources)\n\n        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)\n        self.handler =  self.input_formatter\n\n\n    def invoke(self, user_request):\n\n        self.common_context[\"chain_retries\"] = 0\n        return self.handler.handle(user_request)\n"
  },
  {
    "path": "app/chain/chains/query_chain.py",
    "content": "from app.chain.modules.document_retriever import DocumentRetriever\nfrom app.chain.modules.input_formatter import InputFormatter\n# from app.chain.modules.guard_rail import GuardRail\nfrom app.chain.modules.prompt_generator import PromptGenerator\nfrom app.chain.modules.generator import Generator\nfrom app.chain.modules.schema_retriever import SchemaRetriever\nfrom app.chain.modules.validator import Validator\nfrom app.chain.modules.executer import Executer\nfrom app.chain.modules.ouput_formatter import OutputFormatter\nfrom app.chain.modules.post_processor import PostProcessor\nfrom app.chain.formatter.general_response import Formatter\nfrom app.chain.modules.cache_checker import Cachechecker\n\nfrom app.chain.modules.context_retreiver import ContextRetreiver\nfrom app.chain.modules.context_storage import ContextStorage\n\n\n\n\nfrom loguru import logger\n\nclass QueryChain:\n    \"\"\"\n    Chain class represents the main processing chain for handling user requests.\n\n    This class orchestrates various modules to process user input, retrieve context,\n    generate prompts, execute actions, and format output.\n\n    Attributes:\n        vector_store: A storage system for vector embeddings.\n        data_sources: A list of data sources to be used in processing.\n        context_store: A storage system for maintaining context across interactions.\n        common_context (dict): A shared context dictionary used across modules.\n        configs (dict): Configuration settings for the models.\n        input_formatter (InputFormatter): Module for formatting user input.\n        rag_module (RagModule): Module for Retrieval-Augmented Generation.\n        prompt_generator (PromptGenerator): Module for generating prompts.\n        generator (Generator): Module for generating responses.\n        validator (Validator): Module for validating responses.\n        context_retriver (ContextRetreiver): Module for retrieving context.\n        context_storage (ContextStorage): Module for storing context.\n        executer (Executer): Module for executing actions.\n        cache_checker (Cachechecker): Module for checking and managing cache.\n        output_formatter (OutputFormatter): Module for formatting output.\n\n    The Chain class follows a modular design, where each module is responsible\n    for a specific part of the processing pipeline. This allows for flexibility\n    and easy extension of functionality.\n    \"\"\"\n    def __init__(self, model_configs, store, datasource, context_store):\n\n        logger.info(\"loading modules into chain\")\n\n\n        self.vector_store = store\n        self.data_sources = datasource if datasource is not None else []\n        self.context_store = context_store\n\n        self.common_context = {\n            \"chain_retries\" : 0,\n            \"llm\": {\n                \"input_tokens\" : 0,\n                \"output_tokens\": 0,\n                \"total_cost\": 0,\n                \"latency\": 0,\n                \"response\": {\n                    \"input_tokens\" : 0,\n                    \"output_tokens\": 0,\n                    \"total_cost\": 0,\n                    \"latency\": 0,\n                    \"logprob_percentage\": 0,\n                    \"name\": \"default\"\n                    },\n            },\n            \"execution_logs\": [],\n            \"general_response\": Formatter,\n            \"prompt_mode\" : \"manual\",\n            \"inference_raw\" : \"\",\n            \"prompt\": \"\",\n            \"rag\": {\n                \"context\": [],\n                \"schema\" : [],\n            },\n        }\n\n        self.configs = model_configs\n        self.input_formatter = InputFormatter()\n\n        self.prompt_generator = PromptGenerator(self.common_context, model_configs, self.data_sources)\n        self.generator = Generator(self.common_context, model_configs)\n        self.validator = Validator(self.common_context,self.data_sources)\n        self.context_retriver = ContextRetreiver(self.common_context, context_store)\n        self.context_storage = ContextStorage(self.common_context, context_store)\n        self.schema_retriever = SchemaRetriever(self.vector_store, self.data_sources)\n        self.executer = Executer(self.common_context,self.data_sources, self.prompt_generator)\n        self.cache_checker = Cachechecker(self.common_context, self.vector_store,self.executer)\n        self.output_formatter = OutputFormatter(self.common_context,self.data_sources)\n        self.post_processor = PostProcessor()\n\n        logger.info(\"initializing chain\")\n\n        self.input_formatter.set_next(self.cache_checker) \\\n        .set_next(self.context_retriver) \\\n        .set_next(self.prompt_generator).set_next(self.generator).set_next(self.validator).set_next(self.executer) \\\n        .set_next(self.output_formatter).set_next(self.post_processor)\n\n        self.handler =  self.input_formatter\n\n\n    def invoke(self, user_request):\n        self.common_context[\"chain_retries\"] = 0\n        self.common_context[\"intent\"] = user_request[\"intent_extractor\"][\"intent\"]\n        self.common_context[\"context_id\"] = user_request[\"context_id\"]\n        self.common_context[\"llm\"].update({\n            \"input_tokens\" : 0,\n            \"output_tokens\": 0,\n            \"total_cost\": 0,\n            \"latency\": 0,\n            \"response\": {\n                \"input_tokens\" : 0,\n                \"output_tokens\": 0,\n                \"total_cost\": 0,\n                \"latency\": 0,\n                \"logprob_percentage\": 0,\n                \"name\": \"default\"\n                },\n        })\n        self.common_context[\"prompt_mode\"] = \"manual\"\n        self.common_context[\"rag\"].update({\n            \"context\": [],\n            \"schema\" : [],\n        })\n        return self.handler.handle(user_request)\n"
  },
  {
    "path": "app/chain/formatter/general_response.py",
    "content": "class Formatter:\n\n    def format(data: any, error: any) -> (dict):\n        response = {}\n\n        response[\"main_entity\"] = \"none\"\n        response[\"main_format\"] = \"general_chat\"\n        response[\"role\"] = \"assistant\"\n        response[\"content\"] = data\n        response[\"summary\"] = data\n        response[\"error\"] = error\n\n        return response"
  },
  {
    "path": "app/chain/modules/cache_checker.py",
    "content": "from typing import Any\nfrom loguru import logger\nfrom app.base.abstract_handlers import AbstractHandler\n\n\nclass Cachechecker(AbstractHandler):\n    \"\"\"\n    A handler class for checking and managing cache operations.\n\n    This class extends AbstractHandler and provides functionality to check\n    if a query exists in the cache and handle the response accordingly.\n    \"\"\"\n\n    def __init__(self,common_context, cachestore, forward_handler, forward: bool = True) -> None:\n        \"\"\"\n        Initialize the Cachechecker.\n\n        Args:\n            common_context: The common context shared across handlers.\n            Cachestore: The cache storage mechanism.\n            forward_handler: The next handler in the chain.\n            forward (bool): Whether to forward the request to the next handler.\n        \"\"\"\n        self.cache = cachestore\n        self.forward_handler = forward_handler\n        self.forward = forward\n        self.common_context = common_context\n\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Handle the incoming request by checking the cache\n\n        Args:\n            request (Any): The incoming request to be processed.\n\n        Returns:\n            str: The response after processing the request.\n        \"\"\"\n        logger.info(\"passing through => cache_checker\")\n\n        response = request\n        question = request.get(\"question\", \"\")\n        rag_filters = response[\"rag_filters\"][\"datasources\"]\n        output = await self.cache.find_similar_cache(rag_filters, question)\n        if \"rag\" not in response:\n            response[\"rag\"] = {\n                \"suggestions\": output\n            }\n        else:\n            response[\"rag\"][\"suggestions\"] = output\n\n\n\n        if self.forward and len(output) > 0:\n            if output[0][\"distances\"] < -10:\n                result = output[0][\"metadatas\"]\n                logger.info(\"query retrieved from cache\")\n                return await self.forward_handler.handle({\"inference\":result})\n\n        logger.info(\"query not retrieved from cache\")\n        return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/cache_updater.py",
    "content": "from typing import Any\nfrom loguru import logger\nfrom app.base.abstract_handlers import AbstractHandler\n\nclass Cacheupdater(AbstractHandler):\n    \"\"\"\n    A handler class for updating the cache with new query responses.\n\n    This class extends AbstractHandler and provides functionality to update\n    the cache with new question-inference pairs when appropriate.\n    \"\"\"\n\n    def __init__(self,cachestore) -> None:\n        \"\"\"\n        Initialize the Cacheupdater.\n\n        Args:\n            Cachestore (Any): The cache storage mechanism.\n        \"\"\"\n        self.cache = cachestore\n\n    async def handle(self, response: Any) -> str:\n        \"\"\"\n        Handle the incoming response by updating the cache if necessary.\n\n        Args:\n            response (Dict[str, Any]): The response to be processed.\n\n        Returns:\n            str: The response after processing.\n        \"\"\"\n        logger.info(\"passing through => cache_updater\")\n        data = response[\"query_response\"]\n\n        # question would not be in response if retrieved from cache\n        if (\"question\" in response) and not(data is None or len(data) == 0):\n            logger.info(\"cache updated\")\n            inference = response[\"inference\"]\n            question = response[\"question\"]\n            self.cache.update_cache(\n                document = question,\n                metadata = inference,\n            )\n        return await super().handle(response)"
  },
  {
    "path": "app/chain/modules/context_retreiver.py",
    "content": "from typing import Any\nfrom loguru import logger\nfrom app.base.abstract_handlers import AbstractHandler\nfrom app.models.llmchat import ChatHistory\n\nclass ContextRetreiver(AbstractHandler):\n    \"\"\"\n    A handler class for retrieving context information for a chat.\n\n    This class extends AbstractHandler and provides functionality to fetch\n    relevant context based on the context_id provided in the request.\n    \"\"\"\n\n    def __init__(self,common_context, context_store) -> None:\n        \"\"\"\n        Initialize the ContextRetriever.\n\n        Args:\n            common_context (Any): The common context shared across handlers.\n            context_store (Any): The storage mechanism for context data.\n        \"\"\"\n        self.context_store = context_store\n        self.common_context = context_store\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Handle the incoming request by retrieving relevant context.\n\n        Args:\n            request (Dict[str, Any]): The incoming request to be processed.\n\n        Returns:\n            str: The response after processing the request.\n        \"\"\"\n\n        logger.info(\"retrieving context into chain\")\n        response = request\n\n        context = []\n\n        if \"context_id\" in request:\n            records = self.context_store.query_data(model = ChatHistory, filters= {\"chat_context_id\": request[\"context_id\"]})\n            context.extend(records)\n\n        response[\"context\"] = context\n\n        return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/context_storage.py",
    "content": "from typing import Any\nfrom loguru import logger\nfrom app.base.abstract_handlers import AbstractHandler\nfrom app.models.db import Chat\nimport datetime\n\nclass ContextStorage(AbstractHandler):\n    \"\"\"\n    A handler class for storing chat interactions in the context.\n\n    This class extends AbstractHandler and provides functionality to store\n    chat interactions, including questions, answers, and summaries, in the context store.\n    \"\"\"\n\n    def __init__(self,common_context, context_store) -> None:\n        \"\"\"\n        Initialize the ContextStorage.\n\n        Args:\n            common_context (Any): The common context shared across handlers.\n            context_store (Any): The storage mechanism for context data.\n        \"\"\"\n        self.context_store = context_store\n        self.common_context = context_store\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Handle the incoming request by storing the interaction in the context.\n\n        Args:\n            request (Dict[str, Any]): The incoming request to be processed.\n\n        Returns:\n            str: The response after processing the request.\n        \"\"\"\n\n        logger.info(\"Storing interaction into context\")\n        response = request\n\n        summary = ''\n        if \"summary\" in request:\n            summary = request['summary']\n        if \"context_id\" in request:\n            self.context_store.insert_data(Chat(context_id = request[\"context_id\"], question = request[\"question\"], created_at = datetime.datetime.now(), answer = request[\"content\"], summary = summary))\n\n        return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/document_retriever.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom loguru import logger\nfrom typing import Any\nfrom app.providers.container import Container\nimport asyncio\n\n\n\nclass DocumentRetriever(AbstractHandler):\n    \"\"\"\n    A handler class for retrieving relevant documents based on the input question.\n\n    This class extends AbstractHandler and provides functionality to find and\n    process similar documents from a vector store based on the input question.\n    \"\"\"\n\n    def __init__(self,store, datasources):\n        \"\"\"\n        Initialize the DocumentRetriever.\n\n        Args:\n            store (Any): The vector store for document retrieval.\n        \"\"\"\n\n        self.store =store\n        self.context_relevance_threshold = 4\n        self.datasources = datasources\n\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Handle the incoming request by retrieving relevant documents.\n\n        Args:\n            request (Dict[str, Any]): The incoming request to be processed.\n\n        Returns:\n            str: The response after processing the request.\n        \"\"\"\n\n        logger.info(\"passing through => document_retriever\")\n        response = request\n        tasks = [\n                self.store.find_similar_documentation(datasource, request['question'], 10)\n                for datasource in self.datasources\n            ]\n        results = await asyncio.gather(*tasks)\n\n\n        logger.info(\"sorting retrieved documents\")\n        for index, out in enumerate(results):\n            opt_doc = []\n            if out and len(out) > 0 and out[0]['distances'] < self.context_relevance_threshold:\n                distances = [doc['distances'] for doc in out]\n                if len(out) > 5:\n                    clusters = Container.clustering().kmeans(distances, 2)\n                    shortest_cluster = clusters[0]\n                    for doc in out:\n                        if doc['distances'] in shortest_cluster:\n                            opt_doc.append(doc)\n                else:\n                    opt_doc = out\n\n            if \"rag\" not in response:\n                response[\"rag\"]= {\"context\" : {}}\n            response[\"rag\"][\"context\"][list(self.datasources.keys())[index]] = opt_doc\n\n        return await super().handle(response)\n\n\n\n\n\n"
  },
  {
    "path": "app/chain/modules/executer.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\nfrom app.providers.config import configs\n\n\nclass Executer(AbstractHandler):\n    \"\"\"\n    A handler class for executing queries based on the inference.\n\n    This class extends AbstractHandler and provides functionality to execute\n    queries using the appropriate datasource and handle any errors that occur.\n    \"\"\"\n\n    def __init__(self, common_context, datasource, fallback_handler) -> None:\n        \"\"\"\n        Initialize the Executer.\n\n        Args:\n            common_context (Dict[str, Any]): The common context shared across handlers.\n            datasource (Dict[str, Any]): A dictionary of datasources keyed by intent.\n            fallback_handler (AbstractHandler): The handler to call in case of errors.\n        \"\"\"\n\n        self.fall_back_handler = fallback_handler\n        self.common_context = common_context\n        self.datasource = datasource\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Handle the incoming request by executing the query.\n\n        Args:\n            request (Dict[str, Any]): The incoming request to be processed.\n\n        Returns:\n            str: The response after processing the request.\n        \"\"\"\n        logger.info(\"passing through => executor\")\n\n        inference = request.get(\"inference\", {})\n        formated_sql = inference.get(\"query\", \"\")\n        logger.debug(f\"executing query:{formated_sql}\")\n\n        out, err = self.datasource[self.common_context[\"intent\"]].fetch_data(formated_sql)\n\n\n        if err is not None:\n            logger.error(f\"error in executing query:{err}\")\n            if self.common_context[\"chain_retries\"] < configs.retry_limit :\n                logger.info(\"going back for resolving error\")\n                self.common_context[\"chain_retries\"] =self.common_context[\"chain_retries\"] + 1\n                self.common_context[\"execution_logs\"].append({\"query\": formated_sql, \"error\": str(err)})\n                return await self.fall_back_handler.handle(request)\n\n        response = {**dict(request), **{\n            \"query_response\": out,\n            \"query_error\": err,\n        }}\n\n        return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/follow_up_handler.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\nfrom app.providers.config import configs\nfrom app.loaders.base_loader import BaseLoader\nfrom string import Template\nfrom app.utils.parser import parse_llm_response\nfrom app.chain.formatter.general_response import Formatter\n\nclass FollowupHandler(AbstractHandler):\n    \"\"\"\n    A handler class for processing follow-up queries and extracting required parameters.\n\n    This class extends AbstractHandler and provides functionality to process\n    follow-up queries, extract intent-specific parameters, and generate appropriate responses.\n    \"\"\"\n\n    def __init__(self, common_context , model_configs) -> None:\n        \"\"\"\n        Initialize the FollowupHandler.\n\n        Args:\n            common_context (Dict[str, Any]): The common context shared across handlers.\n            model_configs (Dict[str, Any]): Configuration for the models used in processing.\n        \"\"\"\n\n        self.model_configs = model_configs\n        self.common_context = common_context\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Handle the incoming request by processing follow-up queries and extracting parameters.\n\n        Args:\n            request (Dict[str, Any]): The incoming request to be processed.\n\n        Returns:\n            str: The response after processing the request.\n        \"\"\"\n        response = request\n        logger.info(\"passing through => Intent extractor\")\n\n        use_case = self.model_configs.get(\"use_case\", {})\n        capabilities = use_case.get(\"capabilities\", [])\n\n        intent_extracted = request.get(\"intent_extractor\")\n        intent = intent_extracted.get(\"intent\", \"\")\n\n        filtered_capabilities = [capability for capability in capabilities if capability[\"name\"]== intent]\n        capability = filtered_capabilities[0]\n\n\n        long_description = use_case[\"long_description\"]\n        capability_description = capability[\"description\"]\n        parameter_description = \"\"\n\n        parameters = capability[\"requirements\"]\n        for parameter in parameters:\n            parameter_description= parameter_description + parameter[\"parameter_name\"]+ \" : \"+ parameter[\"parameter_description\"]+\"\\n\"\n\n        prompt = \"\"\"\n                You are part of a Form automations system where your duty is to: $capability_description\n                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.\n\n                -- Form system context ---\n                $long_description\n                -- Form system context ---\n\n                Required parameters\n                -- Parameter section ---\n                $parameter_description\n                --- Parameter section ---\n\n                Instructions:\n                Carefully review all previous messages to establish context.\n                Only extract values that are explicitly provided in previous messages.\n                Do not assume or fill in any values that are not present in previous messages.\n                Do not hallucinate or claim that required values are present when they are not.\n\n                Generate a JSON response in the following format for the query '$question':\n                {\n                  \"explanation\": \"Describe which required values were found in previous messages and how they were extracted. If no values were found, state this clearly.\",\n                  \"params\": {},dont extract values for the params which is not mentioned in previous messages\n                  \"completed\": \"true|false, if all the required values are captured\",\n                  \"message\": \"Ask for specific required parameters that have not been provided yet. If all parameters are captured, provide a success message for the booking.\",\n                  \"summary\" : \"summarise question and answer in one sentence\"\n                }\n          \"\"\"\n\n        contexts = request.get(\"context\", [])\n        contexts = contexts[-5:] if len(contexts) >= 5 else contexts\n\n        prompt = Template(prompt).safe_substitute(\n            question = request[\"question\"],\n            long_description= long_description,\n            capability_description= capability_description,\n            parameter_description=parameter_description\n        )\n\n\n        loader = BaseLoader(model_configs=self.model_configs[\"models\"])\n        infernce_model = loader.load_model(configs.inference_llm_model)\n\n        output, response_metadata = infernce_model.do_inference(\n                            prompt, contexts\n                    )\n        \n        if output[\"error\"] is not None:\n            return await Formatter.format(\"Oops! Something went wrong. Try Again!\",output['error'])\n\n        response[\"inference\"] = parse_llm_response(output['content'])\n        response[\"capability\"] = capability\n        return await super().handle(response)\n\n\n"
  },
  {
    "path": "app/chain/modules/followup_interpreter.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\nfrom app.chain.formatter.general_response import Formatter\n\nclass FollowupInterpreter(AbstractHandler):\n    \"\"\"\n    A handler class for interpreting follow-up responses and formatting them.\n\n    This class extends AbstractHandler and provides functionality to interpret\n    the inference results from follow-up queries and format the response accordingly.\n    \"\"\"\n\n\n    def __init__(self, common_context, general_chain) -> None:\n        \"\"\"\n        Initialize the FollowupInterpreter.\n\n        Args:\n            common_context (Dict[str, Any]): The common context shared across handlers.\n            general_chain (Any): The general processing chain for fallback scenarios.\n        \"\"\"\n\n        self.common_context = common_context\n        self.general_chain = general_chain\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Handle the incoming request by interpreting the inference results and formatting the response.\n        Args:\n            request (Dict[str, Any]): The incoming request to be processed.\n\n        Returns:\n            str: The formatted response after processing the request.\n        \"\"\"\n\n        logger.info(\"passing through => interpreter\")\n        response = request\n\n        if \"inference\" in request:\n            inference = request[\"inference\"]\n            if inference[\"completed\"] == True or inference[\"completed\"] == \"true\":\n                logger.info(\"Intent completed, trigger the action\")\n\n            response = Formatter.format(inference[\"message\"],\"\")\n            response[\"summary\"] = request[\"inference\"][\"summary\"]\n            response[\"question\"] = request[\"question\"]\n            response[\"context_id\"] = request[\"context_id\"]\n        else:\n            logger.info(\"No intents detected\")\n            response = Formatter.format(\"Sorry, I didn't get that\",\"\")\n\n        return await super().handle(response)\n\n"
  },
  {
    "path": "app/chain/modules/general_answer_generator.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom app.providers.config import configs\nfrom app.loaders.base_loader import BaseLoader\nfrom app.utils.parser import markdown_parse_llm_response\nfrom app.chain.formatter.general_response import Formatter\nfrom loguru import logger\n\nclass GeneralAnswerGenerator(AbstractHandler):\n        \"\"\"\n        A handler class for generating inferences based on prompts and contexts.\n\n        This class extends AbstractHandler and provides functionality to generate\n        inferences using a specified language model based on given prompts and contexts.\n        \"\"\"\n\n        def __init__(self, common_context, model_configs) -> None:\n                \"\"\"\n                Initialize the Generator.\n\n                Args:\n                common_context (Dict[str, Any]): The common context shared across handlers.\n                model_configs (Dict[str, Any]): Configuration for the models used in processing.\n                \"\"\"\n                self.model_configs = model_configs\n                self.common_context = common_context\n\n        async def handle(self, request: dict) -> str:\n                \"\"\"\n                Handle the incoming request by generating an inference based on the prompt and context.\n\n                This method extracts the prompt and context from the request, uses an inference model\n                to generate a response, and adds the parsed inference to the response.\n\n                Args:\n                request (Dict[str, Any]): The incoming request to be processed.\n\n                Returns:\n                str: The response after processing the request, including the generated inference.\n                \"\"\"\n                logger.info(\"passing through => generator\")\n\n                response = request\n                prompt = response[\"prompt\"]\n\n                contexts = request.get(\"context\",[])\n                contexts = contexts[-5:] if len(contexts) >= 5 else contexts\n\n                loader = BaseLoader(model_configs=self.model_configs[\"models\"])\n                infernce_model = loader.load_model(configs.inference_llm_model)\n\n                output, response_metadata = infernce_model.do_inference(\n                        prompt, contexts\n                )\n                if output[\"error\"] is not None:\n                        return Formatter.format(\"Oops! Something went wrong. Try Again!\",output['error'])\n\n                response[\"inference\"] = markdown_parse_llm_response(output['content'])\n                if not response[\"inference\"]:\n                        return Formatter.format(\"Oops! Something went wrong. Try Again!\",\"\")\n\n                return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/generator.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom app.providers.config import configs\nfrom app.loaders.base_loader import BaseLoader\nfrom app.utils.parser import parse_llm_response\nfrom app.chain.formatter.general_response import Formatter\nfrom loguru import logger\n\nclass Generator(AbstractHandler):\n        \"\"\"\n        A handler class for generating inferences based on prompts and contexts.\n\n        This class extends AbstractHandler and provides functionality to generate\n        inferences using a specified language model based on given prompts and contexts.\n        \"\"\"\n\n        def __init__(self, common_context, model_configs) -> None:\n                \"\"\"\n                Initialize the Generator.\n\n                Args:\n                common_context (Dict[str, Any]): The common context shared across handlers.\n                model_configs (Dict[str, Any]): Configuration for the models used in processing.\n                \"\"\"\n                self.model_configs = model_configs\n                self.common_context = common_context\n\n        async def handle(self, request: dict) -> str:\n                \"\"\"\n                Handle the incoming request by generating an inference based on the prompt and context.\n\n                This method extracts the prompt and context from the request, uses an inference model\n                to generate a response, and adds the parsed inference to the response.\n\n                Args:\n                request (Dict[str, Any]): The incoming request to be processed.\n\n                Returns:\n                str: The response after processing the request, including the generated inference.\n                \"\"\"\n                logger.info(\"passing through => generator\")\n\n                response = request\n                prompt = response[\"prompt\"]\n\n                loader = BaseLoader(model_configs=self.model_configs[\"models\"])\n                infernce_model = loader.load_model(configs.inference_llm_model)\n\n\n                output, response_metadata = infernce_model.do_inference(\n                        prompt, []\n                )\n                if output[\"error\"] is not None:\n                        return Formatter.format(\"Oops! Something went wrong. Try Again!\",output['error'])\n\n                response[\"inference\"] = parse_llm_response(output['content'])\n                if not response[\"inference\"]:\n                        return Formatter.format(\"Oops! Something went wrong. Try Again!\",\"\")\n\n                return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/input_formatter.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\n\n\nclass InputFormatter(AbstractHandler):\n\n    async def handle(self, request: Any) -> str:\n        logger.info(\"passing through => input_formatter\")\n\n        response = request\n        return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/intent_extracter.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\nfrom app.providers.config import configs\nfrom app.loaders.base_loader import BaseLoader\nfrom string import Template\nfrom app.chain.formatter.general_response import Formatter\nfrom app.utils.parser import parse_llm_response\n\n\nclass IntentExtracter(AbstractHandler):\n    \"\"\"\n    A handler for extracting user intents from chat queries based on a provided use case configuration.\n\n    This class processes chat requests to determine the intent behind user queries using a language model.\n    It generates a prompt with the chat context, available intents, and instructions to guide the model in\n    intent extraction.\n\n    Attributes:\n        common_context (Any): Shared context information used across handlers.\n        model_configs (dict): Configuration settings for the model, including use case details and model paths.\n    \"\"\"\n\n    def __init__(self, common_context , model_configs, datasources) -> None:\n        \"\"\"\n        Initializes the IntentExtractor with common context and model configurations.\n\n        Args:\n            common_context (Any): Shared context information used across handlers.\n            model_configs (dict): Configuration settings for the model.\n        \"\"\"\n        self.model_configs = model_configs\n        self.common_context = common_context\n        self.datasources = datasources\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Processes the request to extract the intent from the user's query.\n\n        Args:\n            request (Any): The incoming request containing the user query and context.\n\n        Returns:\n            str: The result of the superclass's handle method with updated response information.\n        \"\"\"\n\n        response = request\n        logger.info(\"passing through => Intent extractor\")\n\n\n        use_case = self.model_configs.get(\"use_case\", {})\n        long_description = use_case.get(\"long_description\", \"\")\n        short_description = use_case.get(\"short_description\", \"\")\n        capabilities = use_case.get(\"capabilities\", [])\n        rag = request.get(\"rag\", {})\n        context = rag.get(\"context\", {})\n\n        capability_description = \"\"\n        capability_names = [\"out_of_context\"]\n\n        for capability in capabilities:\n            name = capability[\"name\"]\n            description = capability[\"description\"]\n            capability_names.append(name)\n            capability_description += f\"{name} : {description}\\n\"\n\n\n        datasources = self.model_configs.get(\"datasources\", [])\n        datasource_names = []\n        for datasource in datasources:\n            if datasource[\"name\"] in self.datasources:\n                if self.datasources[datasource[\"name\"]].__category__ in [2,5] and \"metadata_inquiry\" not in capability_names:\n                    capability_names.append(\"metadata_inquiry\")\n                name = datasource[\"name\"]\n                description = datasource[\"description\"]\n\n                capability_names.append(name)\n                datasource_names.append(name)\n                capability_description += f\"\\n{name} : {description}\\n\"\n                datasource_context = context[name]\n                for index,cont in enumerate(datasource_context[:2]):\n                    if index == 0:\n                        capability_description += f\"{cont.get('document','')}\\n\"\n                    else:\n                        capability_description += f\"{cont.get('document','')}\\n\"\n\n                \n        response[\"available_datasources\"] = datasource_names\n\n        if \"metadata_inquiry\" in capability_names:\n            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\"\n\n        chat_contexts = request.get(\"context\", [])\n        previous_intent = chat_contexts[-1].chat_answer.get(\"intent\",\"\") if len(chat_contexts) > 0 else \"None\"\n\n        prompt = \"\"\"\n        You are part of a chatbot system where you have to extract intent from users chats and match it with given intents.\n\n        -- chatbot context ---\n        $long_description\n        Also provide data structure information and overview of available data.\n        -- chatbot context ---\n\n        Available intents are:\n        -- Intent section ---\n        $capabilities\n        out_of_context: If chat is irrelevant to chatbot context and its capabilities\n        --- Intent section ---\n\n        Previous last message Intent : $previous_intent\n\n        Instructions:\n        1.Only one intent must be identified.Multiple intents are prohibited.\n        2.Pay special attention to whether the previous intent has been completed.\n        3.Strictly only if the current user query doesn't clearly match an intent, consider the previous messages to identify the most appropriate intent.\n        4.When asked to list possible questions, provide general examples without mentioning \"specific\" word\n\n        Generate a response for the user query '$question' in the following JSON format:\n\n        {\n            \"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.\",\n            \"intent\": \"Detected intent, strictly one from the $capability_list\"\n        }\n        \"\"\"\n\n\n\n        capability_list = \"|\".join(capability_names)\n\n        prompt = Template(prompt).safe_substitute(\n            question = request[\"question\"],\n            long_description = long_description,\n            short_description =short_description,\n            capability_list = capability_list,\n            capabilities= capability_description,\n            previous_intent = previous_intent\n        )\n        logger.debug(f\"intent prompt:{prompt}\")\n\n        loader = BaseLoader(model_configs=self.model_configs[\"models\"])\n        infernce_model = loader.load_model(configs.inference_llm_model)\n\n        output, response_metadata = infernce_model.do_inference(\n                            prompt, chat_contexts\n                    )\n        if output[\"error\"] is not None:\n            return Formatter.format(\"Oops! Something went wrong. Try Again!\",output['error'])\n\n        response[\"available_intents\"] = capability_names\n\n        response[\"intent_extractor\"] = parse_llm_response(output['content'])\n            \n        response[\"rag_filters\"] = {\n            \"datasources\" : response.get('intent_extractor', {}).get('intent', ''),\n            \"document_count\" : 5,\n            \"schema_count\" : 5\n        }\n        return await super().handle(response)"
  },
  {
    "path": "app/chain/modules/metadata_generator.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\nfrom app.providers.config import configs\nfrom app.loaders.base_loader import BaseLoader\nfrom string import Template\nfrom app.utils.parser import markdown_parse_llm_response\nfrom app.chain.formatter.general_response import Formatter\n\n\n\nclass MetadataGenerator(AbstractHandler):\n\n    def __init__(self, common_context , model_configs, datasources) -> None:\n        self.model_configs = model_configs\n        self.common_context = common_context\n        self.datasources = datasources\n\n    async def handle(self, request: Any) -> str:\n        response = request\n        logger.info(\"passing through => Metadata description generator\")\n        rag = request[\"rag\"]\n        contexts = \"\"\n        for datasource_name, handler in self.datasources.items():\n            if handler.__category__ in [2,5]:\n                rag_contexts = rag.get(\"context\", {}).get(datasource_name,\"\")\n                for index,cont in enumerate(rag_contexts):\n                    if index==0:\n                        contexts += \"\\n\\n\" + \"Plugin/Database Name: \"+ datasource_name + \"\\n\" + cont[\"document\"] \n                    else:\n                        contexts +=  \"\\n\" + cont[\"document\"]\n                    \n\n        prompt = \"\"\"\n            You are part of a chatbot system where you need to answer user questions based on the given database schema and context.\n            Please review the following information carefully:\n\n            A brief description about the schema is given below:\n            -- start db schema context section--\n            $context\n            -- end db schema context section--\n\n            Make sure to follow these:\n            1. Use the provided schema and context to inform your answer.\n            2. while listing tables and its columns strictly mention under which plugin name it is.\n            3. Provide accurate information based on the available data.\n            4. Keep the answer concise and with minimal explanation\n            5. If the question cannot be fully answered with the given information, explain what can be answered and what additional information might be needed.\n            6. Present the answer in a human-readable Markdown format\n            7. Give only what user wants, don't hallucinate to give long answers\n\n            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:\n            {\n            \"general_message\": \"Provide a concise human-readable answer in Markdown format to the user's question using the available information\",\n            }\n        \"\"\"\n\n        prompt = Template(prompt).safe_substitute(question = request[\"question\"], context =contexts)\n        response[\"prompt\"] = prompt\n        logger.info(f\"prompt:{prompt}\")\n        chat_history = []\n        if \"context\" in request and len(request[\"context\"]) > 0:\n            chat_history = request[\"context\"]\n            chat_history = chat_history[-7:] if len(chat_history) >= 7 else chat_history\n\n        loader = BaseLoader(model_configs=self.model_configs[\"models\"])\n        infernce_model = loader.load_model(configs.inference_llm_model)\n\n        output, response_metadata = infernce_model.do_inference(\n                            prompt, chat_history\n                    )\n        if output[\"error\"] is not None:\n            return Formatter.format(\"Oops! Something went wrong. Try Again!\",output['error'])\n\n        response[\"inference\"] = markdown_parse_llm_response(output['content'])\n\n        response[\"summary\"] = \"\"\n        return await super().handle(response)"
  },
  {
    "path": "app/chain/modules/metadata_ragfilter.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\n\n\nclass MetadataRagFilter(AbstractHandler):\n    \"\"\"\n    A handler for applying RAG (retrieval-augmented generation) filters based on metadata.\n\n    This class modifies the request's response to include RAG filters, setting the number of documents and schemas\n    to be considered in retrieval operations. It also includes tracing for monitoring and debugging purposes.\n\n    Inherits from:\n        AbstractHandler: A base class for handling requests in the application.\n\n    Methods:\n        handle(request: Any) -> str:\n            Processes the request to apply RAG filters and forwards it to the next handler.\n    \"\"\"\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Applies RAG filters to the request's response and forwards it to the next handler.\n\n        Args:\n            request (Any): The incoming request containing the necessary information for filtering.\n\n        Returns:\n            str: The result of the superclass's handle method with updated response information.\n        \"\"\"\n        logger.info(\"passing through => metadata_ragfilter\")\n        response = request\n        response[\"rag_filters\"] = {\n                \"datasources\": response.get(\"available_datasources\", []),\n                \"document_count\": 50,\n                \"schema_count\": 10\n        }\n\n\n        return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/ouput_formatter.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\n\n\nclass OutputFormatter(AbstractHandler):\n    \"\"\"\n    A handler for formatting the output based on the provided inference and query responses.\n\n    This class processes the response from a query, formats it based on the available data and inference results,\n    and prepares it for further handling. It manages content, context, and additional metadata.\n\n    Attributes:\n        common_context (dict): Shared context information used across handlers.\n        datasource (dict): A dictionary for data formatting based on the intent.\n    \"\"\"\n\n    def __init__(self,common_context, datasource):\n        \"\"\"\n        Initializes the OutputFormatter with common context and datasource.\n\n        Args:\n            common_context (dict): Shared context information used across handlers.\n            datasource (dict): A dictionary for data formatting based on the intent.\n        \"\"\"\n        self.datasource = datasource\n        self.common_context = common_context\n\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Formats the response based on the inference and query response.\n\n        Args:\n            request (Any): The incoming request containing inference results and query response.\n\n        Returns:\n            str: The result of the superclass's handle method with updated response information.\n        \"\"\"\n\n        logger.info(\"passing through => output_formatter\")\n\n        input_data = request.get(\"inference\", {})\n        response = {}\n\n        if \"main_entity\" in input_data and \"operation_kind\" in input_data :\n            intent_key = self.common_context.get(\"intent\")\n            if intent_key in self.datasource:\n                response = self.datasource[intent_key].format(request.get(\"query_response\"), input_data)\n        elif \"general_message\" in input_data:\n            response[\"content\"] = str(input_data.get('general_message'))\n\n\n        if \"data\" in response and isinstance(response[\"data\"], list) and len(response[\"data\"]) == 0:\n            if  \"empty_message\" in input_data:\n                response[\"content\"] = input_data[\"empty_message\"]\n            else:\n                response[\"content\"] = \"I didn't find any data matching the query\"\n            response[\"main_format\"] = \"general_chat\"\n        elif \"kind\" in response and response[\"kind\"] == \"none\":\n            response[\"content\"] = input_data.get(\"empty_message\", \"I didn't find any relevant data regarding this, please reframe your query\")\n            response[\"main_format\"] = \"general_chat\"\n\n\n        response[\"next_questions\"] = input_data.get(\"next_questions\", [])\n\n        if \"context_id\" in request:\n            response[\"context_id\"] = request[\"context_id\"]\n            response[\"question\"] = request[\"question\"]\n\n        response[\"query\"] = input_data.get(\"query\", '')\n        response[\"intent\"] = request.get(\"intent_extractor\", {}).get(\"intent\",\"\")\n        response[\"summary\"] = request.get(\"summary\", '')\n        logger.debug(f\"content: {response.get('content')}\")\n\n\n        return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/post_processor.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\n\nclass PostProcessor(AbstractHandler):\n\n    async def handle(self, request: Any) -> str:\n        logger.info(\"passing through => post_processor\")\n        response = request\n        return response\n"
  },
  {
    "path": "app/chain/modules/prompt_generator.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\nfrom string import Template\n\nclass PromptGenerator(AbstractHandler):\n    \"\"\"\n    A handler for generating prompts based on the provided context, model configurations, and data sources.\n\n    This class creates a formatted prompt for the model by combining various elements such as system prompts,\n    user prompts, and context information. It supports both manual and automatic prompt injection modes.\n\n    Attributes:\n        common_context (dict): Shared context information used across handlers.\n        model_configs (dict): Configuration settings for the model, including prompt injection settings.\n        datasources (dict): Data sources for generating prompt contexts based on intent.\n    \"\"\"\n\n\n    def __init__(self, common_context , model_configs, datasources) -> None:\n        \"\"\"\n        Initializes the PromptGenerator with common context, model configurations, and data sources.\n\n        Args:\n            common_context (dict): Shared context information used across handlers.\n            model_configs (dict): Configuration settings for the model.\n            datasources (dict): Data sources for generating prompt contexts based on intent.\n        \"\"\"\n\n        self.model_configs = model_configs\n        self.common_context = common_context\n        self.datasources = datasources\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Generates a prompt based on the incoming request and provided configurations.\n        Args:\n            request (Any): The incoming request containing data for prompt generation.\n\n        Returns:\n            str: The result of the superclass's handle method with the generated prompt included in the response.\n        \"\"\"\n\n        logger.info(\"passing through => prompt_generator\")\n        response = request\n        intent = response[\"intent_extractor\"]['intent']\n\n        contexts = request.get(\"context\",[])\n        previous_messages = contexts[-5:] if len(contexts) >= 5 else contexts\n\n        recal_history = \"\"\n        for message in previous_messages:\n            recal_history += f\"USER: {message.chat_query}\\n\"\n            answer = message.chat_answer\n            recal_history += f\"ASSITANT: {answer.get('query','')}\\n\\n\"\n\n        # Few shot prompting\n        samples_retrieved = \"\"\n\n        rag = request.get(\"rag\", {})\n        suggestions = rag.get(\"suggestions\", [])\n        for doc in suggestions:\n            samples_retrieved += f\"question: {doc.get('document', '')}\\n\"\n            samples_retrieved += f\"query: {doc.get('metadatas', {}).get('query', '')}\\n\\n\"\n\n\n        prompt_injection = self.model_configs.get(\"prompt_injection\", {\"mode\": \"auto\"})\n        data_source = self.datasources.get(self.common_context.get(\"intent\", \"default\"))\n\n        context = data_source.__prompt__\n        prompt = context.base_prompt\n\n\n        system_prompt = \"\"\n\n        if prompt_injection[\"mode\"] == \"manual\" :\n            system_prompt_context = context.system_prompt\n            system_prompt = system_prompt_context.template.format(\n                **{**system_prompt_context[\"prompt_variables\"]}\n            )\n        else:\n            auto_context = \"\\n\\n\".join(cont[\"document\"] for cont in rag.get(\"context\", {}).get(intent,[]))\n            auto_schema = \"\\n\\n\".join(schema[\"document\"] for schema in rag.get(\"schema\", []))\n            system_prompt_context = context.system_prompt\n            system_prompt = system_prompt_context.template.format(\n                schema=auto_schema,\n                context=auto_context,\n                question=request.get(\"question\", \"\"),\n                suggestions=\"\",\n                recal_history=recal_history\n            )\n\n\n        user_prompt = \"\"\n\n        if self.common_context[\"chain_retries\"] == 0:\n            user_prompt = context.user_prompt.template\n        else:\n            logger.info(\"regenerating prompt using available context\")\n            regeneration_promt_context = context.regeneration_prompt\n\n            user_prompt = Template(regeneration_promt_context.template).safe_substitute(\n                exception_log =self.common_context[\"execution_logs\"][0][\"error\"] if len(self.common_context[\"execution_logs\"])>0 else \"\",\n                query_generated =self.common_context[\"execution_logs\"][0][\"query\"] if len(self.common_context[\"execution_logs\"])>0 else \"\"\n            )\n\n        final_prompt = prompt.format(user_prompt=user_prompt, system_prompt=system_prompt)\n        final_prompt = Template(final_prompt).safe_substitute(\n            question=request.get(\"question\", \"\"),\n            suggestions=samples_retrieved,\n            **self.model_configs.get(\"use_case\", {})\n        )\n\n        response[\"prompt\"] = final_prompt\n        logger.debug(f\"final_prompt:{final_prompt}\")\n        return await super().handle(response)\n"
  },
  {
    "path": "app/chain/modules/router.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\nfrom app.chain.formatter.general_response import Formatter\n\n\nclass Router(AbstractHandler):\n    \"\"\"\n    A handler that routes requests to appropriate handlers based on the detected intent.\n\n    The Router class determines the correct handler to process the request based on the intent extracted\n    from the request. It forwards the request to the appropriate handler or returns a fallback response\n    if no suitable handler is found.\n\n    Attributes:\n        fallback_handler (AbstractHandler): Handler to process requests that do not match any specific intent.\n        general_handler (AbstractHandler): Handler for general intent processing.\n        capability_handler (AbstractHandler): Handler for capability-related intents.\n        metadata_handler (AbstractHandler): Handler for metadata-related intents.\n    \"\"\"\n\n\n    def __init__(self, common_context, fallback_handler, intent_handler, general_handler, capability_handler, metadata_handler) -> None:\n        \"\"\"\n        Initializes the Router with the provided handlers.\n\n        Args:\n            common_context (dict): Shared context information used across handlers.\n            fallback_handler (AbstractHandler): Handler for fallback responses.\n            general_handler (AbstractHandler): Handler for general intent processing.\n            capability_handler (AbstractHandler): Handler for capability-related intents.\n            metadata_handler (AbstractHandler): Handler for metadata-related intents.\n        \"\"\"\n\n        self.fallback_handler = fallback_handler\n        self.forwared_handler = intent_handler\n        self.general_handler = general_handler\n        self.capability_handler = capability_handler\n        self.metadata_handler = metadata_handler\n\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Routes the request to the appropriate handler based on the detected intent.\n\n\n        Args:\n            request (Any): The incoming request containing intent information.\n\n        Returns:\n            str: The result of the handled request.\n        \"\"\"\n\n        logger.info(\"passing through => Router\")\n        response = request\n\n        intent_extractor = request.get(\"intent_extractor\", {})\n        intent = intent_extractor.get(\"intent\", \"\")\n\n        if intent:\n            if intent in  self.forwared_handler.data_sources:\n                datasource = self.forwared_handler.data_sources[intent]\n\n                if datasource.__category__ == 2 or datasource.__category__ == 5:\n                    logger.info(\"entered database workflow\")\n                    return await self.forwared_handler.invoke(request)\n                else:\n                    logger.info(\"entered default workflow\")\n                    return await self.general_handler.invoke(request)\n\n            elif intent == \"metadata_inquiry\":\n                return await self.metadata_handler.invoke(request)\n            elif intent in request.get(\"available_intents\", []) and intent != \"out_of_context\":\n                return await self.capability_handler.invoke(request)\n            else:\n                response = Formatter.format(\"Sorry, I can't help you with that. Is there anything i can help you with ?\",\"\")\n                return await self.fallback_handler.handle(response)\n\n        else:\n            logger.info(\"No intents detected\")\n            response = Formatter.format(\"Sorry, I can't help you with that. Is there anything i can help you with ?\",\"\")\n            return await self.fallback_handler.handle(response)\n\n"
  },
  {
    "path": "app/chain/modules/schema_retriever.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom loguru import logger\nfrom typing import Any\nfrom app.providers.container import Container\n\n\n\nclass SchemaRetriever(AbstractHandler):\n    \"\"\"\n    A handler for retrieving similar schemas based on a given question and context.\n\n    This class queries the store for schemas similar to the input question and context. It processes the\n    retrieved schemas to potentially cluster them and select the most relevant schemas based on certain criteria.\n\n    Attributes:\n        store (object): The data store used to find similar schemas.\n    \"\"\"\n\n    def __init__(self,store,datasources):\n        \"\"\"\n        Initializes the SchemaRetriever with the provided store.\n\n        Args:\n            store (object): The data store used for schema retrieval.\n        \"\"\"\n        self.store = store\n        self.datasources = datasources\n\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Retrieves similar schemas from the store and updates the response with the results.\n\n        Args:\n            request (Any): The incoming request containing the question, context, and filtering criteria.\n\n        Returns:\n            Dict[str, Any]: The updated response dictionary with retrieved schemas.\n        \"\"\"\n\n        logger.info(\"passing through => schema_retriever\")\n\n        response = request\n\n        schema_count = request.get('rag_filters', {}).get(\"schema_count\", 0)\n\n        auto_context = \"\\n\\n\".join(cont.get(\"document\", \"\") for cont in request.get(\"rag\", {}).get(\"context\", []))\n        intent = request.get(\"intent_extracter\",{}).get(\"intent\",\"\")\n\n        datasource = self.datasources[intent]\n        out = await self.store.find_similar_schema(datasource, request[\"question\"] + \"\\n\" + auto_context, schema_count)\n\n        if out and len(out) > 0:\n            distances = [doc['distances'] for doc in out]\n            if len(out) > 2:\n                clusters = Container.clustering().kmeans(distances, 2)\n                shortest_cluster = clusters[0]\n                opt_doc = [doc for doc in out if doc.get('distances') in shortest_cluster]\n            else:\n                opt_doc = out\n\n            response[\"rag\"].update({\n                 \"schema\":    opt_doc,\n            })\n        else:\n            response[\"rag\"].update({\n                \"schema\": [],\n            })\n\n        return await super().handle(response)\n\n\n\n\n\n"
  },
  {
    "path": "app/chain/modules/validator.py",
    "content": "from app.base.abstract_handlers import AbstractHandler\nfrom typing import Any\nfrom loguru import logger\nfrom app.chain.formatter.general_response import Formatter\n\nclass Validator(AbstractHandler):\n    \"\"\"\n    A handler for validating queries generated by the system.\n\n    This class validates the generated SQL queries against the data source and returns an appropriate response\n    if there are validation issues.\n\n    Attributes:\n        common_context (dict): Shared context information used for formatting responses and accessing intent-specific data.\n        datasource (dict): Data source used to validate the generated SQL queries.\n    \"\"\"\n\n    def __init__(self,common_context,datasource) -> None:\n        \"\"\"\n        Initializes the Validator with the provided context and datasource.\n\n        Args:\n            common_context (dict): Shared context information used for validation and response formatting.\n            datasource (dict): Data source used for query validation.\n        \"\"\"\n\n        super().__init__()\n        self.common_context = common_context\n        self.datasource = datasource\n\n    async def handle(self, request: Any) -> str:\n        \"\"\"\n        Validates the generated SQL query and updates the response if there are validation issues.\n\n        Args:\n            request (Any): The incoming request containing the generated query and other relevant information.\n\n        Returns:\n            str: The result of the handled request or an error message if validation fails.\n        \"\"\"\n        logger.info(\"passing through => query_validator\")\n        response = request\n\n        inference = request.get(\"inference\", {})\n        formated_sql = inference.get(\"query\", \"\")\n\n        if formated_sql:\n            intent = self.common_context.get(\"intent\", \"\")\n            validator = self.datasource.get(intent, None)\n\n            if validator:\n                result = validator.validate(formated_sql)\n                if result:\n                    logger.critical(f\"Generated Query Validation Issue: {result}\")\n                    return Formatter.format(result,\"\")\n\n        return await super().handle(response)\n"
  },
  {
    "path": "app/embeddings/cohere/__init__.py",
    "content": "from collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n\n__provider_name__ = \"cohere\"\n__vectordb_name__ = [\"chroma\"]\n__icon__ = '/assets/embeddings/logos/cohere.svg'\n__connection_args__ = [\n    {\n        \"config\": [\"api_key\"],\n        \"models\": [\n                \"large\"\n        ]\n    }\n]\n\n\n\n\n\n__all__ = [\n    __vectordb_name__, __connection_args__, __provider_name__, __icon__\n]"
  },
  {
    "path": "app/embeddings/cohere/handler.py",
    "content": "\nimport chromadb.utils.embedding_functions as embedding_functions\nfrom loguru import logger\n\n\nclass CohereEm:\n    def __init__(self,model_name:str = \"\",api_key:str = \"\"):\n        logger.info(\"Initialising embedding providers\")\n        self.ef = embedding_functions.CohereEmbeddingFunction(api_key=api_key,  model_name= model_name)\n\n    def load_emb(self):\n        return self.ef\n\n    def health_check(self) -> None:\n        pass\n\n\n\n\n"
  },
  {
    "path": "app/embeddings/default/chroma_default.py",
    "content": "import chromadb.utils.embedding_functions as embedding_functions\n\nfrom loguru import logger\n\nclass ChromaDefaultEmbedding:\n    def __init__(self):\n        logger.info(\"Initialising embedding providers\")\n        self.ef = embedding_functions.DefaultEmbeddingFunction()\n\n    def load_emb(self):\n        return self.ef\n    \n\n"
  },
  {
    "path": "app/embeddings/default/default.py",
    "content": "from .onnx import DefaultEmbeddingModel\nfrom .chroma_default import ChromaDefaultEmbedding\n\nfrom loguru import logger\nclass DefaultEmbedding:\n    def __init__(self, vectordb_key: str = \"chroma\"):\n        logger.info(\"Initializing embedding providers\")\n        self.vectordb = vectordb_key\n\n    def load_emb(self):\n        match self.vectordb:\n            case \"chroma\":\n                return ChromaDefaultEmbedding().load_emb()\n            case \"mongodb\":\n                return DefaultEmbeddingModel()\n            case _:\n                logger.error(f\"Unsupported vectordb_key: {self.key}\")\n                return None\n\n    def health_check(self) -> None:\n        pass\n"
  },
  {
    "path": "app/embeddings/default/onnx.py",
    "content": "import os\nimport requests\nimport numpy as np\nfrom tokenizers import Tokenizer\nimport onnxruntime as ort\nfrom typing import List\nfrom loguru import logger\n\nMODEL_ID = \"sentence-transformers/all-MiniLM-L6-v2\"\nTOKENIZER_URL = \"https://raw.githubusercontent.com/chroma-core/onnx-embedding/main/onnx/tokenizer.json\"\nMODEL_URL = \"https://github.com/chroma-core/onnx-embedding/raw/main/onnx/model.onnx?download=\"\n\n# Function to download files from a URL and save them locally\ndef download_file(url: str, local_path: str):\n    response = requests.get(url)\n    response.raise_for_status()  # Check if the download is successful\n    with open(local_path, 'wb') as f:\n        f.write(response.content)\n\n# Ensure that the directory exists\ndef ensure_dir(path):\n    if not os.path.exists(path):\n        os.makedirs(path)\n\n# Use PyTorch's default epsilon for division by zero\ndef normalize(v):\n    norm = np.linalg.norm(v, axis=1)\n    norm[norm == 0] = 1e-12\n    return v / norm[:, np.newaxis]\n\n# Sample implementation of the default sentence-transformers model using ONNX\nclass DefaultEmbeddingModel():\n\n    def __init__(self):\n        # Define paths to save the tokenizer and model\n        embedding_dir = os.path.join(os.getcwd(), \"embeddings\", \"onnx\")\n        ensure_dir(embedding_dir)\n\n        tokenizer_path = os.path.join(embedding_dir, \"tokenizer.json\")\n        model_path = os.path.join(embedding_dir, \"model.onnx\")\n\n        # Download the tokenizer and model from GitHub if they don't exist locally\n        if not os.path.isfile(tokenizer_path):\n            logger.info(\"Downloading tokenizer...\")\n            download_file(TOKENIZER_URL, tokenizer_path)\n\n        if not os.path.isfile(model_path):\n            logger.info(\"Downloading ONNX model...\")\n            download_file(MODEL_URL, model_path)\n\n        # Load the tokenizer\n        self.tokenizer = Tokenizer.from_file(tokenizer_path)\n        self.tokenizer.enable_truncation(max_length=256)\n        self.tokenizer.enable_padding(pad_id=0, pad_token=\"[PAD]\", length=256)\n\n        # Load the ONNX model\n        self.model = ort.InferenceSession(model_path)\n\n    def __call__(self, documents: List[str], batch_size: int = 32):\n        all_embeddings = []\n        for i in range(0, len(documents), batch_size):\n            batch = documents[i:i + batch_size]\n            encoded = [self.tokenizer.encode(d) for d in batch]\n            input_ids = np.array([e.ids for e in encoded])\n            attention_mask = np.array([e.attention_mask for e in encoded])\n            onnx_input = {\n                \"input_ids\": np.array(input_ids, dtype=np.int64),\n                \"attention_mask\": np.array(attention_mask, dtype=np.int64),\n                \"token_type_ids\": np.array([np.zeros(len(e), dtype=np.int64) for e in input_ids], dtype=np.int64),\n            }\n            model_output = self.model.run(None, onnx_input)\n            last_hidden_state = model_output[0]\n            # Perform mean pooling with attention weighting\n            input_mask_expanded = np.broadcast_to(np.expand_dims(attention_mask, -1), last_hidden_state.shape)\n            embeddings = np.sum(last_hidden_state * input_mask_expanded, 1) / np.clip(input_mask_expanded.sum(1), a_min=1e-9, a_max=None)\n            embeddings = normalize(embeddings).astype(np.float32)\n            all_embeddings.append(embeddings)\n        return np.concatenate(all_embeddings)\n\n\n"
  },
  {
    "path": "app/embeddings/google/__init__.py",
    "content": "from collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n__provider_name__ = \"google\"\n__vectordb_name__ = [\"chroma\"]\n__icon__ = '/assets/embeddings/logos/google.svg'\n__connection_args__ = [\n    {\n    \"config\": [\"api_key\"],\n    \"models\": []\n    }\n]\n\n\n\n\n\n__all__ = [\n    __vectordb_name__, __connection_args__, __provider_name__, __icon__\n]"
  },
  {
    "path": "app/embeddings/google/handler.py",
    "content": "import chromadb.utils.embedding_functions as embedding_functions\nfrom loguru import logger\n\n\nclass GoogleEm:\n\n    def __init__(self,api_key:str = \"\"):\n        logger.info(\"Initialising embedding providers\")\n        self.ef = embedding_functions.GoogleGenerativeAiEmbeddingFunction(api_key=api_key)\n\n    def load_emb(self):\n        return self.ef\n\n    def health_check(self) -> None:\n        pass\n\n"
  },
  {
    "path": "app/embeddings/loader.py",
    "content": "from app.embeddings.google. handler import GoogleEm\nfrom app.embeddings.default.default import DefaultEmbedding\nfrom app.embeddings.openai.handler import OpenAIEm\nfrom app.embeddings.cohere.handler import CohereEm\n\n\nfrom loguru import logger\n\n\n\n\n\nclass EmLoader:\n    def __init__(self, configs):\n        self.config = configs\n\n    def load_embclass(self):\n        emb_classes = {\n            \"google\": GoogleEm,\n            \"openai\": OpenAIEm,\n            \"cohere\": CohereEm,\n            # \"default\": DefaultEmbedding,\n\n        }\n        emb_provider = self.config.get(\"provider\")\n        connection_params = self.config.get(\"params\")\n\n\n        emb_class = emb_classes.get(emb_provider)\n        logger.info(f\"embedding class: {emb_provider}\")\n        if emb_class:\n            return emb_class(**connection_params if connection_params else {})\n        else:\n            logger.info(\"No specified embedding providers\")\n            return DefaultEmbedding(self.config.get(\"vectordb\"))"
  },
  {
    "path": "app/embeddings/openai/__init__.py",
    "content": "from collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n\n__provider_name__ = \"openai\"\n__vectordb_name__ = [\"chroma\"]\n__icon__ = '/assets/embeddings/logos/openai.svg'\n__connection_args__ = [\n    {\n        \"config\": [\"api_key\"],\n        \"models\": [\n                \"text-embedding-ada-002\",\n                \"text-embedding-3-small\",\n                \"text-embedding-3-large\"\n        ]\n    }\n]\n\n\n\n\n\n__all__ = [\n    __vectordb_name__, __connection_args__, __provider_name__, __icon__\n]"
  },
  {
    "path": "app/embeddings/openai/handler.py",
    "content": "\nimport chromadb.utils.embedding_functions as embedding_functions\nfrom loguru import logger\n\n\nclass OpenAIEm:\n\n    def __init__(self,model_name:str = \"\",api_key:str = \"\"):\n        logger.info(\"Initialising embedding providers\")\n        self.ef = embedding_functions.OpenAIEmbeddingFunction(api_key=api_key,  model_name= model_name)\n\n    def load_emb(self):\n        return self.ef\n\n    def health_check(self) -> None:\n        pass"
  },
  {
    "path": "app/loaders/ai71/__init__.py",
    "content": "__unique_name__ = \"ai71\"\n__display_name__ = \"AI71\"\n__icon__ = \"/assets/providers/logos/ai71.png\"\n\n__all__ = ['__unique_name__', '__display_name__', '__icon__']"
  },
  {
    "path": "app/loaders/ai71/loader.py",
    "content": "from app.base.model_loader import ModelLoader\nfrom app.base.loader_metadata_mixin import LoaderMetadataMixin\nfrom app.base.base_llm import BaseLLM\nfrom typing import Any\nimport json\nimport requests\n\nclass Ai71ModelLoader(ModelLoader, LoaderMetadataMixin):\n\n    model: Any = None\n    model_config : Any = {}\n\n    def do_inference(self, prompt, previous_messages) -> dict:\n        messages = self.messages_format(prompt, previous_messages)\n\n        self.model = BaseLLM(\n            url = self.model_config[\"endpoint\"],\n            headers = {\n                \"Authorization\": \"Bearer \"+self.model_config[\"api_key\"],\n            },\n            body = {\n                \"temperature\" : 0.5,\n                \"model\": self.model_config[\"name\"],\n                \"messages\": messages\n            }\n        )\n\n        out = self.model._call(\"\")\n\n        response = self.get_response(out)\n        usage = self.get_response_metadata(prompt, response, out)\n\n        return response, usage\n\n    def get_response(self, message) -> dict:\n        if \"choices\" in message and len(message[\"choices\"]) > 0:\n            choice = message[\"choices\"][0]\n            if \"message\" in choice:\n                return {\"content\" : choice[\"message\"][\"content\"], \"error\" : None}\n        elif \"error\" in message:\n            error = message[\"error\"]\n            if \"message\" in error:\n                return {\"content\" : \"\", \"error\" : error[\"message\"]}\n        elif \"detail\" in message:\n            return {\"content\" : \"\", \"error\" : message[\"detail\"]}\n        return {\"content\" : \"\", \"error\" : \"Empty Response from LLM Provider\"}\n\n    def get_response_metadata(self, prompt, response, out) -> dict:\n\n        return{\n                \"input_tokens\" : 0,\n                \"output_tokens\" : 0,\n                \"logprobs\" : [],\n\n        }\n\n    def messages_format(self, prompt, previous_messages) -> list:\n        chat_history = []\n        for prev_message in previous_messages:\n            chat_history.append({\"role\": \"user\", \"content\": prev_message.chat_query})\n            if prev_message.chat_answer is not None:\n                temp = prev_message.chat_answer\n                temp.pop(\"data\", None)\n                chat_history.append({\"role\": \"assistant\", \"content\": json.dumps(temp)})\n\n\n        messages = []\n        if len(chat_history) > 0:\n            messages.extend(chat_history)\n        messages.append({\"role\": \"user\", \"content\": prompt})\n\n        return messages\n\n    def get_models(self):\n\n        \"\"\"\n        Retrieve models from the AI71 API and reformat the response.\n        Args:\n            llm_provider: The LLM provider object with API key.\n        Returns:\n            List of reformatted model information or an error message.\n        \"\"\"\n        url = \"https://api.ai71.ai/v1/models\"\n        try:\n            response = requests.get(url)\n            if response.status_code == 200:\n                data = response.json()\n                models = [{\"display_name\": model[\"name\"], \"id\": model[\"id\"]} for model in data.get(\"data\", [])]\n                return models, False\n            else:\n                return f\"Failed to retrieve AI71 models: {response.status_code} {response.text}\", True\n        except requests.RequestException as e:\n            return f\"Error occurred: {str(e)}\", True"
  },
  {
    "path": "app/loaders/base_loader.py",
    "content": "\nfrom app.loaders.ollama.loader import OllamaModelLoader\nfrom app.loaders.togethor.loader import TogethorModelLoader\nfrom app.loaders.openai.loader import OpenAiModelLoader\nfrom app.loaders.ai71.loader import Ai71ModelLoader\n\n\n\nclass BaseLoader:\n    def __init__(self, model_configs):\n        self.model_configs = model_configs\n\n    def load_model(self, unique_name):\n        for model in self.model_configs:\n            if model['unique_name'] == unique_name:\n                match model['kind']:\n                    case \"togethor\":\n                        loader = TogethorModelLoader(model_config=model)\n                    case \"openai\":\n                        loader = OpenAiModelLoader(model_config = model)\n                    case \"ai71\":\n                        loader = Ai71ModelLoader(model_config = model)\n                    case \"ollama\":\n                        loader = OllamaModelLoader(model_config = model)\n                    case _ :\n                        raise ValueError(f\"Model with the inference provider '{model['kind']}' with the unique name '{unique_name}' was not found\")\n                return loader\n\n        raise ValueError(f\"Model with unique name '{unique_name}' not found\")\n\n    def load_model_config(self, unique_name):\n        for model in self.model_configs:\n            if model['unique_name'] == unique_name:\n                return model\n"
  },
  {
    "path": "app/loaders/ollama/__init__.py",
    "content": "__unique_name__ = \"ollama\"\n__display_name__ = \"Ollama\"\n__icon__ = \"/assets/providers/logos/ollama.png\"\n\n__all__ = ['__unique_name__', '__display_name__', '__icon__']"
  },
  {
    "path": "app/loaders/ollama/loader.py",
    "content": "from app.base.model_loader import ModelLoader\nfrom app.base.base_llm import BaseLLM\nfrom typing import Any\nfrom loguru import logger\nfrom app.base.loader_metadata_mixin import LoaderMetadataMixin\nimport json\nimport requests\n\n\nclass OllamaModelLoader(ModelLoader, LoaderMetadataMixin):\n\n    model: Any = None\n    model_config : Any = {}\n\n    def do_inference(self, prompt, previous_messages) -> dict:\n        messages = self.messages_format(prompt, previous_messages)\n        self.model = BaseLLM(\n            url = self.model_config[\"endpoint\"],\n            body = {\n                \"model\": self.model_config[\"name\"],\n                \"messages\": messages,\n                \"stream\" : False\n            }\n        )\n\n        out = self.model._call(\"\")\n        logger.info(f\"response:{out}\")\n        response = self.get_response(out)\n        usage = self.get_response_metadata(prompt, response, out)\n\n        return response, usage\n\n    def get_response(self, message) -> dict:\n        if \"message\" in message:\n            message = message[\"message\"]\n            if \"content\" in message:\n                return {\"content\" : message[\"content\"], \"error\" : None}\n        elif \"error\" in message:\n            error = message[\"error\"]\n            return {\"content\" : \"\", \"error\" : error}\n        return {\"content\" : \"\", \"error\" : \"Empty Response from LLM Provider\"}\n\n    def get_response_metadata(self, prompt, response, out) -> dict:\n        response_metadata = {}\n        if \"usage\" in out:\n            usage = out[\"usage\"]\n            response_metadata.update({\n                \"input_tokens\" : usage[\"prompt_tokens\"],\n                \"output_tokens\" : usage[\"completion_tokens\"],\n            })\n        else:\n            response_metadata.update({\n                \"input_tokens\" : len(prompt),\n                \"output_tokens\" : len(out),\n            })\n        if \"choices\" in out and len(out[\"choices\"]) > 0:\n            choice = out[\"choices\"][0]\n            if \"logprobs\" in choice and choice[\"message\"][\"content\"] != '' and choice['logprobs'] is not None:\n                response_metadata.update({\n                                    \"logprobs\" : [logprob['logprob'] for logprob in choice['logprobs']['content']]\n                                })\n\n                return response_metadata\n\n\n        response_metadata.update({\n                \"logprobs\" : []\n            })\n        return response_metadata\n\n    def messages_format(self, prompt, previous_messages) -> list:\n        chat_history = []\n        for prev_message in previous_messages:\n            chat_history.append({\"role\": \"user\", \"content\": prev_message.chat_query})\n            if prev_message.chat_answer is not None:\n                temp = prev_message.chat_answer\n                temp.pop(\"data\", None)\n                chat_history.append({\"role\": \"assistant\", \"content\": json.dumps(temp)})\n\n        messages = []\n        if len(chat_history) > 0:\n            messages.extend(chat_history)\n        messages.append({\"role\": \"user\", \"content\": prompt})\n\n        logger.info(f\"messages:{messages}\")\n        return messages\n\n    def get_models(self):\n            \"\"\"\n            Retrieve models from the Ollama API.\n            Returns:\n                List of Ollama model names or an error message.\n            \"\"\"\n            url = \"curl http://localhost:11434/api/tags\"\n            try:\n                response = requests.get(url)\n                if response.status_code == 200:\n                    data = response.json()\n                    models = [{\"display_name\": model[\"id\"], \"id\": model[\"id\"]} for model in data.get(\"data\", [])]\n                    return models, False\n                else:\n                    return f\"Failed to retrieve Ollama models: {response.status_code} {response.text}\", True\n            except requests.RequestException as e:\n                return f\"Error occurred: {str(e)}\", True"
  },
  {
    "path": "app/loaders/openai/__init__.py",
    "content": "__unique_name__ = \"openai\"\n__display_name__ = \"Open AI\"\n__icon__ = \"/assets/providers/logos/openai.png\"\n\n__all__ = ['__unique_name__', '__display_name__', '__icon__']"
  },
  {
    "path": "app/loaders/openai/loader.py",
    "content": "from app.base.model_loader import ModelLoader\nfrom app.base.base_llm import BaseLLM\nfrom typing import Any\nfrom loguru import logger\nfrom app.base.loader_metadata_mixin import LoaderMetadataMixin\nimport json\nimport requests\n\nclass OpenAiModelLoader(ModelLoader, LoaderMetadataMixin):\n\n    model: Any = None\n    model_config : Any = {}\n\n    def do_inference(self, prompt, previous_messages) -> dict:\n        messages = self.messages_format(prompt, previous_messages)\n        self.model = BaseLLM(\n            url = self.model_config[\"endpoint\"],\n            headers = {\n                \"Authorization\": \"Bearer \"+self.model_config[\"api_key\"],\n            },\n            body = {\n                \"temperature\" : 0.5,\n                \"model\": self.model_config[\"name\"],\n                \"messages\": messages,\n                \"logprobs\": False,\n            }\n        )\n\n        out = self.model._call(\"\")      \n        response = self.get_response(out)\n        logger.info(f\"response: {response}\")\n        usage = self.get_response_metadata(prompt, response, out)\n\n        return response, usage\n\n    def get_response(self, message) -> dict:\n        if \"choices\" in message and len(message[\"choices\"]) > 0:\n            choice = message[\"choices\"][0]\n            if \"message\" in choice:\n                return {\"content\" : choice[\"message\"][\"content\"], \"error\" : None}\n        elif \"error\" in message:\n            error = message[\"error\"]\n            if \"message\" in error:\n                return {\"content\" : \"\", \"error\" : error[\"message\"]}\n        return {\"content\" : \"\", \"error\" : \"Empty Response from LLM Provider\"}\n\n    def get_response_metadata(self, prompt, response, out) -> dict:\n        response_metadata = {}\n        if \"usage\" in out:\n            usage = out[\"usage\"]\n            response_metadata.update({\n                \"input_tokens\" : usage[\"prompt_tokens\"],\n                \"output_tokens\" : usage[\"completion_tokens\"],\n            })\n        else:\n            response_metadata.update({\n                \"input_tokens\" : len(prompt),\n                \"output_tokens\" : len(out),\n            })\n        if \"choices\" in out and len(out[\"choices\"]) > 0:\n            choice = out[\"choices\"][0]\n            if \"logprobs\" in choice and choice[\"message\"][\"content\"] != '' and choice['logprobs'] is not None:\n                response_metadata.update({\n                                    \"logprobs\" : [logprob['logprob'] for logprob in choice['logprobs']['content']]\n                                })\n\n                return response_metadata\n\n\n        response_metadata.update({\n                \"logprobs\" : []\n            })\n        return response_metadata\n\n    def messages_format(self, prompt, previous_messages) -> list:\n        chat_history = []\n        for prev_message in previous_messages:\n            chat_history.append({\"role\": \"user\", \"content\": prev_message.chat_query})\n            if prev_message.chat_answer is not None:\n                temp = prev_message.chat_answer\n                temp.pop(\"data\", None)\n                chat_history.append({\"role\": \"assistant\", \"content\": json.dumps(temp)})\n\n        messages = []\n        if len(chat_history) > 0:\n            messages.extend(chat_history)\n        messages.append({\"role\": \"user\", \"content\": prompt})\n\n        return messages\n\n    def get_models(self):\n        \"\"\"\n        Retrieve models from the OpenAI API.\n        Returns:\n            List of OpenAI model names or an error message.\n        \"\"\"\n        url = \"https://api.openai.com/v1/models\"\n        headers = {\n            \"Authorization\": f\"Bearer {self.model_config.get('api_key', '')}\",\n        }\n        try:\n            response = requests.get(url, headers=headers)\n            if response.status_code == 200:\n                data = response.json()\n                models = [{\"display_name\": model[\"id\"], \"id\": model[\"id\"]} for model in data.get(\"data\", [])]\n                return models, False\n            else:\n                return f\"Failed to retrieve OpenAI models: {response.status_code} {response.text}\", True\n        except requests.RequestException as e:\n            return f\"Error occurred: {str(e)}\", True"
  },
  {
    "path": "app/loaders/togethor/__init__.py",
    "content": "__unique_name__ = \"togethor\"\n__display_name__ = \"Togethor AI\"\n__icon__ = \"/assets/providers/logos/togetherai.png\"\n\n__all__ = ['__unique_name__', '__display_name__', '__icon__']"
  },
  {
    "path": "app/loaders/togethor/loader.py",
    "content": "from app.base.model_loader import ModelLoader\nfrom app.base.base_llm import BaseLLM\nfrom typing import Any\nfrom loguru import logger\nfrom app.base.loader_metadata_mixin import LoaderMetadataMixin\nimport json\nimport requests\n\nclass TogethorModelLoader(ModelLoader, LoaderMetadataMixin):\n\n    model: Any = None\n    model_config : Any = {}\n\n\n\n    def do_inference(self, prompt, previous_messages) -> dict:\n        messages = self.messages_format(prompt, previous_messages)\n\n        self.model = BaseLLM(\n            url = self.model_config[\"endpoint\"],\n            headers = {\n                \"Authorization\": \"Bearer \"+self.model_config[\"api_key\"],\n            },\n            body = {\n                \"temperature\" : 0.5,\n                \"model\": self.model_config[\"name\"],\n                \"messages\": messages,\n                \"logprobs\": 1,\n            }\n        )\n        out = self.model._call(\"\")\n        logger.debug(out)\n        response = self.get_response(out)\n        respone_metadata = self.get_response_metadata(prompt, response, out)\n\n        return response, respone_metadata\n\n    def get_response(self, message) -> dict:\n        if \"choices\" in message and len(message[\"choices\"]) > 0:\n            choice = message[\"choices\"][0]\n            if \"message\" in choice:\n                return {\"content\" : choice[\"message\"][\"content\"], \"error\" : None}\n        elif \"error\" in message:\n            error = message[\"error\"]\n            if \"message\" in error:\n                return {\"content\" : \"\", \"error\" : error[\"message\"]}\n        return {\"content\" : \"\", \"error\" : \"Empty Response from LLM Provider\"}\n\n    def get_response_metadata(self, prompt, response, out) -> dict:\n        response_metadata = {}\n        if \"usage\" in out:\n            usage = out[\"usage\"]\n            response_metadata.update({\n                \"input_tokens\" : usage[\"prompt_tokens\"],\n                \"output_tokens\" : usage[\"completion_tokens\"],\n            })\n        else:\n            response_metadata.update({\n                \"input_tokens\" : len(prompt),\n                \"output_tokens\" : len(out),\n            })\n        if \"choices\" in out and len(out[\"choices\"]) > 0:\n            choice = out[\"choices\"][0]\n            if \"message\" in choice:\n                if \"logprobs\" in choice and choice[\"message\"][\"content\"] != '':\n                    response_metadata.update({\n                                        \"logprobs\" : choice['logprobs']['token_logprobs']\n                                    })\n                    return response_metadata\n\n\n        response_metadata.update({\n                \"logprobs\" : []\n            })\n        return response_metadata\n\n    def messages_format(self, prompt, previous_messages) -> list:\n        chat_history = []\n        for prev_message in previous_messages:\n            chat_history.append({\"role\": \"user\", \"content\": prev_message.chat_query})\n            if prev_message.chat_answer is not None:\n                temp = prev_message.chat_answer\n                temp.pop(\"data\", None)\n                chat_history.append({\"role\": \"assistant\", \"content\": json.dumps(temp)})\n\n\n        messages = []\n        if len(chat_history) > 0:\n            messages.extend(chat_history)\n        messages.append({\"role\": \"user\", \"content\": prompt})\n\n        logger.info(f\"messages:{messages}\")\n        return messages\n\n    def get_models(self):\n        \"\"\"\n        Retrieve models from the TogetherAI API.\n        Returns:\n            List of TogetherAI model names or an error message.\n        \"\"\"\n        url = \"https://api.together.xyz/v1/models\"\n        headers = {\n            \"Authorization\": f\"Bearer {self.model_config.get('api_key', '')}\",\n        }\n        try:\n            response = requests.get(url, headers=headers)\n            if response.status_code == 200:\n                data = response.json()\n                models = [{\"display_name\": model[\"display_name\"], \"id\": model[\"id\"]} for model in data]\n                return models, False\n            else:\n                return f\"Failed to retrieve TogetherAI models: {response.status_code} {response.text}\", True\n        except requests.RequestException as e:\n            return f\"Error occurred: {str(e)}\", True"
  },
  {
    "path": "app/main.py",
    "content": "from fastapi import FastAPI\nfrom app.providers.container import Container\nfrom app.api.v1.main_router import MainRouter\nfrom app.api.v1.connector import router as ConnectorRouter\nfrom app.api.v1.llmchat import chat_router\nfrom app.api.v1.provider import router as ProviderRouter\nfrom app.api.v1.provider import vectordb as vectordb\nfrom app.api.v1.connector import cap_router as capabilityrouter\nfrom app.api.v1.connector import inference_router as inference_router\nfrom app.api.v1.connector import actions as actions\nfrom app.api.v1.provider import sample as sample_sql\nfrom app.api.v1.auth import login as login\nimport app.repository.connector as repo\n\n\nfrom fastapi.responses import HTMLResponse\n\n\n# from app.providers.middleware import AuthMiddleware\nfrom fastapi.staticfiles import StaticFiles\nfrom app.chain.chains.intent_chain import IntentChain\nfrom app.chain.chains.capability_chain import CapabilityChain\nfrom app.chain.chains.metadata_chain import MetadataChain\nfrom app.chain.chains.query_chain import QueryChain\nfrom app.chain.chains.general_chain import GeneralChain\nfrom app.providers.config import Configs, configs\nfrom app.providers.context_storage import ContextStorage\n\nfrom fastapi.middleware.cors import CORSMiddleware\nfrom loguru import logger\nimport app.services.connector as svc\nimport app.services.provider as provider_svc\nfrom app.utils.database import SessionLocal, Base, engine\n\nfrom fastapi.templating import Jinja2Templates\nfrom fastapi import Request\nfrom typing import Optional\n\nsession = SessionLocal()\n\n\ndef create_app(config):\n\n    logger.info(\"creating application\")\n    logger.info(\"creating container object\")\n    container = Container()\n    logger.info(\"loading necessary configurations\")\n    json_config =Configs().model_dump(mode='json')\n    container.config.from_dict(json_config)\n    container.config.from_dict(config)\n\n    config[\"models\"] = []\n    logger.level(\"ONEPANE\", no=27, color=\"<yellow>\")\n\n\n    if container.config.logging_enabled():\n        logger.add(\"trace.log\", level=\"ONEPANE\", colorize=False, backtrace=True, diagnose=True)\n\n    logger.info(\"creating database tables\")\n    Base.metadata.create_all(bind=engine)\n\n\n    logger.info(\"initializing plugin providers\")\n    err = provider_svc.initialize_plugin_providers(session)\n    if err is not None:\n        logger.critical(err)\n\n    logger.info(\"initializing vector store\")\n    err = provider_svc.initialize_vectordb_provider(session)\n    if err is not None:\n        logger.critical(err)\n\n    logger.info(\"initializing Vector Embeddings\")\n    err = provider_svc.initialize_embeddings(session)\n    if err is not None:\n        logger.critical(err)\n        \n    logger.info(\"setting all configuration status to 1\")\n    repo.default_configuration_status(session)\n\n\n    logger.info(\"creating local context storage\")\n    context_storage = ContextStorage(session)\n\n    \n    logger.info(\"creating llm fast_api server\")\n    app = FastAPI()\n\n    app.mount(\"/assets\",StaticFiles(directory=\"./assets\"), name=\"assets\")\n    app.mount(\"/ui/assets\",StaticFiles(directory=\"./ui/dist/assets\",  html=True), name=\"ui\", )\n    app.mount(\"/ui/dist-library\", StaticFiles(directory=\"./ui/dist-library\", html=True), name=\"embedbot\")\n\n    templates = Jinja2Templates(directory=\"./ui/dist\")\n\n    @app.get(\"/ui\", response_class=HTMLResponse)\n    @app.get(\"/ui/{full_path:path}\", response_class=HTMLResponse)\n    def serve_home(request: Request, full_path: Optional[str]=\"\"):\n        if request:\n            return templates.TemplateResponse(\"index.html\", context= {\"request\": request}) \n        else:\n            return templates.TemplateResponse(\"index.html\") \n\n    app.add_middleware(\n        CORSMiddleware,\n        allow_origins=[\"*\"],\n        allow_credentials=True,\n        allow_methods=[\"OPTIONS\", \"GET\", \"POST\", \"DELETE\"],\n        allow_headers=[\"*\"],\n    )\n\n    logger.info(\"setting chain, vector store into app context\")\n    app.config = config\n    app.container = container\n    app.context_storage = context_storage\n\n    app.include_router(MainRouter,prefix=\"/api/v1/query\")\n    app.include_router(ConnectorRouter, prefix=\"/api/v1/connector\")\n    app.include_router(chat_router, prefix=\"/api/v1/chat\")\n    app.include_router(ProviderRouter, prefix=\"/api/v1/provider\")\n    app.include_router(capabilityrouter, prefix=\"/api/v1/capability\")\n    app.include_router(inference_router, prefix=\"/api/v1/inference\")\n    app.include_router(actions, prefix=\"/api/v1/actions\")\n    app.include_router(sample_sql, prefix=\"/api/v1/sql\")\n    app.include_router(login, prefix=\"/api/v1/auth\")\n    app.include_router(vectordb, prefix=\"/api/v1/vectordb\")\n\n    curr_schema = app.openapi()\n    curr_schema[\"info\"][\"title\"] = \"Rag genie Chat API\"\n    curr_schema[\"info\"][\"description\"] = \"API for raggenie cloud chatbot\"\n\n    return app\n"
  },
  {
    "path": "app/models/connector.py",
    "content": "from sqlalchemy import Column, String, Integer, ForeignKey, DateTime, Boolean, JSON, Text\nfrom sqlalchemy.sql import func\nfrom sqlalchemy.orm import relationship\nfrom app.utils.database import Base\n\nclass Connector(Base):\n    __tablename__ = 'connectors'\n\n    id = Column(Integer, primary_key=True, index=True)\n    connector_type = Column(Integer, ForeignKey('providers.id'), nullable=False)\n    connector_name = Column(String, nullable=False, index=True)\n    connector_description = Column(String, nullable=True, index=True)\n    connector_config = Column(JSON, nullable=False)\n    schema_config = Column(JSON, nullable=True)\n    connector_docs = Column(Text, nullable=True)\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n    environment_id = Column(Integer, ForeignKey(\"environments.id\"), nullable=False)\n    environment = relationship(\"Environment\", back_populates=\"connectors\")\n\n    provider = relationship('Provider', back_populates='connectors')\n    actions = relationship('Actions', back_populates='connectors', cascade=\"all, delete-orphan\")\n    sample_sql = relationship('SampleSQL', back_populates='connectors', cascade=\"all, delete-orphan\")\n    \n    configurations = relationship('ConfigurationConnectorMapping', back_populates='connector', cascade=\"all, delete\")\n\n\n\nclass Configuration(Base):\n    __tablename__ = 'configurations'\n\n    id = Column(Integer, primary_key=True, index=True)\n    name= Column(String, nullable=False)\n    short_description = Column(String, nullable=False, index=True)\n    long_description = Column(String, nullable=True, index=True)\n    enable = Column(Boolean, default=True)\n    status = Column(Integer, default=0, index=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n    \n    environment_id = Column(Integer, ForeignKey(\"environments.id\"), nullable=False)\n    environment = relationship(\"Environment\", back_populates=\"configurations\")\n\n    capabilities = relationship('Capabilities', back_populates='configuration', cascade=\"all,delete\")\n    inference_mapping = relationship('Inferenceconfigmapping', back_populates='configuration', cascade=\"all,delete\")\n    vectordb_config_mapping = relationship('VectorDBConfigMapping', back_populates='configuration', cascade=\"all,delete\")\n    chat_histories = relationship(\"ChatHistory\", back_populates=\"configuration\", cascade=\"all,delete\") \n\n    \n    connectors = relationship('ConfigurationConnectorMapping', back_populates='configuration', cascade=\"all, delete\",lazy=\"joined\")\n    \n    \n    \nclass ConfigurationConnectorMapping(Base):\n    __tablename__ = 'configuration_connector_mapping'\n    \n    id = Column(Integer, primary_key=True, index=True)\n    configuration_id = Column(Integer, ForeignKey('configurations.id'),nullable=False)\n    connector_id = Column(Integer, ForeignKey('connectors.id'),nullable=False)\n    \n    configuration = relationship('Configuration', back_populates='connectors')\n    connector = relationship('Connector', back_populates='configurations')\n\n\n\n\n\nclass Capabilities(Base):\n    __tablename__ = 'capabilities'\n\n    id = Column(Integer, primary_key=True, index=True)\n    name = Column(String, nullable=False)\n    description=Column(String, nullable=False)\n    requirements=Column(JSON, nullable=False)\n    config_id = Column(Integer, ForeignKey('configurations.id'))\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    configuration = relationship('Configuration', back_populates='capabilities')\n    cap_actions_mapping = relationship('CapActionsMapping', back_populates='capabilities')\n\nclass Inference(Base):\n    __tablename__ = 'inference'\n\n    id =  Column(Integer, primary_key=True, index=True)\n    name = Column(String,  nullable=False)\n    llm_provider = Column(String, nullable=False)\n    model = Column(String, nullable=False)\n    endpoint= Column(String, nullable=False)\n    apikey=Column(String, nullable=False)\n    enable= Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    inference_mapping = relationship('Inferenceconfigmapping', back_populates='inference')\n\n\nclass Inferenceconfigmapping(Base):\n    __tablename__ ='inferenceconfigmapping'\n\n    id = Column(Integer, primary_key=True, index=True)\n    inference_id = Column(Integer, ForeignKey('inference.id'))\n    config_id = Column(Integer, ForeignKey('configurations.id'))\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    inference = relationship('Inference', back_populates='inference_mapping')\n    configuration = relationship('Configuration', back_populates='inference_mapping')\n\n\nclass Actions(Base):\n    __tablename__ = 'actions'\n\n    id = Column(Integer, primary_key=True, index=True)\n    name = Column(String, nullable=False)\n    description = Column(String, nullable=True)\n    types = Column(String, nullable=False)\n    body = Column(JSON, nullable=False)\n    table = Column(String, nullable=True)\n    enable = Column(Boolean, default=True)\n    condition = Column(JSON, default=None)\n    connector_id = Column(Integer, ForeignKey(\"connectors.id\"))\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    connectors = relationship('Connector', back_populates='actions')\n    cap_actions_mapping = relationship('CapActionsMapping', back_populates='actions')\n\nclass CapActionsMapping(Base):\n    __tablename__ = 'cap_actions_mapping'\n\n    id = Column(Integer, primary_key=True, index=True)\n    capability_id = Column(Integer, ForeignKey('capabilities.id'))\n    action_id = Column(Integer, ForeignKey('actions.id'))\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    capabilities = relationship('Capabilities', back_populates='cap_actions_mapping')\n    actions = relationship('Actions', back_populates= 'cap_actions_mapping')"
  },
  {
    "path": "app/models/db.py",
    "content": "from sqlalchemy import  Column, Integer, String, DATETIME\nfrom sqlalchemy.orm import  declarative_base\n\nBase = declarative_base()\n\nclass Chat(Base):\n    __tablename__ = 'chat'\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    context_id = Column(String, nullable=False)\n    question = Column(String, nullable=False)\n    answer = Column(String, nullable=True)\n    summary = Column(String, nullable=True)\n    created_at = Column(DATETIME, nullable=False)"
  },
  {
    "path": "app/models/environment.py",
    "content": "from sqlalchemy import Column, Integer, String, ForeignKey, Boolean\nfrom app.utils.database import Base\nfrom sqlalchemy.orm import relationship\n\n\nclass Environment(Base):\n    __tablename__ = \"environments\"\n\n    id = Column(Integer, primary_key=True)\n    name = Column(String, nullable=False)\n\n    configurations = relationship(\"Configuration\", back_populates=\"environment\") \n    connectors = relationship(\"Connector\", back_populates=\"environment\") \n    sample_sql = relationship(\"SampleSQL\", back_populates=\"environment\")\n    chat_histories = relationship(\"ChatHistory\", back_populates=\"environment\") \n\nclass UserEnvironmentMapping(Base):\n    __tablename__ = \"user_environment_mapping\"\n    \n    id = Column(Integer, primary_key=True)\n    user_id = Column(Integer, ForeignKey('users.id'), nullable=False)\n    environment_id = Column(Integer, ForeignKey('environments.id'), nullable=False)\n    is_active = Column(Boolean, default=False, nullable=False)\n"
  },
  {
    "path": "app/models/llmchat.py",
    "content": "from sqlalchemy import Column, String, Integer, DateTime, Boolean, JSON, ForeignKey\nfrom sqlalchemy.sql import func\nfrom sqlalchemy.orm import relationship\nfrom app.utils.database import Base\n\nclass ChatHistory(Base):\n    __tablename__ = 'chat_histories'\n\n    chat_id = Column(Integer, primary_key=True, index=True, autoincrement=True)\n    chat_context_id = Column(String, index=True, nullable=False)\n    chat_query = Column(String, nullable=False)\n    chat_answer = Column(JSON, nullable=False)\n    chat_summary = Column(String, nullable=False)\n    chat_status = Column(Integer, nullable=True)\n    feedback_status = Column(Integer, nullable=True)\n    feedback_json = Column(JSON, nullable=True)\n    user_id = Column(Integer, nullable=True)\n    primary_chat = Column(Boolean)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n    configuration_id = Column(Integer, ForeignKey(\"configurations.id\"), nullable=False)\n    environment_id = Column(Integer, ForeignKey(\"environments.id\"), nullable=False)\n    \n    configuration = relationship(\"Configuration\", back_populates=\"chat_histories\")\n    environment = relationship(\"Environment\", back_populates=\"chat_histories\")\n"
  },
  {
    "path": "app/models/prompt.py",
    "content": "from pydantic import BaseModel, Field\nclass SystemPrompt(BaseModel):\n    template: str = Field(\n        ...,\n        description=\"The template used for system-level prompt generation.\"\n    )\n\nclass UserPrompt(BaseModel):\n    template: str = Field(\n        ...,\n        description=\"The template used for user-level prompt generation.\"\n    )\n\nclass RegenerationPrompt(BaseModel):\n    template: str = Field(\n        ...,\n        description=\"The template used for regenerating the response prompt.\"\n    )\n\nclass Prompt(BaseModel):\n    base_prompt: str = Field(\n        ...,\n        description=\"The base prompt structure combining system and user prompts.\"\n    )\n    system_prompt: SystemPrompt = Field(\n        ...,\n        description=\"The system prompt details.\"\n    )\n    user_prompt: UserPrompt = Field(\n        ...,\n        description=\"The user prompt details.\"\n    )\n    regeneration_prompt: RegenerationPrompt = Field(\n        ...,\n        description=\"The regeneration prompt details.\"\n    )"
  },
  {
    "path": "app/models/provider.py",
    "content": "from sqlalchemy import Column, String, Integer, DateTime, Boolean, ForeignKey, JSON\nfrom sqlalchemy.sql import func\nfrom sqlalchemy.orm import relationship\nfrom app.utils.database import Base\n\nclass Category(Base):\n    __tablename__ = 'categories'\n\n    id = Column(Integer, primary_key=True, index=True)\n    name = Column(String, unique=True, nullable=False, index=True)\n    description = Column(String, nullable=False)\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    providers = relationship('Provider', back_populates='category')\n\nclass Provider(Base):\n    __tablename__ = 'providers'\n\n    id = Column(Integer, primary_key=True, index=True)\n    name = Column(String, unique=True, nullable=False, index=True)\n    description = Column(String, nullable=False)\n    key = Column(String, unique=True, nullable=False, index=True)\n    icon = Column(String, nullable=False)\n    category_id = Column(Integer, ForeignKey('categories.id'), nullable=False)\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    connectors = relationship('Connector', back_populates='provider')\n    category = relationship('Category', back_populates='providers')\n    providerconfig = relationship('ProviderConfig', back_populates='provider')\n\nclass ProviderConfig(Base):\n    __tablename__ = \"providerconfig\"\n\n    id = Column(Integer, primary_key=True, index=True)\n    name = Column(String, unique=True, nullable=False, index=True)\n    description = Column(String, nullable=False)\n    field = Column(String, nullable=False)\n    slug = Column(String, nullable=False)\n    value = Column(JSON, nullable=True)\n    enable = Column(Boolean, default=True)\n    config_type= Column(Integer, nullable=False)\n    order = Column(Integer, nullable=False)\n    required=Column(Boolean, nullable=True, default=True)\n    provider_id = Column(Integer, ForeignKey('providers.id'), nullable=False)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    provider = relationship('Provider', back_populates='providerconfig')\n\nclass VectorDBConfig(Base):\n    __tablename__ = \"vectordbconfig\"\n\n    id = Column(Integer, primary_key=True, index=True)\n    name = Column(String, unique=True, nullable=False, index=True)\n    description = Column(String, nullable=False)\n    key = Column(String, unique=True, nullable=False, index=True)\n    icon = Column(String, nullable=False)\n    config = Column(JSON)\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\nclass SampleSQL(Base):\n    __tablename__ = \"sample_sql\"\n\n    id = Column(Integer, primary_key=True, index=True)\n    description = Column(String, nullable=False)\n    sql_metadata = Column(JSON, nullable=True)\n    connector_id = Column(Integer, ForeignKey('connectors.id'), nullable=False)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    environment_id = Column(Integer, ForeignKey(\"environments.id\"), nullable=False)\n    environment = relationship(\"Environment\", back_populates=\"sample_sql\")\n    \n    connectors = relationship('Connector', back_populates='sample_sql')\n\nclass VectorDB(Base):\n    __tablename__ = \"vectordb\"\n\n    id = Column(Integer, primary_key=True, index=True)\n    vectordb = Column(String, nullable=False)\n    vectordb_config = Column(JSON, nullable=False)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    vectordb_config_mapping = relationship('VectorDBConfigMapping', back_populates='vector_db',cascade=\"all,delete\")\n    vector_embedding_mapping = relationship('VectorEmbeddingMapping', back_populates='vector_db', cascade=\"all,delete\")\n\n\n\nclass VectorDBConfigMapping(Base):\n    __tablename__ = \"vectordb_config_mapping\"\n\n    id = Column(Integer, primary_key=True, index=True)\n    vector_db_id = Column(Integer, ForeignKey('vectordb.id'), nullable=False)\n    config_id = Column(Integer, ForeignKey('configurations.id'), nullable=False)\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    vector_db = relationship('VectorDB', back_populates='vectordb_config_mapping')\n    configuration = relationship('Configuration', back_populates='vectordb_config_mapping')\n\nclass Embeddings(Base):\n    __tablename__ = \"embeddings_configs\"\n\n    id = Column(Integer, primary_key=True, index=True)\n    provider = Column(String, nullable=False)\n    config = Column(JSON, nullable=False)\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    vector_embedding_mapping = relationship(\"VectorEmbeddingMapping\", back_populates= \"embeddings_config\")\n\nclass VectorEmbeddingMapping(Base):\n    __tablename__ = \"vector_embedding_mapping\"\n\n    id = Column(Integer, primary_key=True, index=True)\n    vector_db_id = Column(Integer, ForeignKey('vectordb.id'), nullable=False)\n    embedding_id = Column(Integer, ForeignKey('embeddings_configs.id'), nullable=False)\n    enable = Column(Boolean, default=True)\n    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)\n    updated_at = Column(DateTime(timezone=True), onupdate=func.now())\n    deleted_at = Column(DateTime(timezone=True), nullable=True)\n\n    vector_db = relationship('VectorDB', back_populates='vector_embedding_mapping', cascade=\"all,delete\")\n    embeddings_config = relationship('Embeddings', back_populates='vector_embedding_mapping', cascade=\"all,delete\")"
  },
  {
    "path": "app/models/request.py",
    "content": "from pydantic import BaseModel\nfrom  typing import Dict,List, Literal\nfrom typing import Any\n\n\nclass Chat(BaseModel):\n    content: str\n    role: str\n\n\nclass FlowItem(BaseModel):\n    question: str\n    answer: dict\n\nclass PostBody(BaseModel):\n    question: str\n    flow: list[FlowItem]\n\nclass ResponseItem(BaseModel):\n    description: str\n    metadata: Dict[str,str]\n\nclass FeedbackCorrectionRequest(BaseModel):\n    responses: List[ResponseItem]\n\n\nclass ConnectionArgument(BaseModel):\n    type: Literal[1,2,3,4,6,7, 8]\n    generic_name: str\n    description: str\n    order: int\n    required: bool\n    value: Any\n    slug: str"
  },
  {
    "path": "app/models/user.py",
    "content": "from sqlalchemy import Column, Integer, String, Boolean\nfrom app.utils.database import Base\n\nclass User(Base):\n    __tablename__ = \"users\"\n\n    id = Column(Integer, primary_key=True)\n    username = Column(String, nullable=False)\n"
  },
  {
    "path": "app/plugins/airtable/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'airtable'\n__display_name__ = 'Airtable'\n__description__ = 'Airtable integration for handling Airtable database operations.'\n__icon__ = '/assets/plugins/logos/airtable.svg'\n__category__ = 2\n\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    token= ConnectionArgument(\n        type = 2,\n        generic_name= 'Airtable token',\n        description = 'Token for airtable workspace',\n        order = 2,\n        required = True,\n        value = None,\n        slug = \"api_key\"\n    ),\n    workspace_id=ConnectionArgument(\n        type= 1,\n        generic_name= 'Airtable workspace id',\n        description= 'Airtable workspace ID',\n        order = 1,\n        required = True,\n        value = None,\n        slug = \"space_name\"\n    )\n)\n\n# Prompt\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n            \"template\": \"\"\"\n            You are an Airtable expert.Your job is to answer questions about the Airtable tables specified in schema.\n            You must output the Airtable query that answers the question using the schema provided.\n            Use the schema details and db constraints enclosed in `[schema][/schema]` to generate query\n\n\n            [schema]\n            {schema}\n            [/schema]\n\n            {context}\n\n            sample queries generated previously\n\n            question: list all hospitals\n            query: https://api.airtable.com/v0/appXXXXXXX/hospitals\n\n            question: list all hospitals in x\n            query: executing query:https://api.airtable.com/v0/appXXXXXXX/hospitals?filterByFormula=AND(SEARCH(LOWER('x'),LOWER({{location}}))=1)\n\n            question: list all hospital supports xyz ab plan\n            query: https://api.airtable.com/v0/appXXXXXXX/hospitals?filterByFormula=AND(SEARCH(LOWER(\"xyz ab\"),LOWER({{insurance_plan}}))=1)\n\n\n            Adhere to these rules while generating query:\n            - Deliberately go through the question and database schema word by word to appropriately answer the question\n            - Dont change the field names\n            - Use Lower for comparing or equality\n            \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            User question is \"$question\"\n            generate a json in the following format without any formatting.\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"complete airtable rest api query without authentication\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"general_message\": \"general message like 'here is the list of x'\",\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"main_entity\": \"document\"\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            User query is \"$question\"\n            generate a json in the following format without any formatting. extra explanation is strictly prohibited.\n            {\n                \"output\": \"Your answer for the question\",\n                \"main_entity\": \"document\",\n                \"operation_kind\": \"text\"\n            }\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/airtable/formatter.py",
    "content": "from typing import Any, Dict\nfrom loguru import logger\n\nclass Formatter:\n    \"\"\"\n    Formatter class to format the response based on the inference and data.\n    \"\"\"\n\n\n    def format(self, data: Dict[str, Any], inference: Dict[str, Any]) -> dict:\n        \"\"\"\n        Format the response using the given data and inference information.\n\n        :param data: The data containing records to process.\n        :param inference: Inference details including main entity and operation kind.\n        :return: Formatted response dictionary.\n        \"\"\"\n\n        logger.info(\"Processing output using inference details\")\n\n        response = {}\n        self.main_entity = inference.get(\"main_entity\", \"\")\n        self.kind = inference.get(\"operation_kind\", \"\")\n        self.general_message = inference.get(\"general_message\", \"Unable to process question, try again\")\n        self.next_questions = inference.get(\"next_questions\", [])\n\n        # Extract results from data records\n        results = [record[\"fields\"] for record in data.get(\"records\", [])]\n\n        response[\"content\"] = self.general_message\n\n        if len(results) == 0:\n            response[\"content\"]= \"Sorry, I couldn't find any details regarding this\"\n\n        response[\"main_entity\"] = self.main_entity\n        response[\"main_format\"] = self.kind\n        response[\"role\"] = \"assistant\"\n        response[\"data\"]= results\n\n        return response\n\n"
  },
  {
    "path": "app/plugins/airtable/handler.py",
    "content": "from .formatter import Formatter\nfrom loguru import logger\nimport requests\nimport uuid\nfrom urllib.parse import urlsplit, urlunsplit, parse_qs, urlencode\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.query_plugin import QueryPlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\nfrom typing import Tuple, Optional\n\n\nclass Airtable(BasePlugin, QueryPlugin, PluginMetadataMixin, Formatter):\n    \"\"\"\n    Airtable class for interacting with Airtable API and fetching table data, schemas, and more.\n    \"\"\"\n\n    def __init__(self, connector_name : str, token:str, workspace:str):\n        super().__init__(__name__)\n\n        self.connection = {\n            \"base_url\": \"https://api.airtable.com/v0\",\n        }\n\n        self.connector_name = connector_name.replace(' ','_')\n        self.params = {\n            'token': token,\n            'base_id': workspace\n        }\n\n\n    def connect(self):\n        \"\"\"\n        Mocked connection method for Airtable.\n\n        :return: Tuple containing connection status (True/False) and an error message if any.\n        \"\"\"\n        return True, None\n\n\n    def healthcheck(self)-> Tuple[bool, Optional[str]]:\n        \"\"\"\n        Perform a health check by checking if the Airtable base is accessible.\n\n        :return: Tuple containing the health status (True/False) and error message (if any).\n        \"\"\"\n        logger.info(\"health check for airtable\")\n\n        url = self.connection[\"base_url\"]+ \"/meta/bases/\"+ self.params[\"base_id\"]+\"/tables\"\n\n        headers = {\n            \"Authorization\": \"Bearer \"+self.params[\"token\"]\n        }\n\n        try:\n            response = requests.get(url, headers=headers)\n            if response.status_code == 200:\n                logger.info(\"Airtable health check passed.\")\n                return True, None\n            else:\n                logger.error(f\"Health check failed: {response.status_code} {response.text}\")\n                return False, \"Failed to connect with airtable\"\n        except Exception as e:\n            logger.exception(f\"Exception during health check: {str(e)}\")\n            return False, str(e)\n\n\n\n    def configure_datasource(self, init_config):\n        \"\"\"\n        Configures the Airtable datasource.\n\n        :param init_config: Initial configuration for the datasource.\n        \"\"\"\n        return None\n\n\n    def fetch_data(self, query, params=None):\n        \"\"\"\n        Fetches data from Airtable based on the provided query.\n\n        :param query: The Airtable API query.\n        :param params: Optional query parameters.\n        :return: A tuple containing the fetched data and an optional error message.\n        \"\"\"\n\n        logger.info(\"preparing query\")\n        try:\n            parts = query.split(\"v0\")\n            if len(parts) <= 1:\n                return [], \"Invalid query format\"\n\n            query = parts[1].lstrip('/')\n            first_part, second_part = query.split('/', 1)\n            final_query = second_part\n\n\n            url = self.connection.get(\"base_url\")+\"/\"+self.params[\"base_id\"]+\"/\"+final_query\n\n            headers = {\n                \"Authorization\": \"Bearer \"+self.params[\"token\"]\n            }\n\n            logger.info(f\"Generating URL for fetch_data: {url}\")\n            url_parts = urlsplit(url)\n            query_params = parse_qs(url_parts.query)\n            query_params.pop('api_key', None)\n            query_params.pop('API_KEY', None)\n            new_query_string = urlencode(query_params, doseq=True)\n            url = urlunsplit((url_parts.scheme, url_parts.netloc, url_parts.path, new_query_string, url_parts.fragment))\n\n            logger.info(f\"Final request URL: {url}\")\n            response = requests.get(url, headers=headers, params=params)\n\n\n            if response.status_code == 200:\n                return response.json(), None\n            else:\n                logger.error(f\"Failed to fetch data: {response.status_code}, {response.text}\")\n                return [], \"Failed to fetch\"\n\n        except Exception as e:\n            logger.error(f\"Failed to fetch data: {e}\")\n            return [], \"Failed to fetch\"\n\n\n    def fetch_schema_details(self):\n        \"\"\"\n        Fetches the schema details (tables and columns) from Airtable.\n\n        :return: A tuple containing the schema DDL as a list of strings and the table metadata.\n        \"\"\"\n\n        schema_ddl = []\n        table_metadata = []\n\n        base_id = self.params.get(\"base_id\")\n        token = self.params.get(\"token\",\"\")\n        base_url = self.connection.get(\"base_url\")\n\n        url = f\"{base_url}/meta/bases/{base_id}/tables\"\n\n        headers = {\n            \"Authorization\": f\"Bearer {token}\"\n        }\n\n        response = requests.get(url, headers=headers)\n\n        if response.status_code == 200:\n            out = response.json()\n            if \"tables\" in out and len(out[\"tables\"])>0:\n                tables = out[\"tables\"]\n                for table in tables:\n                    schema = {\n                            \"table_id\": str(uuid.uuid4()),\n                            \"table_name\": table[\"name\"],\n                            \"description\": \"\",\n                            \"columns\": []\n                    }\n                    fields= []\n                    for field in table[\"fields\"]:\n                        fields.append({\n                            \"column_id\" : str(uuid.uuid4()),\n                            \"column_name\": field['name'],\n                            \"column_type\": field['type'],\n                            \"description\": \"\",\n                        })\n\n                    schema[\"columns\"] = fields\n                    schema_ddl.append(f\"\\nTable name: {table['name']}\\n\" + \"\\n\".join([f['column_name'] for f in fields]))\n                    table_metadata.append(schema)\n\n        return schema_ddl, table_metadata\n\n    def create_ddl_from_metadata(self,table_metadata):\n        \"\"\"\n        Creates DDL from the provided table metadata.\n\n        :param table_metadata: List of table metadata dictionaries.\n        :return: List of schema DDL strings.\n        \"\"\"\n        schema_ddl = []\n        for table in table_metadata:\n            ddl = f\"\\nTable name: {table['table_name']}\\n\"\n            ddl += \"\\n\".join([col.get(\"column_name\",\"\") for col in table[\"columns\"]])\n            schema_ddl.append(ddl)\n        return schema_ddl\n\n\n    def validate(self, formatted_sql: str) -> None:\n        \"\"\"\n        Validates the provided SQL.\n\n        :param formatted_sql: SQL string to validate.\n        \"\"\"\n        pass\n\n    def close_connection(self) -> None:\n        \"\"\"\n        Closes the connection to Airtable.\n        \"\"\"\n        pass\n\n"
  },
  {
    "path": "app/plugins/bigquery/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'bigquery'\n__display_name__ = 'Bigquery'\n__description__ = 'Bigquery integration for handling Bigquery database operations.'\n__icon__ = '/assets/plugins/logos/bigquery.svg'\n__category__ = 2\n\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    project_id= ConnectionArgument(\n        type = 1,\n        generic_name= 'Project id',\n        description = 'Google cloud project id',\n        order= 1,\n        required = True,\n        value = None,\n        slug = \"project_id\"\n    ),\n    service_account_json=ConnectionArgument(\n        type= 7,\n        generic_name= 'Service account JSON',\n        description= 'Service account details',\n        order= 2,\n        required = True,\n        value = None,\n        slug = \"service_account_json\"\n    )\n)\n\n# Prompt\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n            \"template\": \"\"\"\n            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.\n        go through the schema details given below\n        - start db schema section--\n        {schema}\n        -- end db schema section--\n\n        A brief description about the schema is given below:\n        -- start db context section--\n        {context}\n        -- end db context section--\n\n        Sample sql queries with their questions are given below\n\n        -- start query samples section--\n        $suggestions\n        -- end query samples section--\n\n\n        Adhere to these rules while generating query:\n          1.Do not hallucinate and give incorrect answer\n          2.Do not give incomplete answers\n            \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            generate a json in the following format without any formatting. extra explanation is strictly prohibited.\n            {\n                \"explanation\": \"Explain how you finalized the nerd graphql query using the schemas and rules provided\",\n                \"query\" : \"BigQuery SQL query to answer `$question` by strictly following the rules.\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"visualisation\": {\n                            \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                            \"x-axis\": [\"fields that can be used as x axis\"],\n                            \"y-axis\": [\"field that can be used as y axis\"],\n                            \"title\": \"layout title name\"\n                },\n                \"confidence\" : \"confidence in 100\",\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            You were trying to answer the following user question by writing SPL query to answer the question given in `[question][/question]`\n            [question]\n            $question\n            [/question]\n\n            You generated this query given in `[query][/query]`\n            [query]\n            {query_generated}\n            [/query]\n\n            But upon execution you encountered some error , error traceback is given in [query_error][/query_error]\n            [query_error]\n            {exception_log}\n            [/query_error]\n\n            Answer the given user question by writing an BigQuery SQL query by taking into account your previous errors and rectifying them.\n\n\n            generate a json in the following format without any formatting. extra explanation is strictly prohibited.\n            {{\n                \"explanation\": \"Explain how you are going to finalize the SQL query by taking the previous generation details into account\",\n                \"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\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"visualisation\": {\n                \"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\",\n                \"x-axis\": [\"fields that can be used as x axis\"],\n                \"y-axis\": [\"field that can be used as y axis\"],\n                \"title\": \"layout title name\"\n                },\n                \"confidence\" : \"confidence in 100\",\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\"\n            }}\n\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __display_name__, __plugin_name__, __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/bigquery/formatter.py",
    "content": "from typing import Any\nfrom loguru import logger\n\n\nclass Formatter:\n    def format(self, data: Any,input) -> (dict):\n        \"\"\"\n        Main entry point for formatting the data based on the input parameters.\n        Handles different formatting strategies based on operation kind.\n\n        :param data: The data to format.\n        :param input_params: Dictionary containing operation and formatting details.\n        :return: A dictionary containing the formatted response.\n        \"\"\"\n        response = {}\n        self.main_entity = input.get(\"main_entity\")\n        self.kind = input.get(\"operation_kind\", \"\").lower()\n        self.general_message = input.get(\"general_message\")\n        self.empty_message = input.get(\"empty_message\")\n\n        logger.info(\"Formatting output using inference\")\n\n        if self.kind  == \"list\":\n            response = self.basic_formatter(data, input)\n        elif self.kind == \"aggregation\":\n            response = self.aggregation_formatter(data, input)\n        else:\n            response[\"data\"] = data\n            response[\"kind\"] = \"list\"\n\n\n        response.update({\n            \"main_entity\": self.main_entity,\n            \"main_format\": self.kind,\n            \"role\": \"assistant\",\n            \"content\": self.general_message,\n            \"empty_message\": self.empty_message,\n        })\n\n        return response\n\n    def basic_formatter(self, data: Any, input:Any) -> dict :\n        \"\"\"\n        Formats data as a list, handling cases for none, single, and multiple entries.\n\n        :param data: The data to format.\n        :return: A dictionary containing the formatted list response.\n        \"\"\"\n        logger.info(\"Formatting data as a list\")\n\n        if data is None:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"single\"}\n        else:\n            response = {\"data\": data, \"kind\": \"list\"}\n\n        return response\n\n\n    def aggregation_formatter(self, data:Any, input:Any) -> dict :\n        \"\"\"\n        Formats data for aggregation visualisation, supporting table and chart formats.\n\n        :param data: The data to format.\n        :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type).\n        :return: A dictionary containing the formatted aggregation response.\n        \"\"\"\n\n        logger.info(\"Formatting data as aggregation\")\n\n        visualisation = input.get(\"visualisation\", {})\n        response = {}\n\n\n        if data is None or len(data) == 0:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"table\"}\n        else:\n            value_fields = visualisation.get(\"y-axis\", [])\n            key_fields = visualisation.get(\"x-axis\", [])\n            title = visualisation.get(\"title\", \"\")\n\n            visualisaton_kind = visualisation[\"type\"].replace(\" \", \"_\") if visualisation[\"type\"] is not None else visualisation[\"type\"]\n\n            if visualisaton_kind.lower() in [\"bar_chart\", \"line_chart\", \"pie_chart\"] and len(value_fields) > 0 and len(key_fields) > 0:\n                response[\"kind\"] = visualisaton_kind\n                response[\"data\"] = data\n                response[\"x\"] = key_fields\n                response[\"y\"] = value_fields\n                response[\"title\"] = title\n            else:\n                response = {\"kind\": \"table\", \"data\": data}\n\n        return response\n\n\n\n\n"
  },
  {
    "path": "app/plugins/bigquery/handler.py",
    "content": "from google.cloud import bigquery\nfrom google.oauth2 import service_account\nfrom .formatter import Formatter\nfrom loguru import logger\nimport re\nfrom typing import List\nimport json\nimport uuid\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\nfrom app.base.query_plugin import QueryPlugin\n\n\nclass Bigquery(Formatter, BasePlugin, QueryPlugin,  PluginMetadataMixin):\n\n    def __init__(self, connector_name : str, project_id: str, service_account_json: str):\n        super().__init__(__name__)\n\n        self.connector_name = connector_name.replace(' ','_')\n        self.params = {\n            'project' : project_id,\n            'credentials' : service_account.Credentials.from_service_account_info(json.loads(service_account_json)),\n        }\n        self.client = None\n\n\n        self.schema = []\n\n    def connect(self):\n        \"\"\"\n        Establish a connection to BigQuery.\n        :return: Tuple containing connection status and an optional error message.\n        \"\"\"\n        try:\n            self.client = bigquery.Client(**self.params)\n\n            logger.info(\"Connection to Google Bigquery successful.\")\n            return True, None\n        except Exception as error:\n            logger.error(f\"Error connecting to Google Bigquery: {error}\")\n            return False, str(error)\n\n    def healthcheck(self):\n        \"\"\"\n        Perform a health check by executing a simple query.\n        :return: Tuple containing the health check status and an optional error message.\n        \"\"\"\n        if self.client is None:\n            logger.warning(\"Connection to BigQuery is not established.\")\n            return False, \"Connection to BigQuery is not established.\"\n        try:  \n            datasets = list(self.client.list_datasets())\n            if datasets:            \n                dataset_id = datasets[0].dataset_id\n                query = f\"SELECT * FROM {dataset_id}.INFORMATION_SCHEMA.TABLES\"\n                query_job = self.client.query(query)\n                results = query_job.result()\n\n                if results.total_rows > 0:\n                    logger.info(\"Healthcheck successful: BigQuery connection is healthy.\")\n                    return True, None\n\n            logger.warning(\"Healthcheck failed: No results returned.\")\n            return False, \"Healthcheck failed: No results returned.\"\n\n        except Exception as error:\n            logger.error(f\"Healthcheck failed: {error}\")\n            return False, str(error)\n\n    def configure_datasource(self, init_config):\n\n        return None\n\n    def fetch_data(self,query: str):\n        \"\"\"\n        Fetch data by executing a BigQuery SQL query.\n        :param query: SQL query string.\n        :return: Tuple of data rows and an optional error message.\n        \"\"\"\n        try:\n            query = self.client.query(query)\n            results = query.result()\n            rows = [row for row in results]\n            return rows, None\n        except Exception as e:\n            logger.critical(e)\n            return None, e\n\n    def fetch_schema_details(self):\n        \"\"\"\n        Fetch schema details for all tables in all datasets.\n        :return: A tuple containing the schema DDLs and table metadata.\n        \"\"\"\n\n        schema_ddl = []\n        table_metadata = []\n\n        if self.client is None:\n            logger.error(\"BigQuery client is not connected.\")\n            return schema_ddl, table_metadata\n\n        datasets = list(self.client.list_datasets())\n        if not datasets:\n            logger.critical(\"Project does not contain any datasets.\")\n            return schema_ddl, table_metadata\n\n        for dataset in datasets:\n            dataset_id = dataset.dataset_id\n            schema_structure_query = f\"SELECT * FROM {dataset_id}.INFORMATION_SCHEMA.TABLES\"\n            result, error = self.fetch_data(schema_structure_query)\n\n            if result is not None:\n                for res in result:\n\n                    schema = {\n                        \"table_id\": str(uuid.uuid4()),\n                        \"table_name\":  f\"{dataset.dataset_id}.{res[2]}\",\n                        \"description\": \"\",\n                        \"columns\": []\n                    }\n                    fields= []\n\n                    ddl = res[11]\n\n                    # Regex to extract column names and data types\n                    pattern = r'`([^`]+)`\\s(\\w+)|(\\w+)\\s(\\w+)'\n\n                    matches = re.findall(pattern, ddl)\n\n                    # Extract column names and data types from the matches\n                    columns = [match[0] or match[2] for match in matches]\n                    data_types = [match[1] or match[3] for match in matches]\n\n                    for index,(column, datatype) in enumerate(list(zip(columns, data_types))[1:]):\n                        fields.append({\n                            \"column_id\" : str(uuid.uuid4()),\n                            \"column_name\": column,\n                            \"column_type\": datatype,\n                            \"description\": \"\",\n                        })\n                    schema[\"columns\"] = fields\n\n                    table_metadata.append(schema)\n                    schema_ddl.append(ddl)\n\n            else:\n                logger.critical(f\"Error fetching schema:{error}\")\n\n\n        return schema_ddl, table_metadata\n\n\n\n    def create_ddl_from_metadata(self, table_metadata: List[dict]):\n        \"\"\"\n        Create DDL statements from table metadata.\n        :param table_metadata: List of table metadata.\n        :return: List of DDL strings.\n        \"\"\"\n        schema_ddl = []\n        for table in table_metadata:\n            tmp = f\"CREATE TABLE '{table['table_name']}'\"\n            for index,field in enumerate(table[\"columns\"]):\n                if index == 0:\n                    tmp = f\"{tmp} ({field.get('column_name','')} {field.get('column_type','')}\"\n                elif index < len(table['columns'])-1:\n                    tmp = f\"{tmp},{field.get('column_name','')} {field.get('column_type','')}\"\n                else:\n                    tmp = f\"{tmp},{field.get('column_name','')} {field.get('column_type','')});\"\n\n            schema_ddl.append(tmp)\n        return schema_ddl\n\n\n    def validate(self, formatted_query: str) -> None:\n        \"\"\"\n        Validate the formatted query (placeholder for actual implementation).\n        :param formatted_query: SQL query string.\n        \"\"\"\n        pass"
  },
  {
    "path": "app/plugins/csv/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'CSV'\n__display_name__ = 'CSV Loader'\n__description__ = 'CSV loader for interacting with CSV data'\n__icon__ = '/assets/plugins/logos/csv.svg'\n__category__ = 5\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    document_files = ConnectionArgument(\n        type = 8,\n        generic_name= 'csv file',\n        description = 'Supports only .csv file.',\n        order = 1,\n        required = True,\n        value = None,\n        slug = \"document_files\"\n    )\n)\n\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n            \"template\": \"\"\"\n            You are an Sqlite expert. Your job is to answer questions about a Sqlite database using only the provided schema details and rules.\n\n            go through the schema details given below\n            -- start db schema section--\n            {schema}\n            -- end db schema section--\n\n            A brief description about the schema is given below\n\n            -- start db context section--\n            {context}\n            -- end db context section--\n\n            Sample sql queries with their questions are given below\n\n            -- start query samples section--\n            $suggestions\n            -- end query samples section--\n\n            Adhere to the given rules without failure\n\n            -- start rules section --\n            - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`.\n            - use LIKE operator with LOWER function for string comparison or equality\n            - Always use alias/table name for fields in WHERE condition\n            - Do not use non existing tables or fields\n            - id columns are mandatory for all operations\n            - Do not use JSON_BUILD_OBJECT operation\n            - Do not use unwanted joins\n            - Do not return incomplete queries\n            - Adher to sqlite query syntax\n            -- end rules section --\n            \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            Follow these steps to generate query to solve the question `$question`\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Do only the task asked, Don't hallucinate and overdo the task\n            4. Strictly return all the fields in the schema during listing operations\n            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.\n            6. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            7. Generate a query to solve the problem using the schema, context, and strictly follow the rules\n            8. output in the given json format, extra explanation is strictly prohibited\n            9. If the table name contains hyphens (-), enclose the table name in double quotes (\")\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"sqlite query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"x-axis\": [\"fields that can be used as x axis\"],\n                    \"y-axis\": [\"fields that can be used as y axis\"],\n                    \"title\": \"layout title name\"\n                },\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]`\n            [question]\n            $question\n            [/question]\n\n            You generated this query given in `[query][/query]`\n            [query]\n            {query_generated}\n            [/query]\n\n            But upon execution you encountered some error , error traceback is given in [query_error][/query_error]\n            [query_error]\n            {exception_log}\n            [/query_error]\n\n            Follow these steps to generate the query\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Use survey answers if available and include it in query for filtering values\n            4. Do only the task asked, Don't hallucinate and overdo the task\n            5. Strictly return all the fields in the schema during listing operations\n            6. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            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\n            8. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"sqlite query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"value_field\": \"fields in which values are stored\",\n                    \"x-axis\": \"field that can be used as x axis\",\n                    \"y-axis\": \"field that can be used as y axis\",\n                    \"title\": \"layout title name\"\n                },\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n            }\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/csv/formatter.py",
    "content": "from typing import Any\nfrom loguru import logger\n\n\nclass Formatter:\n    def format(self, data: Any,input) -> (dict):\n        \"\"\"\n        Main entry point for formatting the data based on the input parameters.\n        Handles different formatting strategies based on operation kind.\n\n        :param data: The data to format.\n        :param input_params: Dictionary containing operation and formatting details.\n        :return: A dictionary containing the formatted response.\n        \"\"\"\n        response = {}\n        self.main_entity = input.get(\"main_entity\")\n        self.kind = input.get(\"operation_kind\", \"\").lower()\n        self.general_message = input.get(\"general_message\")\n        self.empty_message = input.get(\"empty_message\")\n\n        logger.info(\"Formatting output using inference for sqlite\")\n\n        if self.kind  == \"list\":\n            response = self.basic_formatter(data, input)\n        elif self.kind == \"aggregation\":\n            response = self.aggregation_formatter(data, input)\n        else:\n            response[\"data\"] = data\n            response[\"kind\"] = \"list\"\n\n\n        response.update({\n            \"main_entity\": self.main_entity,\n            \"main_format\": self.kind,\n            \"role\": \"assistant\",\n            \"content\": self.general_message,\n            \"empty_message\": self.empty_message,\n        })\n\n        return response\n\n    def basic_formatter(self, data: Any, input:Any) -> dict :\n        \"\"\"\n        Formats data as a list, handling cases for none, single, and multiple entries.\n\n        :param data: The data to format.\n        :return: A dictionary containing the formatted list response.\n        \"\"\"\n        logger.info(\"Formatting data as a list\")\n\n        if data is None:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"single\"}\n        else:\n            response = {\"data\": data, \"kind\": \"list\"}\n\n        return response\n\n\n    def aggregation_formatter(self, data:Any, input:Any) -> dict :\n        \"\"\"\n        Formats data for aggregation visualisation, supporting table and chart formats.\n\n        :param data: The data to format.\n        :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type).\n        :return: A dictionary containing the formatted aggregation response.\n        \"\"\"\n\n        logger.info(\"Formatting data as aggregation\")\n\n        visualisation = input.get(\"visualisation\", {})\n        title = visualisation.get(\"title\", \"\")\n        response = {}\n\n\n        if data is None or len(data) == 0:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"table\", \"title\": title}\n        else:\n            value_fields = visualisation.get(\"y-axis\", [])\n            key_fields = visualisation.get(\"x-axis\", [])\n\n            visualisaton_kind = visualisation[\"type\"].replace(\" \", \"_\") if visualisation[\"type\"] is not None else \"table\"\n\n            if visualisaton_kind.lower() in [\"bar_chart\", \"line_chart\", \"pie_chart\"] and len(value_fields) > 0 and len(key_fields) > 0:\n                response[\"kind\"] = visualisaton_kind\n                response[\"data\"] = data\n                response[\"x\"] = key_fields\n                response[\"y\"] = value_fields\n                response[\"title\"] = title\n            else:\n                response = {\"kind\": \"table\", \"data\": data, \"title\": title}\n\n        return response\n"
  },
  {
    "path": "app/plugins/csv/handler.py",
    "content": "from .formatter import Formatter\nfrom loguru import logger\nimport sqlite3\nimport pandas as pd\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\nfrom typing import Tuple, Optional, List\nimport uuid\nimport sqlparse\nimport sqlvalidator\nimport os\n\n\nclass CSVPlugin(BasePlugin, PluginMetadataMixin, Formatter):\n    \"\"\"\n    CSVPlugin class for interacting with CSV data and inserting it into an SQL database.\n    \"\"\"\n\n    def __init__(self, connector_name : str, document_files: List[str]):\n        super().__init__(__name__)\n        \n        self.connector_name = connector_name.replace(' ','_')\n        self.params = {\n            'csv_files': document_files,\n            'db_name': f\"{self.connector_name}.sqlite\",\n        }\n        self.connection = None\n        self.max_limit = 10\n\n    def _dict_factory(self, cursor, row):\n        d = {}\n        for idx, col in enumerate(cursor.description):\n            d[col[0]] = row[idx]\n        return d\n\n    def connect(self) -> Tuple[bool, Optional[str]]:\n        \"\"\"\n        Establish a connection to the SQLite database, delete all tables,\n        and insert data from CSV files.\n\n        :return: Tuple containing connection status (True/False) and an error message if any.\n        \"\"\"\n        try:\n            db_path = f\"assets/datasource/csv_db/{self.params['db_name']}\"\n            if 'db_name' not in self.params or not self.params['db_name']:\n                raise ValueError(\"Database name is missing or invalid in parameters.\")\n                        \n            if os.path.exists(db_path):\n                # Delete the file\n                os.remove(db_path)\n                print(f\"The database file '{db_path}' has been deleted successfully.\")\n\n            os.makedirs(os.path.dirname(db_path), exist_ok=True)\n\n            self.connection = sqlite3.connect(\n                db_path, \n                uri=True, \n                check_same_thread=False, \n                timeout=8.0\n            )\n            self.connection.row_factory = self._dict_factory\n            self.cursor = self.connection.cursor()\n            logger.info(f\"Connected to database: {db_path}\")\n                        \n            # Insert data from CSV files into the database\n            for csv_file in self.params.get('csv_files', []):\n                if 'file_name' not in csv_file or 'file_path' not in csv_file:\n                    logger.warning(f\"Invalid CSV file entry: {csv_file}\")\n                    continue\n\n                table_name = csv_file['file_name'].rsplit('.', 1)[0].replace(' ','_')\n                self._insert_csv_to_db(csv_file['file_path'], table_name)\n            \n            return True, None\n        except Exception as e:\n            logger.exception(f\"Failed to connect to database: {type(e).__name__}, {e}\")\n            return False, f\"{type(e).__name__}: {e}\"\n\n\n    def healthcheck(self):\n        try:\n            if self.connection is None:\n                logger.warning(\"Connection to CSV is not established.\")\n                return False, \"Connection to CSV is not established.\"\n\n            self.cursor.execute(\"SELECT 1;\")\n            return True, None        \n        except sqlite3.Error as error:\n            return False, error\n\n    def _insert_csv_to_db(self, csv_file: str, table_name: str):\n        \"\"\"\n        Helper method to read a CSV file and insert its data into an SQLite table.\n\n        :param csv_file: Path to the CSV file.\n        :param table_name: Name of the table to insert data into.\n        \"\"\"\n        try:\n            # Read CSV file using pandas\n            df = pd.read_csv(csv_file)\n            logger.info(f\"Read CSV file: {csv_file} with {len(df)} rows.\")\n\n            # Write to the SQLite database\n            df.to_sql(table_name, self.connection, if_exists='replace', index=False)\n            logger.info(f\"Data from {csv_file} inserted into table: {table_name}\")\n        except Exception as e:\n            logger.exception(f\"Failed to insert data from {csv_file} into table {table_name}: {str(e)}\")\n\n    def configure_datasource(self, init_config):\n        pass\n\n    def fetch_data(self, query, params=None):\n        try:\n            params = {} if params is None else params\n            self.cursor.execute(query, params)\n            if \"limit\"  not in query.lower():\n                return self.cursor.fetchmany(self.max_limit), None\n            else:\n                return self.cursor.fetchall(), None\n        except Exception as e:\n            logger.critical(e)\n            self.connection.rollback()\n            return None, e\n\n    def fetch_schema_details(self):\n        #Creating ddl from table schema\n        table_metadata = []\n        schema_ddl = []\n\n        table_schemas=self._fetch_table_schema()\n\n        if len(table_schemas) != 0 :\n\n            for table, columns in table_schemas.items():\n                table_ddl = \"\"\n\n                schema = {\n                    \"table_id\": str(uuid.uuid4()),\n                    \"table_name\": table,\n                    \"description\": \"\",\n                    \"columns\": []\n                }\n\n                fields= []\n                table_ddl = f\"\\n\\nCREATE TABLE {table} (\"\n                for column in columns:\n                    fields.append({\n                        \"column_id\" : str(uuid.uuid4()),\n                        \"column_name\": column['name'],\n                        \"column_type\": column['type'],\n                        \"description\": \"\",\n                    })\n                    table_ddl +=f\"\\n{column['name']} {column['type']} ,\"\n                table_ddl +=f\");\"\n\n                schema[\"columns\"] = fields\n                table_metadata.append(schema)\n                schema_ddl.append(table_ddl)\n\n        return schema_ddl, table_metadata\n\n    def create_ddl_from_metadata(self,table_metadata):\n        schema_ddl = []\n        for table in table_metadata:\n            tmp = f\"\\n\\nCREATE TABLE {table['table_name']}\"\n            for field in table[\"columns\"]:\n                tmp = f\"{tmp} {field.get('column_name','')} \\n\"\n            schema_ddl.append(tmp)\n        return schema_ddl\n    \n    def _fetch_table_schema(self):\n        # Execute query to get all table names \n        self.cursor.execute(\"SELECT name FROM sqlite_master\")\n        # Fetch all table names\n        table_names = self.cursor.fetchall()\n\n        table_schemas = {}\n\n        for table in table_names:\n            self.cursor.execute(f\"SELECT name, type FROM pragma_table_info('{table['name']}')\")\n            columns = self.cursor.fetchall()\n\n            table_schemas[table['name']] = columns\n        return table_schemas\n\n    def fetch_feedback(self):\n        pass\n\n\n    def validate(self,formated_sql):\n        #validate sql using SQLParser\n        queries = sqlparse.split(formated_sql)\n        query = queries[0]\n        formated_query = sqlparse.format(query, reindent=True, keyword_case='upper')\n\n        parsed = sqlparse.parse(formated_query)[0]\n\n        if parsed.get_type() != 'SELECT':\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        token_names = [p._get_repr_name() for p in parsed.tokens]\n        if \"DDL\" in token_names:\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        sql_query = sqlvalidator.parse(formated_sql)\n        try:\n            if not sql_query.is_valid():\n                logger.info(sql_query.is_valid())\n                return \"I didn't get you, Please reframe your question\"\n        except Exception as error:\n            logger.critical(f\"error:{error}\")\n        return  None\n\n    def close_conection(self):\n        self.cursor.close()\n        self.connection.close()"
  },
  {
    "path": "app/plugins/document/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'document'\n__display_name__ = 'Document Loader'\n__description__ = 'document integration for handling document data'\n__icon__ = '/assets/plugins/logos/document.svg'\n__category__ = 4\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    document_files= ConnectionArgument(\n        type = 8,\n        generic_name= 'document files',\n        description = 'Supports only .pdf, .yaml, .txt, and .docx files.',\n        order = 1,\n        required = True,\n        value = None,\n        slug = \"document_files\"\n    )\n)\n\n# Prompt\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n        \"template\": \"\"\"\n        You are a Chatbot designed to answer user questions based only on the context given to you.\n        Use the details enclosed in [context][/context] to generate answers.\n        [context]\n        {context}\n        [/context]\n\n        Adhere to these rules while generating answers:\n        - Carefully read through the question and context word by word to appropriately answer the question.\n        - Only use information provided in the context to answer questions.\n        - Answer should not break the json format\n        - If the answer cannot be found in the context, state that you don't have enough information to answer.\n        - Present the answer in a human-readable Markdown format\n        \n        \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            User question is \"$question\"\n            Generate a JSON response in the following format without any formatting:\n            {\n                \"explanation\": \"Explain how you determined the answer using the provided context\",\n                \"general_message\": \"Answer in Markdown format to user question based on the context with all the details\",\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            User question is \"$question\"\n            Generate a JSON response in the following format without any formatting:\n            {\n                \"explanation\": \"Explain how you determined the answer using the provided context\",\n                \"general_message\": \"Answer in Markdown format to user question based on the context\",\n            }\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/document/formatter.py",
    "content": "from typing import Any, Dict\nfrom loguru import logger\n\nclass Formatter:\n    \"\"\"\n    Formatter class to format the response based on the inference and data.\n    \"\"\"\n\n\n    def format(self, data: Dict[str, Any], inference: Dict[str, Any]) -> dict:\n        \"\"\"\n        Format the response using the given data and inference information.\n\n        :param data: The data containing records to process.\n        :param inference: Inference details including main entity and operation kind.\n        :return: Formatted response dictionary.\n        \"\"\"\n\n        logger.info(\"Processing output using inference details\")\n\n        response = {}\n        self.main_entity = inference.get(\"main_entity\", \"\")\n        self.kind = inference.get(\"operation_kind\", \"\")\n        self.general_message = inference.get(\"general_message\", \"Unable to process question, try again\")\n\n        response[\"content\"] = self.general_message\n\n        response[\"main_entity\"] = self.main_entity\n        response[\"main_format\"] = self.kind\n        response[\"role\"] = \"assistant\"\n        return response\n\n"
  },
  {
    "path": "app/plugins/document/handler.py",
    "content": "from .formatter import Formatter\nfrom loguru import logger\nimport requests\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.remote_data_plugin import RemoteDataPlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\nfrom app.base.document_data_plugin import DocumentDataPlugin\nfrom typing import  Tuple, Optional\nfrom app.readers.base_reader import BaseReader\nimport os\n\n\nclass Document(BasePlugin, PluginMetadataMixin,DocumentDataPlugin,  Formatter):\n    \"\"\"\n    Document class for interacting with document data.\n    \"\"\"\n\n    def __init__(self, connector_name : str, document_files:str):\n        super().__init__(__name__)\n\n        self.connection = {}\n\n        self.connector_name = connector_name.replace(' ','_')\n        self.params = {\n            'document_files': document_files,\n        }\n\n        self.supported_types = {\".pdf\": \"pdf\", \".docx\": \"docx\", \".txt\": \"text\", \".yaml\": \"yaml\"}\n\n\n    def connect(self):\n        \"\"\"\n        Mocked connection method for pdf.\n\n        :return: Tuple containing connection status (True/False) and an error message if any.\n        \"\"\"\n        return True, None\n\n\n    def healthcheck(self)-> Tuple[bool, Optional[str]]:\n        \"\"\"\n        Perform a health check by checking if the document is accessible.\n\n        :return: Tuple containing the health status (True/False) and error message (if any).\n        \"\"\"\n        logger.info(\"health check for documentations\")\n\n        try:\n            data = []\n            for file_info in self.params.get(\"document_files\", []):\n                file_path = file_info.get(\"file_path\")\n                if not file_path:\n                    logger.error(\"File path is missing in the document file information.\")\n                    continue\n\n                # Check if it's a URL or a local file\n                if file_path.startswith(\"http://\") or file_path.startswith(\"https://\"):\n                    try:\n                        response = requests.head(file_path, allow_redirects=True, timeout=5)\n                        if response.status_code >= 400:\n                            logger.error(f\"URL not accessible: {file_path}\")\n                        else:\n                            data.append(file_path)\n                    except Exception as e:\n                        logger.error(f\"Error accessing URL {file_path}: {e}\")\n                else:\n                    if os.path.exists(file_path):\n                        data.append(file_path)\n                    else:\n                        logger.error(f\"Local file does not exist: {file_path}\")\n            if not data:\n                raise ValueError(\"No data fetched during health check\")\n            \n            return True, None\n        except Exception as e:\n            logger.exception(f\"Exception during fetching data: {str(e)}\")\n            return False, str(e)\n\n    def fetch_data(self, params=None):\n        data = []\n\n        for file_info in self.params.get(\"document_files\", []):\n            url = file_info.get(\"file_path\")\n            if url is None:\n                logger.error(\"URL is missing in the document file information.\")\n                continue\n\n            file_type = None\n\n            for ext, typ in self.supported_types.items():\n                if url.endswith(ext):\n                    file_type = typ\n                    break\n\n            if file_type is None:\n                logger.error(f\"Unsupported file format: {url}\")\n                continue\n            base_reader = BaseReader({\n                \"type\": file_type,\n                \"path\": [url]\n            })\n            data.extend(base_reader.load_data())\n\n        return data\n\n\n"
  },
  {
    "path": "app/plugins/loader.py",
    "content": "from app.plugins.csv.handler import CSVPlugin\nfrom app.plugins.postgresql.handler import Postresql\nfrom app.plugins.mysql.handler import Mysql\nfrom app.plugins.mssql.handler import Mssql\nfrom app.plugins.bigquery.handler import Bigquery\nfrom app.plugins.airtable.handler import Airtable\nfrom app.plugins.website.handler import Website\nfrom app.plugins.document.handler import Document\nfrom app.plugins.sqlite.handler import Sqlite\nfrom app.plugins.maria.handler import Maria\nfrom loguru import logger\n\n\nclass DSLoader:\n    def __init__(self, configs):\n        self.config = configs\n\n    def load_ds(self):\n        db_classes = {\n            \"postgres\": Postresql,\n            \"mysql\": Mysql,\n            \"mssql\": Mssql,\n            \"bigquery\": Bigquery,\n            \"airtable\": Airtable,\n            \"website\": Website,\n            \"document\" : Document,\n            \"sqlite\" : Sqlite,\n            \"CSV\" : CSVPlugin,\n            \"maria\": Maria,\n        }\n        db_type = self.config.get(\"type\",\"\")\n        connection_params = self.config.get(\"params\",{})\n        connector_name = self.config.get(\"connector_name\",\"default\")\n\n        logger.info(f\"initialising {db_type}\")\n\n        db_class = db_classes.get(db_type)\n        if db_class:\n            try:\n                ds = db_class(connector_name=connector_name,**connection_params)\n                return ds\n            except Exception as e:\n                raise e\n\n        else:\n            logger.warning(\"Invalid database type specified in configuration.\")\n            return None"
  },
  {
    "path": "app/plugins/maria/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'maria'\n__display_name__ = \"MariaDB\"\n__description__ = 'MariaDB integration for handling MariaDB database operations.'\n__icon__ = '/assets/plugins/logos/mariaDB.svg'\n__category__ = 2\n\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    db_name= ConnectionArgument(\n        type = 1,\n        generic_name= 'MariaDB Database name',\n        description = 'Database name',\n        order= 5,\n        required = True,\n        value = None,\n        slug = \"db_name\"\n    ),\n    db_user=ConnectionArgument(\n        type= 1,\n        generic_name= 'MariaDB User name',\n        description= 'Database username',\n        order= 2,\n        required = True,\n        value = None,\n        slug = \"db_user\"\n    ),\n    db_password=ConnectionArgument(\n        type= 2,\n        generic_name= 'MariaDB Password',\n        description= 'Database password',\n        order= 3,\n        required = True,\n        value = None,\n        slug = \"db_password\"\n    ),\n    db_host=ConnectionArgument(\n        type= 1,\n        generic_name= 'MariaDB Database host',\n        description= 'Database hostname',\n        order= 1,\n        required = True,\n        value = None,\n        slug = \"db_host\"\n    ),\n    db_port=ConnectionArgument(\n        type= 3,\n        generic_name= 'MariaDB Database port',\n        description= 'Database port',\n        order = 4,\n        required = True,\n        value = None,\n        slug = \"db_port\"\n    ),\n)\n\n# Prompt\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n            \"template\": \"\"\"\n            You are an MariaDB expert. Your job is to answer questions about a MariaDB database using only the provided schema details and rules.\n\n            go through the schema details given below\n            -- start db schema section--\n            {schema}\n            -- end db schema section--\n\n            A brief description about the schema is given below\n\n            -- start db context section--\n            {context}\n            -- end db context section--\n\n            Sample sql queries with their questions are given below\n\n            -- start query samples section--\n            $suggestions\n            -- end query samples section--\n\n            Adhere to the given rules without failure\n\n            -- start rules section --\n            - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`.\n            - use LIKE operator with LOWER function for string comparison or equality\n            - Always use alias/table name for fields in WHERE condition\n            - Do not use non existing tables or fields\n            - id columns are mandatory for all operations\n            - Do not use JSON_BUILD_OBJECT operation\n            - Do not use unwanted joins\n            - Do not return incomplete queries\n            - Adher to sysql query syntax\n            -- end rules section --\n            \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            Follow these steps to generate query to solve the question `$question`\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Do only the task asked, Don't hallucinate and overdo the task\n            4. Strictly return all the fields in the schema during listing operations\n            5. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            6. Generate a query to solve the problem using the schema, context, and strictly follow the rules\n            7. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"mariadb query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"x-axis\": [\"fields that can be used as x axis\"],\n                    \"y-axis\": [\"fields that can be used as y axis\"],\n                    \"title\": \"layout title name\"\n                },\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]`\n            [question]\n            $question\n            [/question]\n\n            You generated this query given in `[query][/query]`\n            [query]\n            {query_generated}\n            [/query]\n\n            But upon execution you encountered some error , error traceback is given in [query_error][/query_error]\n            [query_error]\n            {exception_log}\n            [/query_error]\n\n            Follow these steps to generate the query\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Use survey answers if available and include it in query for filtering values\n            4. Do only the task asked, Don't hallucinate and overdo the task\n            5. Strictly return all the fields in the schema during listing operations\n            6. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            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\n            8. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"mariadb query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"value_field\": \"fields in which values are stored\",\n                    \"x-axis\": \"field that can be used as x axis\",\n                    \"y-axis\": \"field that can be used as y axis\",\n                    \"title\": \"layout title name\"\n                },\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n            }\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/maria/formatter.py",
    "content": "from typing import Any\nfrom loguru import logger\n\n\nclass Formatter:\n    def format(self, data: Any,input) -> (dict):\n        \"\"\"\n        Main entry point for formatting the data based on the input parameters.\n        Handles different formatting strategies based on operation kind.\n\n        :param data: The data to format.\n        :param input_params: Dictionary containing operation and formatting details.\n        :return: A dictionary containing the formatted response.\n        \"\"\"\n        response = {}\n        self.main_entity = input.get(\"main_entity\")\n        self.kind = input.get(\"operation_kind\", \"\").lower()\n        self.general_message = input.get(\"general_message\")\n        self.empty_message = input.get(\"empty_message\")\n\n        logger.info(\"Formatting output using inference for mariadb\")\n\n        if self.kind  == \"list\":\n            response = self.basic_formatter(data, input)\n        elif self.kind == \"aggregation\":\n            response = self.aggregation_formatter(data, input)\n        else:\n            response[\"data\"] = data\n            response[\"kind\"] = \"list\"\n\n\n        response.update({\n            \"main_entity\": self.main_entity,\n            \"main_format\": self.kind,\n            \"role\": \"assistant\",\n            \"content\": self.general_message,\n            \"empty_message\": self.empty_message,\n        })\n\n        return response\n\n    def basic_formatter(self, data: Any, input:Any) -> dict :\n        \"\"\"\n        Formats data as a list, handling cases for none, single, and multiple entries.\n\n        :param data: The data to format.\n        :return: A dictionary containing the formatted list response.\n        \"\"\"\n        logger.info(\"Formatting data as a list\")\n\n        if data is None:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"single\"}\n        else:\n            response = {\"data\": data, \"kind\": \"list\"}\n\n        return response\n\n\n    def aggregation_formatter(self, data:Any, input:Any) -> dict :\n        \"\"\"\n        Formats data for aggregation visualisation, supporting table and chart formats.\n\n        :param data: The data to format.\n        :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type).\n        :return: A dictionary containing the formatted aggregation response.\n        \"\"\"\n\n        logger.info(\"Formatting data as aggregation\")\n\n        visualisation = input.get(\"visualisation\", {})\n        response = {}\n\n\n        if data is None or len(data) == 0:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"table\"}\n        else:\n            value_fields = visualisation.get(\"y-axis\", [])\n            key_fields = visualisation.get(\"x-axis\", [])\n            title = visualisation.get(\"title\", \"\")\n\n            visualisaton_kind = visualisation[\"type\"].replace(\" \", \"_\") if visualisation[\"type\"] is not None else \"table\"\n\n            if visualisaton_kind.lower() in [\"bar_chart\", \"line_chart\", \"pie_chart\"] and len(value_fields) > 0 and len(key_fields) > 0:\n                response[\"kind\"] = visualisaton_kind\n                response[\"data\"] = data\n                response[\"x\"] = key_fields\n                response[\"y\"] = value_fields\n                response[\"title\"] = title\n            else:\n                response = {\"kind\": \"table\", \"data\": data}\n\n        return response\n\n\n\n\n"
  },
  {
    "path": "app/plugins/maria/handler.py",
    "content": "import mariadb\nfrom loguru import logger\nimport sqlvalidator\nimport sqlparse\nfrom .formatter import Formatter\nimport uuid\n\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.query_plugin import QueryPlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\n\n\nclass Maria(Formatter, BasePlugin, QueryPlugin,  PluginMetadataMixin):\n\n    def __init__(self,connector_name : str, db_name:str, db_user:str=\"root\", db_password:str=\"\", db_host:str=\"localhost\", db_port:int=3306):\n        logger.info(\"Initializing datasource\")\n        super().__init__(__name__)\n        \n        db_port = int(db_port)\n        \n        self.connector_name = connector_name.replace(' ','_')\n\n        # common\n        self.params = {\n            'database': db_name,\n            'user': db_user,\n            'password': db_password,\n            'host': db_host,\n            'port': db_port,\n        }\n        self.connection = None\n\n        # class specific\n        self.cursor = None\n        self.max_limit = 5\n        \n\n\n    def connect(self):\n        try:\n            self.connection = mariadb.connect(**self.params)\n            self.cursor = self.connection.cursor(dictionary=True)\n            logger.info(\"Connection to MariaDB successful.\")\n            return True, None\n        except mariadb.Error as error:\n            logger.error(f\"Error connecting to MariaDB: {error}\")\n            return False, error\n\n    def healthcheck(self):\n        try:\n            if self.connection is None:\n                logger.warning(\"Connection to MariaDB is not established.\")\n                return False, \"Connection to MariaDB is not established.\"\n\n            with self.connection.cursor() as cursor:\n                cursor.execute(\"SELECT 1;\")\n                cursor.fetchall() \n                return True, None\n        except mariadb.Error as error:\n            logger.error(f\"Error during healthcheck: {error}\")\n            return False, error\n\n\n    def configure_datasource(self, init_config):\n        logger.info(\"Configuring datasource\")\n        if init_config is not None and \"script\" in init_config:\n            try:\n                self.cursor.execute(init_config[\"script\"])\n                self.connection.commit()\n            except Exception as e:\n                return e\n\n        return None\n\n    def fetch_data(self, query, params=None):\n        try:\n            self.cursor.execute(query, params)\n            if \"limit\"  not in query.lower():\n                return self.cursor.fetchmany(self.max_limit), None\n            else:\n                return self.cursor.fetchall(), None\n        except mariadb.Error as e:\n            logger.critical(e)\n            self.connection.rollback()\n            return None, e\n\n    def fetch_schema_details(self):\n        #Creating ddl from table schema\n        table_metadata = []\n        schema_ddl = []\n\n        table_schemas=self._fetch_table_schema()\n\n        if len(table_schemas) != 0 :\n\n            for table, columns in table_schemas.items():\n                table_ddl = \"\"\n\n                schema = {\n                    \"table_id\": str(uuid.uuid4()),\n                    \"table_name\": table,\n                    \"description\": \"\",\n                    \"columns\": []\n                }\n\n                fields= []\n                table_ddl = f\"\\n\\nCREATE TABLE {table}\"\n                for column in columns:\n                    fields.append({\n                        \"column_id\" : str(uuid.uuid4()),\n                        \"column_name\": column['column_name'],\n                        \"column_type\": column['data_type'],\n                        \"description\": \"\",\n                    })\n                    table_ddl +=f\"\\n{column['column_name']} {column['data_type']} {column['character_maximum_length']},\"\n                table_ddl +=f\");\"\n\n                schema[\"columns\"] = fields\n                table_metadata.append(schema)\n                \n                schema_ddl.append(table_ddl)\n\n        return schema_ddl, table_metadata\n\n    def create_ddl_from_metadata(self,table_metadata):\n        schema_ddl = []\n        for table in table_metadata:\n            tmp = f\"\\n\\nCREATE TABLE {table['table_name']}\"\n            for field in table[\"columns\"]:\n                tmp = f\"{tmp} {field.get('column_name','')} \\n\"\n            schema_ddl.append(tmp)\n        return schema_ddl\n\n\n    def _fetch_table_schema(self):\n        # Execute query to get all table names in the public schema\n        self.cursor.execute(\"SHOW TABLES\")\n        # Fetch all table names\n        table_names = self.cursor.fetchall()\n\n        table_schemas = {}\n\n        for table in table_names:\n\n            table_name = next(iter(table.values()))\n            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}'\")\n            columns = self.cursor.fetchall()\n\n\n            table_schemas[table_name] = columns\n        return table_schemas\n\n    def fetch_feedback(self):\n        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);\"\n        result = self.fetch_data(sql_query)\n        logger.info(result)\n        return result\n\n    def validate(self,formated_sql):\n        #validate sql using SQLParser\n        queries = sqlparse.split(formated_sql)\n        query = queries[0]\n        formated_query = sqlparse.format(query, reindent=True, keyword_case='upper')\n\n        parsed = sqlparse.parse(formated_query)[0]\n\n        if parsed.get_type() != 'SELECT':\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        token_names = [p._get_repr_name() for p in parsed.tokens]\n        if \"DDL\" in token_names:\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        sql_query = sqlvalidator.parse(formated_sql)\n        if not sql_query.is_valid():\n            logger.info(sql_query.is_valid())\n            return \"I didn't get you, Please reframe your question\"\n\n        return  None\n\n    def close_connection(self):\n        self.cursor.close()\n        self.connection.close()\n\n\n"
  },
  {
    "path": "app/plugins/mssql/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'mssql'\n__display_name__ = \"MSSQL DB\"\n__description__ = 'MSSQL integration for handling MSSQL database operations.'\n__icon__ = '/assets/plugins/logos/mssql.svg'\n__category__ = 2\n\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    db_name= ConnectionArgument(\n        type = 1,\n        generic_name= 'MSSQL Database name',\n        description = 'Database name',\n        order= 5,\n        required = True,\n        value = None,\n        slug = \"db_name\"\n    ),\n    db_user=ConnectionArgument(\n        type= 1,\n        generic_name= 'MSSQL User name',\n        description= 'Database username',\n        order= 2,\n        required = True,\n        value = None,\n        slug = \"db_user\"\n    ),\n    db_password=ConnectionArgument(\n        type= 2,\n        generic_name= 'MSSQL Password',\n        description= 'Database password',\n        order= 3,\n        required = True,\n        value = None,\n        slug = \"db_password\"\n    ),\n    db_server=ConnectionArgument(\n        type= 1,\n        generic_name= 'MSSQL Database Server',\n        description= 'Include port number with a comma in server eg: ip.aaaaaaa.com,9600',\n        order= 1,\n        required = True,\n        value = None,\n        slug = \"db_server\"\n    ),\n    db_port=ConnectionArgument(\n        type= 3,\n        generic_name= 'MSSQL Database port',\n        description= 'Database port',\n        order = 4,\n        required = True,\n        value = None,\n        slug = \"db_port\"\n    ),\n)\n\n# Prompt\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n            \"template\": \"\"\"\n            You are an Mssql expert. Your job is to answer questions about a Mssql database using only the provided schema details and rules.\n\n            Conversation history is provided below:\n            -- start chat_history section --\n            {recal_history}\n            -- end chat_history section --\n\n            go through the schema details given below:\n            -- start db schema section--\n            {schema}\n            -- end db schema section--\n\n            A brief description about the schema is given below:\n            -- start db context section--\n            {context}\n            -- end db context section--\n\n            Sample sql queries with their questions are given below:\n            -- start query samples section--\n            $suggestions\n            -- end query samples section--\n\n            Adhere to the given rules without failure\n\n            -- start rules section --\n            - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`.\n            - use LIKE operator with LOWER function for string comparison or equality\n            - Always use alias/table name for fields in WHERE condition\n            - Do not use non existing tables or fields\n            - id columns are mandatory for all operations\n            - Do not use JSON_BUILD_OBJECT operation\n            - Do not use unwanted joins\n            - Do not return incomplete queries\n            - Adher to sysql query syntax\n            -- end rules section --\n            \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            Follow these steps to generate query to solve the question `$question`\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Do only the task asked, Don't hallucinate and overdo the task\n            4. Strictly return all the fields in the schema during listing operations\n            5. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            6. Generate a query to solve the problem using the schema, context, and strictly follow the rules\n            7. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"mssql query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"x-axis\": [\"fields that can be used as x axis\"],\n                    \"y-axis\": [\"fields that can be used as y axis\"],\n                    \"title\": \"layout title name\"\n                },\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]`\n            [question]\n            $question\n            [/question]\n\n            You generated this query given in `[query][/query]`\n            [query]\n            {query_generated}\n            [/query]\n\n            But upon execution you encountered some error , error traceback is given in [query_error][/query_error]\n            [query_error]\n            {exception_log}\n            [/query_error]\n\n            Follow these steps to generate the query\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Use survey answers if available and include it in query for filtering values\n            4. Do only the task asked, Don't hallucinate and overdo the task\n            5. Strictly return all the fields in the schema during listing operations\n            6. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            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\n            8. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"mssql query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"value_field\": \"fields in which values are stored\",\n                    \"x-axis\": \"field that can be used as x axis\",\n                    \"y-axis\": \"field that can be used as y axis\",\n                    \"title\": \"layout title name\"\n                },\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n            }\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/mssql/formatter.py",
    "content": "from typing import Any\nfrom loguru import logger\n\n\nclass Formatter:\n    def format(self, data: Any,input) -> (dict):\n        \"\"\"\n        Main entry point for formatting the data based on the input parameters.\n        Handles different formatting strategies based on operation kind.\n\n        :param data: The data to format.\n        :param input_params: Dictionary containing operation and formatting details.\n        :return: A dictionary containing the formatted response.\n        \"\"\"\n        response = {}\n        self.main_entity = input.get(\"main_entity\")\n        self.kind = input.get(\"operation_kind\", \"\").lower()\n        self.general_message = input.get(\"general_message\")\n        self.empty_message = input.get(\"empty_message\")\n\n        logger.info(\"Formatting output using inference for mysql\")\n\n        if self.kind  == \"list\":\n            response = self.basic_formatter(data, input)\n        elif self.kind == \"aggregation\":\n            response = self.aggregation_formatter(data, input)\n        else:\n            response[\"data\"] = data\n            response[\"kind\"] = \"list\"\n\n\n        response.update({\n            \"main_entity\": self.main_entity,\n            \"main_format\": self.kind,\n            \"role\": \"assistant\",\n            \"content\": self.general_message,\n            \"empty_message\": self.empty_message,\n        })\n\n        return response\n\n    def basic_formatter(self, data: Any, input:Any) -> dict :\n        \"\"\"\n        Formats data as a list, handling cases for none, single, and multiple entries.\n\n        :param data: The data to format.\n        :return: A dictionary containing the formatted list response.\n        \"\"\"\n        logger.info(\"Formatting data as a list\")\n\n        if data is None:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"single\"}\n        else:\n            response = {\"data\": data, \"kind\": \"list\"}\n\n        return response\n\n\n    def aggregation_formatter(self, data:Any, input:Any) -> dict :\n        \"\"\"\n        Formats data for aggregation visualisation, supporting table and chart formats.\n\n        :param data: The data to format.\n        :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type).\n        :return: A dictionary containing the formatted aggregation response.\n        \"\"\"\n\n        logger.info(\"Formatting data as aggregation\")\n\n        visualisation = input.get(\"visualisation\", {})\n        response = {}\n\n\n        if data is None or len(data) == 0:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"table\"}\n        else:\n            value_fields = visualisation.get(\"y-axis\", [])\n            key_fields = visualisation.get(\"x-axis\", [])\n            title = visualisation.get(\"title\", \"\")\n\n            visualisaton_kind = visualisation[\"type\"].replace(\" \", \"_\") if visualisation[\"type\"] is not None else \"table\"\n\n            if visualisaton_kind.lower() in [\"bar_chart\", \"line_chart\", \"pie_chart\"] and len(value_fields) > 0 and len(key_fields) > 0:\n                response[\"kind\"] = visualisaton_kind\n                response[\"data\"] = data\n                response[\"x\"] = key_fields\n                response[\"y\"] = value_fields\n                response[\"title\"] = title\n            else:\n                response = {\"kind\": \"table\", \"data\": data}\n\n        return response\n\n\n\n\n"
  },
  {
    "path": "app/plugins/mssql/handler.py",
    "content": "import pyodbc\nfrom loguru import logger\nimport sqlvalidator\nimport sqlparse\nfrom .formatter import Formatter\nimport uuid\n\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.query_plugin import QueryPlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\n\n\nclass Mssql(Formatter, BasePlugin, QueryPlugin,  PluginMetadataMixin):\n\n\n    def __init__(self, connector_name : str, db_name:str, db_user:str, db_password:str, db_server:str=\"localhost\", db_port:int=1433):\n        logger.info(\"Initializing datasource\")\n        super().__init__(__name__)\n\n\n        self.connector_name = connector_name.replace(' ','_')\n        self.params = {\n            'database': db_name,\n            'user': db_user,\n            'password': db_password,\n            'server': db_server,\n            'port': db_port,\n        }\n        self.connection = None\n\n        self.cursor = None\n        self.max_limit = 10000\n\n\n    def connect(self):\n        try:\n            drivers = [driver for driver in pyodbc.drivers()]\n            connection_string = (\n                f\"DRIVER={{{drivers[0]}}};\"\n                f\"SERVER={self.params['server']},{self.params['port']};\"\n                f\"DATABASE={self.params['database']};\"\n                f\"UID={self.params['user']};\"\n                f\"PWD={self.params['password']};\"\n                f\"TrustServerCertificate=yes;\"\n            )\n            self.connection = pyodbc.connect(connection_string)\n            self.cursor = self.connection.cursor()\n            logger.info(\"Connection to MsSQL DB successful.\")\n            return True, None\n        except pyodbc.Error as error:\n            logger.error(f\"Error connecting to MsSQL DB: {error}\")\n            return False, str(error)\n\n    def healthcheck(self):\n        try:\n            if self.connection is None:\n                logger.warning(\"Connection to MsSQL DB is not established.\")\n                return False, \"Connection to MsSQL DB is not established.\"\n\n            with self.connection.cursor() as cursor:\n                cursor.execute(\"SELECT 1;\")\n                cursor.fetchall() \n                return True, None\n        except pyodbc.Error as error:\n            logger.error(f\"Error during healthcheck: {error}\")\n            return False, str(error)\n\n\n    def configure_datasource(self, init_config):\n        pass\n\n    def fetch_data(self, query, reconnect_attempt = True, params=None):\n        try:\n            self.cursor.execute(query)\n\n            # Fetch column names\n            column_names = [column[0] for column in self.cursor.description]\n\n            # Fetch data\n            if \"TOP\" not in query.upper():\n                rows = self.cursor.fetchmany(self.max_limit)\n            else:\n                rows = self.cursor.fetchall()\n\n            # Map column names to row data\n            result = [dict(zip(column_names, row)) for row in rows]\n\n            return result, None\n        except pyodbc.Error as error:\n            logger.error(f\"Error executing query: {error}\")\n            if '08S01' in str(error) and reconnect_attempt:\n                logger.info(\"Attempting to reconnect...\")\n                self.connect()  # Attempt to reconnect\n                reconnect_attempt = False\n                self.fetch_data(query, reconnect_attempt = False, params=None)\n            return None, str(error)\n\n    def fetch_schema_details(self):\n        schema_ddl = []\n        table_metadata = []\n\n        # Fetch all table and view names\n        self.cursor.execute(\"\"\"\n            SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE \n            FROM INFORMATION_SCHEMA.TABLES \n            WHERE TABLE_TYPE IN ('BASE TABLE', 'VIEW')\n        \"\"\")\n        tables = self.cursor.fetchall()\n\n        for table in tables:\n            schema_name = table[0]\n            table_name = table[1]\n            table_type = table[2]\n\n            logger.info(f\"Fetching DDL for {table_type}: {schema_name}.{table_name}\")\n\n            schema = {\n                \"table_id\": str(uuid.uuid4()),\n                \"table_name\": f\"{schema_name}.{table_name}\",\n                \"description\": \"\",\n                \"columns\": []\n            }\n\n            # Fetch column details\n            self.cursor.execute(f\"\"\"\n                SELECT \n                    COLUMN_NAME,\n                    DATA_TYPE,\n                    CHARACTER_MAXIMUM_LENGTH,\n                    IS_NULLABLE,\n                    COLUMN_DEFAULT\n                FROM \n                    INFORMATION_SCHEMA.COLUMNS\n                WHERE \n                    TABLE_SCHEMA = '{schema_name}'\n                    AND TABLE_NAME = '{table_name}';\n            \"\"\")\n            columns = self.cursor.fetchall()\n            ddl = f\"CREATE { 'TABLE' if table_type == 'BASE TABLE' else 'VIEW' } {schema_name}.{table_name} (\\n\"\n            fields = []\n\n            for column in columns:\n                column_name = column[0]\n                data_type = column[1]\n                max_length = column[2]\n                is_nullable = column[3]\n                column_default = column[4]\n\n                fields.append({\n                    \"column_id\": str(uuid.uuid4()),\n                    \"column_name\": column_name,\n                    \"column_type\": data_type,\n                    \"description\": \"\",\n                })\n\n                # Format data type with length if needed\n                datatype_formatted = f\"{data_type}({max_length})\" if max_length else data_type\n\n                nullable = \"NULL\" if is_nullable == \"YES\" else \"NOT NULL\"\n                default = f\"DEFAULT {column_default}\" if column_default else \"\"\n\n                ddl += f\"    {column_name} {datatype_formatted} {nullable} {default},\\n\"\n\n            # Fix schema['columns'] once per table\n            schema[\"columns\"] = fields\n            table_metadata.append(schema)\n\n            # Clean up DDL (remove last comma)\n            ddl = ddl.rstrip(\",\\n\") + \"\\n);\\n\\n\"\n            schema_ddl.append(ddl)\n            \n        table_metadata = sorted(table_metadata, key=lambda x: x['table_name'].lower())\n        return schema_ddl, table_metadata\n\n\n    def create_ddl_from_metadata(self,table_metadata):\n        schema_ddl = []\n        for table in table_metadata:\n            tmp = f\"\\n\\nCREATE TABLE {table['table_name']}\"\n            for field in table[\"columns\"]:\n                tmp = f\"{tmp} {field.get('column_name','')} \\n\"\n            schema_ddl.append(tmp)\n        return schema_ddl\n\n\n    def fetch_feedback(self):\n        pass\n\n    def validate(self,formated_sql):\n        #validate sql using SQLParser\n        queries = sqlparse.split(formated_sql)\n        query = queries[0]\n        formated_query = sqlparse.format(query, reindent=True, keyword_case='upper')\n\n        parsed = sqlparse.parse(formated_query)[0]\n\n        if parsed.get_type() != 'SELECT':\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        token_names = [p._get_repr_name() for p in parsed.tokens]\n        if \"DDL\" in token_names:\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        # sql_query = sqlvalidator.parse(formated_sql)\n        # if not sql_query.is_valid():\n        #     logger.info(sql_query.is_valid())\n        #     return \"I didn't get you, Please reframe your question\"\n\n        return  None\n\n    def close_connection(self):\n        self.cursor.close()\n        self.connection.close()"
  },
  {
    "path": "app/plugins/mysql/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'mysql'\n__display_name__ = \"MySQL DB\"\n__description__ = 'MySQL integration for handling MySQL database operations.'\n__icon__ = '/assets/plugins/logos/mysql.svg'\n__category__ = 2\n\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    db_name= ConnectionArgument(\n        type = 1,\n        generic_name= 'MySQL Database name',\n        description = 'Database name',\n        order= 5,\n        required = True,\n        value = None,\n        slug = \"db_name\"\n    ),\n    db_user=ConnectionArgument(\n        type= 1,\n        generic_name= 'MySQL User name',\n        description= 'Database username',\n        order= 2,\n        required = True,\n        value = None,\n        slug = \"db_user\"\n    ),\n    db_password=ConnectionArgument(\n        type= 2,\n        generic_name= 'MySQL Password',\n        description= 'Database password',\n        order= 3,\n        required = True,\n        value = None,\n        slug = \"db_password\"\n    ),\n    db_host=ConnectionArgument(\n        type= 1,\n        generic_name= 'MySQL Database host',\n        description= 'Database hostname',\n        order= 1,\n        required = True,\n        value = None,\n        slug = \"db_host\"\n    ),\n    db_port=ConnectionArgument(\n        type= 3,\n        generic_name= 'MySQL Database port',\n        description= 'Database port',\n        order = 4,\n        required = True,\n        value = None,\n        slug = \"db_port\"\n    ),\n)\n\n# Prompt\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n            \"template\": \"\"\"\n            You are an Mysql expert. Your job is to answer questions about a Mysql database using only the provided schema details and rules.\n\n            go through the schema details given below\n            -- start db schema section--\n            {schema}\n            -- end db schema section--\n\n            A brief description about the schema is given below\n\n            -- start db context section--\n            {context}\n            -- end db context section--\n\n            Sample sql queries with their questions are given below\n\n            -- start query samples section--\n            $suggestions\n            -- end query samples section--\n\n            Adhere to the given rules without failure\n\n            -- start rules section --\n            - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`.\n            - use LIKE operator with LOWER function for string comparison or equality\n            - Always use alias/table name for fields in WHERE condition\n            - Do not use non existing tables or fields\n            - id columns are mandatory for all operations\n            - Do not use JSON_BUILD_OBJECT operation\n            - Do not use unwanted joins\n            - Do not return incomplete queries\n            - Adher to sysql query syntax\n            -- end rules section --\n            \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            Follow these steps to generate query to solve the question `$question`\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Do only the task asked, Don't hallucinate and overdo the task\n            4. Strictly return all the fields in the schema during listing operations\n            5. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            6. Generate a query to solve the problem using the schema, context, and strictly follow the rules\n            7. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"mysql query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"x-axis\": [\"fields that can be used as x axis\"],\n                    \"y-axis\": [\"fields that can be used as y axis\"],\n                    \"title\": \"layout title name\"\n                },\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]`\n            [question]\n            $question\n            [/question]\n\n            You generated this query given in `[query][/query]`\n            [query]\n            {query_generated}\n            [/query]\n\n            But upon execution you encountered some error , error traceback is given in [query_error][/query_error]\n            [query_error]\n            {exception_log}\n            [/query_error]\n\n            Follow these steps to generate the query\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Use survey answers if available and include it in query for filtering values\n            4. Do only the task asked, Don't hallucinate and overdo the task\n            5. Strictly return all the fields in the schema during listing operations\n            6. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            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\n            8. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"mysql query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"value_field\": \"fields in which values are stored\",\n                    \"x-axis\": \"field that can be used as x axis\",\n                    \"y-axis\": \"field that can be used as y axis\",\n                    \"title\": \"layout title name\"\n                },\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n            }\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/mysql/formatter.py",
    "content": "from typing import Any\nfrom loguru import logger\n\n\nclass Formatter:\n    def format(self, data: Any,input) -> (dict):\n        \"\"\"\n        Main entry point for formatting the data based on the input parameters.\n        Handles different formatting strategies based on operation kind.\n\n        :param data: The data to format.\n        :param input_params: Dictionary containing operation and formatting details.\n        :return: A dictionary containing the formatted response.\n        \"\"\"\n        response = {}\n        self.main_entity = input.get(\"main_entity\")\n        self.kind = input.get(\"operation_kind\", \"\").lower()\n        self.general_message = input.get(\"general_message\")\n        self.empty_message = input.get(\"empty_message\")\n\n        logger.info(\"Formatting output using inference for mysql\")\n\n        if self.kind  == \"list\":\n            response = self.basic_formatter(data, input)\n        elif self.kind == \"aggregation\":\n            response = self.aggregation_formatter(data, input)\n        else:\n            response[\"data\"] = data\n            response[\"kind\"] = \"list\"\n\n\n        response.update({\n            \"main_entity\": self.main_entity,\n            \"main_format\": self.kind,\n            \"role\": \"assistant\",\n            \"content\": self.general_message,\n            \"empty_message\": self.empty_message,\n        })\n\n        return response\n\n    def basic_formatter(self, data: Any, input:Any) -> dict :\n        \"\"\"\n        Formats data as a list, handling cases for none, single, and multiple entries.\n\n        :param data: The data to format.\n        :return: A dictionary containing the formatted list response.\n        \"\"\"\n        logger.info(\"Formatting data as a list\")\n\n        if data is None:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"single\"}\n        else:\n            response = {\"data\": data, \"kind\": \"list\"}\n\n        return response\n\n\n    def aggregation_formatter(self, data:Any, input:Any) -> dict :\n        \"\"\"\n        Formats data for aggregation visualisation, supporting table and chart formats.\n\n        :param data: The data to format.\n        :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type).\n        :return: A dictionary containing the formatted aggregation response.\n        \"\"\"\n\n        logger.info(\"Formatting data as aggregation\")\n\n        visualisation = input.get(\"visualisation\", {})\n        response = {}\n\n\n        if data is None or len(data) == 0:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"table\"}\n        else:\n            value_fields = visualisation.get(\"y-axis\", [])\n            key_fields = visualisation.get(\"x-axis\", [])\n            title = visualisation.get(\"title\", \"\")\n\n            visualisaton_kind = visualisation[\"type\"].replace(\" \", \"_\") if visualisation[\"type\"] is not None else \"table\"\n\n            if visualisaton_kind.lower() in [\"bar_chart\", \"line_chart\", \"pie_chart\"] and len(value_fields) > 0 and len(key_fields) > 0:\n                response[\"kind\"] = visualisaton_kind\n                response[\"data\"] = data\n                response[\"x\"] = key_fields\n                response[\"y\"] = value_fields\n                response[\"title\"] = title\n            else:\n                response = {\"kind\": \"table\", \"data\": data}\n\n        return response\n\n\n\n\n"
  },
  {
    "path": "app/plugins/mysql/handler.py",
    "content": "import pymysql\nimport mysql.connector\nfrom loguru import logger\nimport sqlvalidator\nimport sqlparse\nfrom .formatter import Formatter\nimport uuid\n\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.query_plugin import QueryPlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\n\n\nclass Mysql(Formatter, BasePlugin, QueryPlugin,  PluginMetadataMixin):\n\n    def __init__(self, connector_name : str, db_name:str, db_user:str=\"root\", db_password:str=\"\", db_host:str=\"localhost\", db_port:int=3306):\n        logger.info(\"Initializing datasource\")\n        super().__init__(__name__)\n\n        self.connector_name = connector_name.replace(' ','_')\n        # common\n        self.params = {\n            'database': db_name,\n            'user': db_user,\n            'password': db_password,\n            'host': db_host,\n            'port': db_port,\n        }\n        self.connection = None\n\n\n        # class specific\n        self.cursor = None\n        self.max_limit = 5\n\n\n    def connect(self):\n        try:\n            self.connection = mysql.connector.connect(**self.params)\n            self.cursor = self.connection.cursor(dictionary=True)\n            logger.info(\"Connection to MySQL DB successful.\")\n            return True, None\n        except mysql.connector.Error as error:\n            logger.error(f\"Error connecting to MySQL DB: {error}\")\n            return False, error\n\n    def healthcheck(self):\n        try:\n            if self.connection is None or not self.connection.is_connected():\n                logger.warning(\"Connection to MySQL DB is not established.\")\n                return False, \"Connection to MySQL DB is not established.\"\n\n            with self.connection.cursor() as cursor:\n                cursor.execute(\"SELECT 1;\")\n                cursor.fetchall() \n                return True, None\n        except mysql.connector.Error as error:\n            logger.error(f\"Error during healthcheck: {error}\")\n            return False, error\n\n\n    def configure_datasource(self, init_config):\n        logger.info(\"Configuring datasource\")\n        if init_config is not None and \"script\" in init_config:\n            try:\n                self.cursor.execute(init_config[\"script\"])\n                self.connection.commit()\n            except Exception as e:\n                return e\n\n        return None\n\n    def fetch_data(self, query, params=None):\n        try:\n            self.cursor.execute(query, params)\n            if \"limit\"  not in query.lower():\n                return self.cursor.fetchmany(self.max_limit), None\n            else:\n                return self.cursor.fetchall(), None\n        except pymysql.Error as e:\n            logger.critical(e)\n            self.connection.rollback()\n            return None, e\n\n    def fetch_schema_details(self):\n        #Creating ddl from table schema\n        table_metadata = []\n        schema_ddl = []\n\n        table_schemas=self._fetch_table_schema()\n\n        if len(table_schemas) != 0 :\n\n            for table, columns in table_schemas.items():\n                table_ddl = \"\"\n\n                schema = {\n                    \"table_id\": str(uuid.uuid4()),\n                    \"table_name\": table,\n                    \"description\": \"\",\n                    \"columns\": []\n                }\n\n                fields= []\n                table_ddl = f\"\\n\\nCREATE TABLE {table}\"\n                for column in columns:\n                    fields.append({\n                        \"column_id\" : str(uuid.uuid4()),\n                        \"column_name\": column['COLUMN_NAME'],\n                        \"column_type\": column['DATA_TYPE'],\n                        \"description\": \"\",\n                    })\n                    table_ddl +=f\"\\n{column['COLUMN_NAME']} {column['DATA_TYPE']} {column['CHARACTER_MAXIMUM_LENGTH']},\"\n                table_ddl +=f\");\"\n\n                schema[\"columns\"] = fields\n                table_metadata.append(schema)\n                \n                schema_ddl.append(table_ddl)\n\n        return schema_ddl, table_metadata\n\n    def create_ddl_from_metadata(self,table_metadata):\n        schema_ddl = []\n        for table in table_metadata:\n            tmp = f\"\\n\\nCREATE TABLE {table['table_name']}\"\n            for field in table[\"columns\"]:\n                tmp = f\"{tmp} {field.get('column_name','')} \\n\"\n            schema_ddl.append(tmp)\n        return schema_ddl\n\n\n    def _fetch_table_schema(self):\n        # Execute query to get all table names in the public schema\n        self.cursor.execute(\"SHOW TABLES\")\n        # Fetch all table names\n        table_names = self.cursor.fetchall()\n\n        table_schemas = {}\n\n        for table in table_names:\n\n            table_name = next(iter(table.values()))\n            self.cursor.execute(f\"SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = '{table_name}'\")\n            columns = self.cursor.fetchall()\n\n\n            table_schemas[table_name] = columns\n        return table_schemas\n\n    def fetch_feedback(self):\n        sql_query = \"SELECT chat_query, feedback_json FROM public.chat_histories WHERE feedback_status = 2 AND created_at >= CURRENT_DATE - INTERVAL '7 days';\"\n        result = self.fetch_data(sql_query)\n        logger.info(result)\n        return result\n\n    def validate(self,formated_sql):\n        #validate sql using SQLParser\n        queries = sqlparse.split(formated_sql)\n        query = queries[0]\n        formated_query = sqlparse.format(query, reindent=True, keyword_case='upper')\n\n        parsed = sqlparse.parse(formated_query)[0]\n\n        if parsed.get_type() != 'SELECT':\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        token_names = [p._get_repr_name() for p in parsed.tokens]\n        if \"DDL\" in token_names:\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        sql_query = sqlvalidator.parse(formated_sql)\n        if not sql_query.is_valid():\n            logger.info(sql_query.is_valid())\n            return \"I didn't get you, Please reframe your question\"\n\n        return  None\n\n    def close_connection(self):\n        self.cursor.close()\n        self.connection.close()\n\n\n"
  },
  {
    "path": "app/plugins/postgresql/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'postgres'\n__display_name__ = \"Postgres DB\"\n__description__ = 'Postgres integration for handling Postgres database operations.'\n__icon__ = '/assets/plugins/logos/postgresql.svg'\n__category__ = 2\n\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    db_name= ConnectionArgument(\n        type = 1,\n        generic_name= 'Database name',\n        description = 'Database name',\n        order= 5,\n        required = True,\n        value = None,\n        slug = \"db_name\"\n    ),\n    db_user=ConnectionArgument(\n        type= 1,\n        generic_name= 'User name',\n        description= 'Database username',\n        order= 2,\n        required = True,\n        value = None,\n        slug = \"db_user\"\n    ),\n    db_password=ConnectionArgument(\n        type= 2,\n        generic_name= 'Password',\n        description= 'Database password',\n        order= 3,\n        required = True,\n        value = None,\n        slug = \"db_password\"\n    ),\n    db_host=ConnectionArgument(\n        type= 1,\n        generic_name= 'Database host',\n        description= 'Database hostname',\n        order= 1,\n        required = True,\n        value = None,\n        slug = \"db_host\"\n    ),\n    db_port=ConnectionArgument(\n        type= 3,\n        generic_name= 'Database port',\n        description= 'Database port',\n        order = 4,\n        required = True,\n        value = None,\n        slug = \"db_port\"\n    ),\n    db_sslmode=ConnectionArgument(\n        type= 6,\n        generic_name= 'Database sslmode',\n        description= 'SSL mode',\n        order= 6,\n        required = True,\n        value=[{\"label\":\"prefer\", \"value\": \"prefer\"}, {\"label\":\"disable\", \"value\": \"disable\"}, {\"label\":\"require\", \"value\": \"require\"}],\n        slug = \"db_sslmode\"\n    )\n)\n\n# Prompt\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n            \"template\": \"\"\"\n            You are an Postgresql expert. Your job is to answer questions about a Postgres database using only the provided schema details and rules.\n\n            go through the schema details given below\n            -- start db schema section--\n            {schema}\n            -- end db schema section--\n\n            A brief description about the schema is given below\n\n            -- start db context section--\n            {context}\n            -- end db context section--\n\n            Sample sql queries with their questions are given below\n\n            -- start query samples section--\n            $suggestions\n            -- end query samples section--\n\n            Adhere to the given rules without failure\n\n            -- start rules section --\n            - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`.\n            - use LIKE operator with LOWER function for string comparison or equality\n            - Always use alias/table name for fields in WHERE condition\n            - Do not use non existing tables or fields\n            - id columns are mandatory for all operations\n            - Do not use JSON_BUILD_OBJECT operation\n            - Do not use unwanted joins\n            - Do not return incomplete queries\n            - Adher to postgresql query syntax\n            -- end rules section --\n            \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            Follow these steps to generate query to solve the question `$question`\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Do only the task asked, Don't hallucinate and overdo the task\n            4. Strictly return all the fields in the schema during listing operations\n            5. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            6. Generate a query to solve the problem using the schema, context, and strictly follow the rules\n            7. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"postgresql query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"x-axis\": [\"fields that can be used as x axis\"],\n                    \"y-axis\": [\"fields that can be used as y axis\"],\n                    \"title\": \"layout title name\"\n                },\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]`\n            [question]\n            $question\n            [/question]\n\n            You generated this query given in `[query][/query]`\n            [query]\n            {query_generated}\n            [/query]\n\n            But upon execution you encountered some error , error traceback is given in [query_error][/query_error]\n            [query_error]\n            {exception_log}\n            [/query_error]\n\n            Follow these steps to generate the query\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Use survey answers if available and include it in query for filtering values\n            4. Do only the task asked, Don't hallucinate and overdo the task\n            5. Strictly return all the fields in the schema during listing operations\n            6. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            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\n            8. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"postgresql query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"value_field\": \"fields in which values are stored\",\n                    \"x-axis\": \"field that can be used as x axis\",\n                    \"y-axis\": \"field that can be used as y axis\",\n                    \"title\": \"layout title name\"\n                },\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n            }\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/postgresql/formatter.py",
    "content": "from typing import Any\nfrom loguru import logger\n\n\nclass Formatter:\n    def format(self, data: Any,input) -> (dict):\n        \"\"\"\n        Main entry point for formatting the data based on the input parameters.\n        Handles different formatting strategies based on operation kind.\n\n        :param data: The data to format.\n        :param input_params: Dictionary containing operation and formatting details.\n        :return: A dictionary containing the formatted response.\n        \"\"\"\n        response = {}\n        self.main_entity = input.get(\"main_entity\")\n        self.kind = input.get(\"operation_kind\", \"\").lower()\n        self.general_message = input.get(\"general_message\")\n        self.empty_message = input.get(\"empty_message\")\n\n        logger.info(\"Formatting output using inference for postgresql\")\n\n        if self.kind  == \"list\":\n            response = self.basic_formatter(data, input)\n        elif self.kind == \"aggregation\":\n            response = self.aggregation_formatter(data, input)\n        else:\n            response[\"data\"] = data\n            response[\"kind\"] = \"list\"\n\n\n        response.update({\n            \"main_entity\": self.main_entity,\n            \"main_format\": self.kind,\n            \"role\": \"assistant\",\n            \"content\": self.general_message,\n            \"empty_message\": self.empty_message,\n        })\n\n        return response\n\n    def basic_formatter(self, data: Any, input:Any) -> dict :\n        \"\"\"\n        Formats data as a list, handling cases for none, single, and multiple entries.\n\n        :param data: The data to format.\n        :return: A dictionary containing the formatted list response.\n        \"\"\"\n        logger.info(\"Formatting data as a list\")\n\n        if data is None:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"single\"}\n        else:\n            response = {\"data\": data, \"kind\": \"list\"}\n\n        return response\n\n\n    def aggregation_formatter(self, data:Any, input:Any) -> dict :\n        \"\"\"\n        Formats data for aggregation visualisation, supporting table and chart formats.\n\n        :param data: The data to format.\n        :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type).\n        :return: A dictionary containing the formatted aggregation response.\n        \"\"\"\n\n        logger.info(\"Formatting data as aggregation\")\n\n        visualisation = input.get(\"visualisation\", {})\n        response = {}\n\n\n        if data is None or len(data) == 0:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"table\"}\n        else:\n            value_fields = visualisation.get(\"y-axis\", [])\n            key_fields = visualisation.get(\"x-axis\", [])\n            title = visualisation.get(\"title\", \"\")\n\n            visualisaton_kind = visualisation[\"type\"].replace(\" \", \"_\") if visualisation[\"type\"] is not None else \"table\"\n\n            if visualisaton_kind.lower() in [\"bar_chart\", \"line_chart\", \"pie_chart\"] and len(value_fields) > 0 and len(key_fields) > 0:\n                response[\"kind\"] = visualisaton_kind\n                response[\"data\"] = data\n                response[\"x\"] = key_fields\n                response[\"y\"] = value_fields\n                response[\"title\"] = title\n            else:\n                response = {\"kind\": \"table\", \"data\": data}\n\n        return response\n\n\n\n\n"
  },
  {
    "path": "app/plugins/postgresql/handler.py",
    "content": "import psycopg2\nfrom psycopg2 import sql, extras\nfrom loguru import logger\nimport sqlvalidator\nimport sqlparse\nfrom .formatter import Formatter\nimport uuid\n\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.query_plugin import QueryPlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\n\n\nclass Postresql(Formatter, BasePlugin, QueryPlugin,  PluginMetadataMixin):\n\n    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\"):\n        logger.info(\"Initializing datasource\")\n        super().__init__(__name__)\n\n        self.connector_name = connector_name.replace(' ','_')\n        # common\n        self.params = {\n            'dbname': db_name,\n            'user': db_user,\n            'password': db_password,\n            'host': db_host,\n            'port': db_port,\n            'sslmode': db_sslmode\n        }\n        self.connection = None\n\n\n        # class specific\n        self.cursor = None\n        self.max_limit = 5\n\n\n    def connect(self):\n        try:\n            self.connection = psycopg2.connect(**self.params)\n            self.cursor = self.connection.cursor(cursor_factory = extras.RealDictCursor)\n            logger.info(\"Connection to PostgreSQL DB successful.\")\n            return True, None\n        except psycopg2.DatabaseError as error:\n            logger.error(f\"Error connecting to PostgreSQL DB: {error}\")\n            return False, error\n\n    def healthcheck(self):\n        try:\n            if self.connection is None or self.connection.closed:\n                logger.warning(\"Connection to PostgreSQL DB is not established.\")\n                return False, \"Connection to PostgreSQL DB is not established.\"\n\n            with self.connection.cursor() as cursor:\n                cursor.execute(\"SELECT 1;\")\n                return True, None\n        except psycopg2.DatabaseError as error:\n            return False, error\n\n\n    def configure_datasource(self, init_config):\n        logger.info(\"Configuring datasource\")\n        if init_config is not None and \"script\" in init_config:\n            try:\n                self.cursor.execute(init_config[\"script\"])\n                self.connection.commit()\n            except Exception as e:\n                return e\n\n        return None\n\n    def fetch_data(self, query, params=None):\n        try:\n            self.cursor.execute(query, params)\n            if \"limit\"  not in query.lower():\n                return self.cursor.fetchmany(self.max_limit), None\n            else:\n                return self.cursor.fetchall(), None\n        except Exception as e:\n            logger.critical(e)\n            self.connection.rollback()\n            return None, e\n\n    def fetch_schema_details(self):\n        #Creating ddl from table schema\n        table_metadata = []\n        schema_ddl = []\n\n        table_schemas=self._fetch_table_schema()\n\n        if len(table_schemas) != 0 :\n\n            for table, columns in table_schemas.items():\n                table_ddl = \"\"\n\n                schema = {\n                    \"table_id\": str(uuid.uuid4()),\n                    \"table_name\": table,\n                    \"description\": \"\",\n                    \"columns\": []\n                }\n\n                fields= []\n\n\n                table_ddl = f\"\\n\\nCREATE TABLE {table}\"\n                # logger.info(f\"columns:{columns}\")\n                for column in columns:\n                    fields.append({\n                        \"column_id\" : str(uuid.uuid4()),\n                        \"column_name\": column['column_name'],\n                        \"column_type\": column['data_type'],\n                        \"description\": \"\",\n                    })\n                    table_ddl +=f\"\\n{column['column_name']} {column['data_type']} {column['character_maximum_length']},\"\n                table_ddl +=f\");\"\n\n                schema[\"columns\"] = fields\n                table_metadata.append(schema)\n                schema_ddl.append(table_ddl)\n\n        return schema_ddl, table_metadata\n\n    def create_ddl_from_metadata(self,table_metadata):\n        schema_ddl = []\n        for table in table_metadata:\n            tmp = f\"\\n\\nCREATE TABLE {table['table_name']}\"\n            for field in table[\"columns\"]:\n                tmp = f\"{tmp} {field.get('column_name','')} \\n\"\n            schema_ddl.append(tmp)\n        return schema_ddl\n\n    def select_all_from_table(self, table_name):\n        query = sql.SQL(\"SELECT * FROM {}\").format(sql.Identifier(table_name))\n        return self.fetch_data(query)\n\n    def _fetch_table_schema(self):\n        # Execute query to get all table names in the public schema\n        self.cursor.execute(\"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\")\n        # Fetch all table names\n        table_names = self.cursor.fetchall()\n\n        table_schemas = {}\n\n        for table in table_names:\n\n            # logger.info(f\"table_name:{table['table_name']}\")\n            self.cursor.execute(f\"SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = '{table['table_name']}'\")\n            columns = self.cursor.fetchall()\n\n\n            table_schemas[table['table_name']] = columns\n        return table_schemas\n\n    def fetch_feedback(self):\n        sql_query = \"SELECT chat_query, feedback_json FROM public.chat_histories WHERE feedback_status = 2 AND created_at >= CURRENT_DATE - INTERVAL '7 days';\"\n        result = self.fetch_data(sql_query)\n        logger.info(result)\n        return result\n\n    def validate(self,formated_sql):\n        #validate sql using SQLParser\n        queries = sqlparse.split(formated_sql)\n        query = queries[0]\n        formated_query = sqlparse.format(query, reindent=True, keyword_case='upper')\n\n        parsed = sqlparse.parse(formated_query)[0]\n\n        if parsed.get_type() != 'SELECT':\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        token_names = [p._get_repr_name() for p in parsed.tokens]\n        if \"DDL\" in token_names:\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        sql_query = sqlvalidator.parse(formated_sql)\n        if not sql_query.is_valid():\n            logger.info(sql_query.is_valid())\n            return \"I didn't get you, Please reframe your question\"\n\n        return  None\n\n    def close_connection(self):\n        self.cursor.close()\n        self.connection.close()\n\n\n"
  },
  {
    "path": "app/plugins/sqlite/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'sqlite'\n__display_name__ = \"SQLite DB\"\n__description__ = 'SQLite integration for handling SQLite database operations.'\n__icon__ = '/assets/plugins/logos/sqlite.svg'\n__category__ = 2\n\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    db_name = ConnectionArgument(\n        type = 1,\n        generic_name= 'Sqlite Database Name',\n        description = 'Database name',\n        order= 1,\n        required = True,\n        value = None,\n        slug = \"db_name\"\n    ),\n)\n\n# Prompt\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n            \"template\": \"\"\"\n            You are an Sqlite expert. Your job is to answer questions about a Sqlite database using only the provided schema details and rules.\n\n            go through the schema details given below\n            -- start db schema section--\n            {schema}\n            -- end db schema section--\n\n            A brief description about the schema is given below\n\n            -- start db context section--\n            {context}\n            -- end db context section--\n\n            Sample sql queries with their questions are given below\n\n            -- start query samples section--\n            $suggestions\n            -- end query samples section--\n\n            Adhere to the given rules without failure\n\n            -- start rules section --\n            - Use Table Aliases always to prevent ambiguity . For example, `SELECT table1.col1, table2.col1 FROM table1 JOIN table2 ON table1.id = table2.id`.\n            - use LIKE operator with LOWER function for string comparison or equality\n            - Always use alias/table name for fields in WHERE condition\n            - Do not use non existing tables or fields\n            - id columns are mandatory for all operations\n            - Do not use JSON_BUILD_OBJECT operation\n            - Do not use unwanted joins\n            - Do not return incomplete queries\n            - Adher to sqlite query syntax\n            -- end rules section --\n            \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            Follow these steps to generate query to solve the question `$question`\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Do only the task asked, Don't hallucinate and overdo the task\n            4. Strictly return all the fields in the schema during listing operations\n            5. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            6. Generate a query to solve the problem using the schema, context, and strictly follow the rules\n            7. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"sqlite query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"x-axis\": [\"fields that can be used as x axis\"],\n                    \"y-axis\": [\"fields that can be used as y axis\"],\n                    \"title\": \"layout title name\"\n                },\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            You were trying to answer the following user question by writing SQL query to answer the question given in `[question][/question]`\n            [question]\n            $question\n            [/question]\n\n            You generated this query given in `[query][/query]`\n            [query]\n            {query_generated}\n            [/query]\n\n            But upon execution you encountered some error , error traceback is given in [query_error][/query_error]\n            [query_error]\n            {exception_log}\n            [/query_error]\n\n            Follow these steps to generate the query\n\n            1. Deliberately go through schema, context, rules deliberately\n            2. Understand the question and check whether it's doable with the given context\n            3. Use survey answers if available and include it in query for filtering values\n            4. Do only the task asked, Don't hallucinate and overdo the task\n            5. Strictly return all the fields in the schema during listing operations\n            6. Strictly return at least 1 text fields and an id field during aggregation/group by operations\n            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\n            8. output in the given json format, extra explanation is strictly prohibited\n\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"query\" : \"sqlite query\",\n                \"operation_kind\" : \"aggregation|list\",\n                \"visualisation\": {\n                    \"type\": \"chart type (bar chart, line chart, pie chart) or 'table' for tabular format; 'none' if operation_kind is 'list'\",\n                    \"value_field\": \"fields in which values are stored\",\n                    \"x-axis\": \"field that can be used as x axis\",\n                    \"y-axis\": \"field that can be used as y axis\",\n                    \"title\": \"layout title name\"\n                },\n                \"schema\": \"used schema details separated by comma\",\n                \"confidence\" : \"confidence in 100\",\n                \"general_message\": \"a general message describing the answers like 'here is your list of incidents' or 'look what i found'\",\n                \"main_entity\" : \"main entity  for the query\",\n                \"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]\n            }\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/sqlite/formatter.py",
    "content": "from typing import Any\nfrom loguru import logger\n\n\nclass Formatter:\n    def format(self, data: Any,input) -> (dict):\n        \"\"\"\n        Main entry point for formatting the data based on the input parameters.\n        Handles different formatting strategies based on operation kind.\n\n        :param data: The data to format.\n        :param input_params: Dictionary containing operation and formatting details.\n        :return: A dictionary containing the formatted response.\n        \"\"\"\n        response = {}\n        self.main_entity = input.get(\"main_entity\")\n        self.kind = input.get(\"operation_kind\", \"\").lower()\n        self.general_message = input.get(\"general_message\")\n        self.empty_message = input.get(\"empty_message\")\n\n        logger.info(\"Formatting output using inference for sqlite\")\n\n        if self.kind  == \"list\":\n            response = self.basic_formatter(data, input)\n        elif self.kind == \"aggregation\":\n            response = self.aggregation_formatter(data, input)\n        else:\n            response[\"data\"] = data\n            response[\"kind\"] = \"list\"\n\n\n        response.update({\n            \"main_entity\": self.main_entity,\n            \"main_format\": self.kind,\n            \"role\": \"assistant\",\n            \"content\": self.general_message,\n            \"empty_message\": self.empty_message,\n        })\n\n        return response\n\n    def basic_formatter(self, data: Any, input:Any) -> dict :\n        \"\"\"\n        Formats data as a list, handling cases for none, single, and multiple entries.\n\n        :param data: The data to format.\n        :return: A dictionary containing the formatted list response.\n        \"\"\"\n        logger.info(\"Formatting data as a list\")\n\n        if data is None:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"single\"}\n        else:\n            response = {\"data\": data, \"kind\": \"list\"}\n\n        return response\n\n\n    def aggregation_formatter(self, data:Any, input:Any) -> dict :\n        \"\"\"\n        Formats data for aggregation visualisation, supporting table and chart formats.\n\n        :param data: The data to format.\n        :param visualisation: Dictionary containing visualisation details (e.g., x-axis, y-axis, chart type).\n        :return: A dictionary containing the formatted aggregation response.\n        \"\"\"\n\n        logger.info(\"Formatting data as aggregation\")\n\n        visualisation = input.get(\"visualisation\", {})\n        response = {}\n\n\n        if data is None or len(data) == 0:\n            response = {\"data\": [], \"kind\": \"none\"}\n        elif len(data) == 1:\n            response = {\"data\": data, \"kind\": \"table\"}\n        else:\n            value_fields = visualisation.get(\"y-axis\", [])\n            key_fields = visualisation.get(\"x-axis\", [])\n            title = visualisation.get(\"title\", \"\")\n\n            visualisaton_kind = visualisation[\"type\"].replace(\" \", \"_\") if visualisation[\"type\"] is not None else \"table\"\n\n            if visualisaton_kind.lower() in [\"bar_chart\", \"line_chart\", \"pie_chart\"] and len(value_fields) > 0 and len(key_fields) > 0:\n                response[\"kind\"] = visualisaton_kind\n                response[\"data\"] = data\n                response[\"x\"] = key_fields\n                response[\"y\"] = value_fields\n                response[\"title\"] = title\n            else:\n                response = {\"kind\": \"table\", \"data\": data}\n\n        return response\n"
  },
  {
    "path": "app/plugins/sqlite/handler.py",
    "content": "import sqlite3\nimport pathlib\nimport urllib\nfrom loguru import logger\nimport sqlvalidator\nimport sqlparse\nfrom .formatter import Formatter\nimport uuid\n\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.query_plugin import QueryPlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\n\nclass Sqlite(Formatter, BasePlugin, QueryPlugin, PluginMetadataMixin):\n    def __init__(self, connector_name : str, db_name:str, db_parent_path:str=''):\n        logger.info(\"Initializing datasource\")\n        super().__init__(__name__)\n\n        self.connector_name = connector_name.replace(' ','_')\n        self.params = {\n            'db_name': db_name,\n            'db_parent_path': db_parent_path,\n        }\n        self.connection = None\n\n        # class specific\n        self.cursor = None\n        self.max_limit = 5\n\n    def _dict_factory(self, cursor, row):\n        d = {}\n        for idx, col in enumerate(cursor.description):\n            d[col[0]] = row[idx]\n        return d\n    \n    def _path_to_uri(self, path):\n        path = pathlib.Path(path)\n        if path.is_absolute():\n            return path.as_uri()\n        return 'file:' + urllib.parse.quote(path.as_posix(), safe=':/')\n\n    def connect(self):\n        try:\n            db_path = pathlib.Path(self.params['db_parent_path']).joinpath(self.params['db_name']).as_posix()\n            uri_filename = f\"{self._path_to_uri(db_path)}?mode=rw\"            \n            self.connection = sqlite3.connect(uri_filename, uri=True, check_same_thread=False, timeout= 8.0)\n            self.connection.row_factory = self._dict_factory\n            self.cursor = self.connection.cursor()\n            \n            logger.info(\"Connection to SQLite DB successful.\")\n            return True, None\n        except sqlite3.Error as error:\n            logger.error(f\"Error connecting to SQLite DB: {error}\")\n            return False, error\n\n    def healthcheck(self):\n        try:\n            if self.connection is None:\n                logger.warning(\"Connection to SQLite DB is not established.\")\n                return False, \"Connection to SQLite DB is not established.\"\n\n            self.cursor.execute(\"SELECT 1;\")\n            return True, None        \n        except sqlite3.Error as error:\n            return False, error\n\n    def configure_datasource(self, init_config):\n        logger.info(\"Configuring datasource\")\n        if init_config is not None and \"script\" in init_config:\n            try:\n                self.cursor.execute(init_config[\"script\"])\n                self.connection.commit()\n            except Exception as e:\n                return e\n\n        return None\n\n    def fetch_data(self, query, params=None):\n        try:\n            params = {} if params is None else params\n            self.cursor.execute(query, params)\n            if \"limit\"  not in query.lower():\n                return self.cursor.fetchmany(self.max_limit), None\n            else:\n                return self.cursor.fetchall(), None\n        except Exception as e:\n            logger.critical(e)\n            self.connection.rollback()\n            return None, e\n\n    def fetch_schema_details(self):\n        #Creating ddl from table schema\n        table_metadata = []\n        schema_ddl = []\n\n        table_schemas=self._fetch_table_schema()\n\n        if len(table_schemas) != 0 :\n\n            for table, columns in table_schemas.items():\n                table_ddl = \"\"\n\n                schema = {\n                    \"table_id\": str(uuid.uuid4()),\n                    \"table_name\": table,\n                    \"description\": \"\",\n                    \"columns\": []\n                }\n\n                fields= []\n\n\n                table_ddl = f\"\\n\\nCREATE TABLE {table} (\"\n                # logger.info(f\"columns:{columns}\")\n                for column in columns:\n                    fields.append({\n                        \"column_id\" : str(uuid.uuid4()),\n                        \"column_name\": column['name'],\n                        \"column_type\": column['type'],\n                        \"description\": \"\",\n                    })\n                    table_ddl +=f\"\\n{column['name']} {column['type']} ,\"\n                table_ddl +=f\");\"\n\n                schema[\"columns\"] = fields\n                table_metadata.append(schema)\n                schema_ddl.append(table_ddl)\n\n        return schema_ddl, table_metadata\n\n    def create_ddl_from_metadata(self,table_metadata):\n        schema_ddl = []\n        for table in table_metadata:\n            tmp = f\"\\n\\nCREATE TABLE {table['table_name']}\"\n            for field in table[\"columns\"]:\n                tmp = f\"{tmp} {field.get('column_name','')} \\n\"\n            schema_ddl.append(tmp)\n        return schema_ddl\n\n    def _fetch_table_schema(self):\n        # Execute query to get all table names \n        self.cursor.execute(\"SELECT name FROM sqlite_master\")\n        # Fetch all table names\n        table_names = self.cursor.fetchall()\n\n        table_schemas = {}\n\n        for table in table_names:\n\n            # logger.info(f\"table_name:{table['name']}\")\n            self.cursor.execute(f\"SELECT name, type FROM pragma_table_info('{table['name']}')\")\n            columns = self.cursor.fetchall()\n\n\n            table_schemas[table['name']] = columns\n        return table_schemas\n\n    def fetch_feedback(self):\n        pass\n\n    def validate(self,formated_sql):\n        #validate sql using SQLParser\n        queries = sqlparse.split(formated_sql)\n        query = queries[0]\n        formated_query = sqlparse.format(query, reindent=True, keyword_case='upper')\n\n        parsed = sqlparse.parse(formated_query)[0]\n\n        if parsed.get_type() != 'SELECT':\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        token_names = [p._get_repr_name() for p in parsed.tokens]\n        if \"DDL\" in token_names:\n            return \"Sorry, I am not designed for data manipulation operations\"\n\n        sql_query = sqlvalidator.parse(formated_sql)\n        if not sql_query.is_valid():\n            logger.info(sql_query.is_valid())\n            return \"I didn't get you, Please reframe your question\"\n\n        return  None\n\n    def close_conection(self):\n        self.cursor.close()\n        self.connection.close()\n"
  },
  {
    "path": "app/plugins/website/__init__.py",
    "content": "from app.models.prompt import Prompt\nfrom collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__plugin_name__ = 'website'\n__display_name__ = 'Website Loader'\n__description__ = 'Website integration for handling website data'\n__icon__ = '/assets/plugins/logos/website.svg'\n__category__ = 1\n\n\n# Connection arguments\n__connection_args__ = OrderedDict(\n    website_url= ConnectionArgument(\n        type = 4,\n        generic_name= 'Website URL',\n        description = 'URL of website',\n        order = 1,\n        required = True,\n        value = None,\n        slug = \"website_url\"\n    ),\n    headers=ConnectionArgument(\n        type= 7,\n        generic_name= 'Headers to be used',\n        description= 'Provide required headers',\n        order= 2,\n        required = False,\n        value = {},\n        slug = \"headers\"\n    ),\n    depth=ConnectionArgument(\n        type= 3,\n        generic_name= 'Depth of scanning',\n        description= 'Choose the depth of scanning for child URLs. Set to 0 to scan all',\n        order= 3,\n        required = True,\n        value=1,\n        slug = \"depth\"\n    )\n)\n\n# Prompt\n__prompt__ = Prompt(**{\n        \"base_prompt\": \"{system_prompt}{user_prompt}\",\n        \"system_prompt\": {\n            \"template\": \"\"\"\n            You are an Chatbot designed to answer user questions based only on the context given to you.\n            Use the details enclosed in `[context][/context]` to generate answer\n\n            [context]\n            {context}\n            [/context]\n\n            Adhere to these rules while generating query:\n            - Deliberately go through the question and context word by word to appropriately answer the question\n            \"\"\"\n        },\n        \"user_prompt\":{\n            \"template\": \"\"\"\n            User question is \"$question\"\n            generate a json in the following format without any formatting.\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"operation_kind\" : \"none\",\n                \"general_message\": \"Answer to user question in human readable Markdown format based on the context\",\n                \"confidence\" : \"confidence in 100\",\n                \"main_entity\": \"document\"\n            }\n            \"\"\"\n        },\n        \"regeneration_prompt\": {\n            \"template\": \"\"\"\n            User question is \"$question\"\n            generate a json in the following format without any formatting.\n            {\n                \"explanation\": \"Explain how you finalized the sql query using the schemas and rules provided\",\n                \"operation_kind\" : \"none\",\n                \"general_message\": \"Answer to user question in human readable Markdown format based on the context\",\n                \"confidence\" : \"confidence in 100\",\n                \"main_entity\": \"document\"\n            }\n            \"\"\"\n        }\n    })\n\n\n\n__all__ = [\n    __version__, __plugin_name__, __display_name__ , __description__, __icon__, __category__, __prompt__\n]"
  },
  {
    "path": "app/plugins/website/formatter.py",
    "content": "from typing import Any, Dict\nfrom loguru import logger\n\nclass Formatter:\n    \"\"\"\n    Formatter class to format the response based on the inference and data.\n    \"\"\"\n\n\n    def format(self, data: Dict[str, Any], inference: Dict[str, Any]) -> dict:\n        \"\"\"\n        Format the response using the given data and inference information.\n\n        :param data: The data containing records to process.\n        :param inference: Inference details including main entity and operation kind.\n        :return: Formatted response dictionary.\n        \"\"\"\n\n        logger.info(\"Processing output using inference details\")\n\n        response = {}\n        self.main_entity = inference.get(\"main_entity\", \"\")\n        self.kind = inference.get(\"operation_kind\", \"\")\n        self.general_message = inference.get(\"general_message\", \"Unable to process question, try again\")\n\n        response[\"content\"] = self.general_message\n\n        response[\"main_entity\"] = self.main_entity\n        response[\"main_format\"] = self.kind\n        response[\"role\"] = \"assistant\"\n        return response\n\n"
  },
  {
    "path": "app/plugins/website/handler.py",
    "content": "from .formatter import Formatter\nfrom loguru import logger\nimport requests\nimport json\nfrom app.base.base_plugin import BasePlugin\nfrom app.base.remote_data_plugin import RemoteDataPlugin\nfrom app.base.plugin_metadata_mixin import PluginMetadataMixin\nfrom typing import  Tuple, Optional\nfrom app.readers.base_reader import BaseReader\n\n\nclass Website(BasePlugin, PluginMetadataMixin,RemoteDataPlugin,  Formatter):\n    \"\"\"\n    Website class for interacting with website data.\n    \"\"\"\n\n    def __init__(self, connector_name : str, website_url:str, depth : int = 1, headers: str = \"{}\"):\n        super().__init__(__name__)\n\n        self.connection = {}\n\n        self.connector_name = connector_name.replace(' ','_')\n        self.params = {\n            'url': website_url,\n            \"depth\":  depth,\n            \"headers\": headers,\n        }\n\n\n    def connect(self):\n        \"\"\"\n        Mocked connection method for Website.\n\n        :return: Tuple containing connection status (True/False) and an error message if any.\n        \"\"\"\n        return True, None\n\n\n    def healthcheck(self)-> Tuple[bool, Optional[str]]:\n        \"\"\"\n        Perform a health check by checking if the Website  is accessible.\n\n        :return: Tuple containing the health status (True/False) and error message (if any).\n        \"\"\"\n        logger.info(\"health check for website\")\n\n        url = self.params[\"url\"]\n\n        headers = {}\n        try:\n            headers = json.loads(self.params.get(\"headers\", \"{}\"))\n        except Exception as e:\n            return False, str(\"Provide valid json for headers\")\n\n        try:\n            response = requests.get(url,headers=headers)\n            if response.status_code == 200:\n                logger.info(\"Website health check passed.\")\n                return True, None\n            else:\n                logger.error(f\"Health check failed: {response.status_code} {response.text}\")\n                return False, \"Failed to connect with airtable\"\n        except Exception as e:\n            logger.exception(f\"Exception during health check: {str(e)}\")\n            return False, str(e)\n\n\n    def fetch_data(self, params=None):\n\n        headers = {}\n        try:\n            headers = json.loads(self.params.get(\"headers\", \"{}\"))\n        except Exception as e:\n            logger.exception(e)\n\n        base_reader = BaseReader({\n                                \"type\": \"url\",\n                                \"path\": [self.params.get('url')],\n                                \"depth\": int(self.params.get(\"depth\", 1)),\n                                \"headers\": headers,\n                            })\n        data = base_reader.load_data()\n        return data"
  },
  {
    "path": "app/providers/cache_manager.py",
    "content": "from collections import OrderedDict\nfrom app.providers.config import configs\n\nclass CacheManager(object):\n    _instance = None\n    _cache_store = OrderedDict()\n    _cache_limit = configs.config_cache_limit\n \n    def __init__(self):\n        raise RuntimeError(\"Call get_instance() instead\")\n \n    @classmethod\n    def get_instance(cls):\n        if cls._instance is None:\n            cls._instance = cls.__new__(cls)\n        return cls._instance\n \n    def set(self, key, value):\n        if key in self._cache_store:\n            self._cache_store.move_to_end(key)\n        elif len(self._cache_store) >= self._cache_limit:\n            self._cache_store.popitem(last=False)\n            \n        self._cache_store[key] = value\n \n    def get(self, key):\n        return self._cache_store.get(key)\n \n    def clear(self, key):\n        if key in self._cache_store:\n            del self._cache_store[key]\n \ncache_manager = CacheManager.get_instance()\n"
  },
  {
    "path": "app/providers/clustering.py",
    "content": "import random\n\n\nclass Clustering:\n\n    def _initialize_centroids(self,data, k):\n        return random.sample(data, k)\n\n    def _assign_clusters(self, data, centroids):\n        clusters = []\n        for point in data:\n            distances = [abs(point - centroid) for centroid in centroids]\n            clusters.append(distances.index(min(distances)))\n        return clusters\n\n    def _recalculate_centroids(self, data, clusters, k):\n        new_centroids = []\n        for i in range(k):\n            cluster_points = [data[j] for j in range(len(data)) if clusters[j] == i]\n            if cluster_points:\n                new_centroids.append(sum(cluster_points) / len(cluster_points))\n            else:\n                new_centroids.append(random.choice(data))\n        return new_centroids\n\n    def _get_clustered_values(self, data, clusters, k):\n        clustered_values = [[] for _ in range(k)]\n        for i, point in enumerate(data):\n            clustered_values[clusters[i]].append(point)\n        return clustered_values\n\n    def kmeans(self, data, k, max_iterations=100):\n        if len(data) > 1:\n            centroids = self._initialize_centroids(data, k)\n            for _ in range(max_iterations):\n                clusters = self._assign_clusters(data, centroids)\n                new_centroids = self._recalculate_centroids(data, clusters, k)\n                if new_centroids == centroids:\n                    break\n                centroids = new_centroids\n            clustered_values = self._get_clustered_values(data, clusters, k)\n\n\n            # Sort clusters based on their minimum value\n            clustered_values.sort(key=lambda cluster: (cluster[0] if cluster else float('inf')))\n\n            return clustered_values\n        else:\n            return [data]"
  },
  {
    "path": "app/providers/config.py",
    "content": "import os\nfrom typing import List\n\nfrom dotenv import load_dotenv\nfrom pydantic_settings import BaseSettings\n\n\nload_dotenv()\n\nclass Configs(BaseSettings):\n    # base\n    ENV: str = os.getenv(\"ENV\", \"dev\")\n    API: str = \"/api\"\n    PROJECT_NAME: str = \"raggenie\"\n\n    DATABASE_URL: str = \"sqlite:///raggenie.db\"\n\n    PROJECT_ROOT: str = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))\n\n    # CORS\n    BACKEND_CORS_ORIGINS: List[str] = [\"*\"]\n\n    # database\n    logging_enabled: bool = os.getenv(\"ENABLE_FILE_LOGGING\", False)\n    inference_llm_model:str = os.getenv(\"INFERENCE_LLM_MODEL\", \"gpt\")\n\n    # Auth\n    auth_enabled: bool = os.getenv(\"AUTH_ENABLED\",False)\n    default_username: str = os.getenv(\"DEFAULT_USERNAME\", \"Admin\")\n    \n    client_private_key_file_path: str = os.getenv(\"CLIENT_PRIVATE_KEY_FILE_PATH\", \"app/providers/client-key-file.json\")\n    zitadel_token_url: str = os.getenv(\"ZITADEL_TOKEN_URL\", \"http://localhost:8080/oauth/v2/token\")\n    zitadel_domain: str = os.getenv(\"ZITADEL_DOMAIN\", \"http://localhost:8080\")\n    retry_limit:int = os.getenv(\"RETRY_LIMIT\",0)\n    application_port: int = os.getenv(\"APP_PORT\", 8001)\n    application_server: str = os.getenv(\"APP_SERVER\", \"http://localhost:8001\")\n    \n    # Cache\n    config_cache_limit: int = os.getenv(\"CONFIG_CACHE_LIMIT\", 10)\n\n\nconfigs = Configs()\n"
  },
  {
    "path": "app/providers/container.py",
    "content": "from dependency_injector import containers, providers\nfrom app.plugins.loader import DSLoader\nfrom app.providers.clustering import Clustering\nfrom app.vectordb.loader import VectorDBLoader\n\n\n\n\n\nclass Container(containers.DeclarativeContainer):\n    config = providers.Configuration()\n\n    datasources = providers.Callable(lambda config: {ds['name']: DSLoader(\n            ds\n        ).load_ds() for ds in config[\"datasources\"]} if config and config.get(\"datasources\") else None, config)\n    vectorstore = providers.Singleton(VectorDBLoader, config = config.vector_db)\n    clustering = providers.Singleton(Clustering)\n\n\n"
  },
  {
    "path": "app/providers/context_storage.py",
    "content": "from app.models.db import Base\nfrom app.utils.database import get_db\nfrom fastapi import Depends\nfrom sqlalchemy.orm import Session\n\n\nclass ContextStorage:\n    def __init__(self,db: Session=Depends(get_db)):\n        self.session = db\n        self.engine = self.session.get_bind()\n\n\n    def create_table(self):\n        Base.metadata.create_all(self.engine)\n\n    def insert_data(self, data):\n        self.session.add(data)\n        self.session.commit()\n\n    def update_data(self, model, filters, updates):\n        self.session.query(model).filter_by(**filters).update(updates)\n        self.session.commit()\n\n    def query_data(self, model,  filters=None, limit=None):\n        query = self.session.query(model)\n        if filters:\n            query = query.filter_by(**filters)\n\n\n        if limit:\n            query = query.limit(limit)\n\n        results = query.all()\n        return results"
  },
  {
    "path": "app/providers/data_preperation.py",
    "content": "from loguru import logger\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\n\nclass SourceDocuments:\n    def __init__(self,schema_details, schema_configs, documentation):\n        self.documentation = []\n        logger.info(\"Fetching schema details\")\n        self.schema_details = schema_details\n        self.schema_configs = schema_configs\n\n        self.documentation.extend(documentation)\n\n        for schema_config in schema_configs:\n            table_doc = ''\n            table_doc = f\"Table Name: {schema_config['table_name']} - {schema_config['description']}\\n column are given below\\n\"\n            for column in schema_config['columns']:\n                table_doc = f\"{table_doc} {column.get('column_name','')} - {column['description']}\\n\"\n            self.documentation.append({'content': table_doc, 'metadata': {}})\n\n\n\n    def get_source_documents(self):\n        chunked_docs = []\n        chunked_schema = []\n\n        try:\n\n            text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=20,separators=[\"\\n\\n\",\"\\'\\\")\"])\n            text_splitter_doc = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=20,separators=[\"##\"])\n\n            splitted_schema = list(map(lambda item: f\"'{item}'\", self.schema_details))\n            load_schema = text_splitter.create_documents(splitted_schema)\n\n\n\n            for docs in self.documentation:\n                temp_docs = text_splitter_doc.create_documents([str(docs[\"content\"])])\n                chunks = text_splitter_doc.split_documents(temp_docs)\n                for chunk in chunks:\n                    chunk.metadata = docs[\"metadata\"] if \"metadata\" in docs else {}\n                chunked_docs.extend(chunks)\n\n            chunked_schema = text_splitter.split_documents(load_schema)\n        except Exception as e:\n            logger.critical(e)\n\n        return chunked_docs, chunked_schema\n"
  },
  {
    "path": "app/providers/middleware.py",
    "content": "from datetime import datetime, timezone\nimport json\nfrom app.providers.zitadel import Zitadel\nimport requests\nfrom app.utils.jwt import JWTUtils\nfrom app.providers.config import configs\nfrom fastapi import Request, status, HTTPException, Cookie\nfrom fastapi import Request, HTTPException, status\nfrom typing import Optional\n\n\nasync def verify_token(request: Request, session_data: Optional[str] = Cookie(None)):\n\n    if configs.auth_enabled:\n        zitadel = Zitadel()\n\n        try:\n            session_data = json.loads(session_data)  # This handles None and invalid JSON\n            session_id = session_data.get(\"session_id\")\n            session_token = session_data.get(\"session_token\")\n            user_id = session_data.get(\"user_id\")\n\n\n            \n            if not session_id or not session_token:\n                raise ValueError(\"missing session data\")\n            response = zitadel.get_user_info(session_id)\n            session_expiry = response.get(\"session\").get(\"expirationDate\")\n            session_expiry_utc = datetime.fromisoformat(session_expiry.rstrip(\"Z\")).replace(tzinfo=timezone.utc)\n            now_utc = datetime.now(timezone.utc)\n            if (session_expiry_utc - now_utc).total_seconds() < 300:\n                zitadel.refresh_session(session_id)\n            \n        except (TypeError, json.JSONDecodeError, AttributeError, ValueError):\n            raise HTTPException(\n                status_code=status.HTTP_401_UNAUTHORIZED,\n                detail=\"Invalid or missing session data\"\n            )\n        \n        except requests.exceptions.RequestException as e:  # Handles request errors (e.g., network issues, 404)\n            raise HTTPException(\n                status_code=status.HTTP_401_UNAUTHORIZED,\n                detail=f\"Session validation failed: {str(e)}\",\n            )\n        return {\"session_id\": session_id, \"user_id\": user_id}\n    else:\n        return {\"session_id\": '1', \"user_id\": '1', \"username\": configs.default_username}\n\n"
  },
  {
    "path": "app/providers/reranker.py",
    "content": "\n\n\nfrom sentence_transformers import CrossEncoder\n\n\n\nclass Reranker:\n\n    def __init__(self,model_name):\n        self.cross_encoder = CrossEncoder(model_name)\n\n\n    def predict(self,pairs):\n        return self.cross_encoder.predict(pairs)"
  },
  {
    "path": "app/providers/zitadel.py",
    "content": "import json\nimport requests\nimport time\nfrom app.providers.config import configs\nfrom app.schemas.common import CommonResponse\nfrom fastapi.responses import JSONResponse, RedirectResponse\nfrom jwt import encode\n\n\nclass Zitadel:\n    \n    def __init__(self):\n        self.base_url = configs.zitadel_domain\n        with open(configs.client_private_key_file_path, \"r\") as f:\n            json_data = json.load(f)\n        self.private_key = json_data[\"key\"]\n        self.kid = json_data[\"keyId\"]\n        self.user_id = json_data[\"userId\"]\n        self.token = None  # Will store the access token\n        self.token_expiry = 0  # Timestamp when token expires\n        self._refresh_token()  # Generate initial token\n        self.headers = {\n            \"Authorization\": f\"Bearer {self.token}\",\n            \"Content-Type\": \"application/json\",\n        }\n        \n        \n    def _generate_jwt(self):\n        \"\"\"Generate a signed JWT.\"\"\"\n        header = {\"alg\": \"RS256\", \"kid\": self.kid}\n        payload = {\n            \"iss\": self.user_id,\n            \"sub\": self.user_id,\n            \"aud\": configs.zitadel_domain,\n            \"iat\": int(time.time()),\n            \"exp\": int(time.time()) + 3600  # 1-hour expiry\n        }\n        return encode(payload, self.private_key, algorithm=\"RS256\", headers=header)\n    \n    def _refresh_token(self):\n        \"\"\"Fetch a new OAuth access token using the JWT.\"\"\"\n        jwt_token = self._generate_jwt()\n        data = {\n            \"grant_type\": \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n            \"scope\": f\"openid email profile urn:zitadel:iam:org:project:id:zitadel:aud\",\n            \"assertion\": jwt_token\n        }\n        response = requests.post(configs.zitadel_token_url, data=data)\n        if response.status_code == 200:\n            token_data = response.json()\n            self.token = token_data[\"access_token\"]\n            self.token_expiry = int(time.time()) + 3500\n        else:\n            raise Exception(f\"Failed to fetch access token: {response.text}\")\n        \n        \n    def _ensure_valid_token(self):\n        \"\"\"Ensure the token is valid, refreshing if expired.\"\"\"\n        if time.time() >= self.token_expiry:\n            self._refresh_token()\n        self.headers[\"Authorization\"] = f\"Bearer {self.token}\"\n        \n    \n    def create_user_session(self , user_id: str, idp_intent_id: str, token: str):\n        \"\"\" create session for a user and sets the session cookie.\"\"\"\n        self._ensure_valid_token()\n        try:\n            response = requests.post(\n                f\"{self.base_url}/v2/sessions\",\n                json={\n                    \"checks\": {\n                        \"user\": {\n                            \"userId\": user_id\n                        },\n                        \"idpIntent\": {\n                            \"idpIntentId\": idp_intent_id,\n                            \"idpIntentToken\": token\n                        }\n                    },\n                    \"lifetime\": \"1800.000000000s\"\n                },\n                headers=self.headers\n            )\n            response.raise_for_status()\n            \n            session_data = response.json()\n            session_id = session_data.get(\"sessionId\")\n            session_token = session_data.get(\"sessionToken\")\n            \n            if not session_id or not session_token:\n                return JSONResponse(\n                    status_code=500,\n                    content={\"error\": \"Session ID or token not found in response\"}\n                )\n                \n            json_response = JSONResponse(\n                status_code=201,\n                content={\"message\": \"Session created successfully\", \"session_id\": session_id, \"user_id\": user_id},\n            )\n            json_response.set_cookie(\n                key=\"session_data\",\n                value=json.dumps({\"session_id\": session_id, \"session_token\": session_token, \"user_id\": user_id}),\n                httponly=True,\n                secure=False,\n                samesite=\"Lax\",\n                max_age=1800,\n                path=\"/\",\n            )\n\n            return json_response\n        \n        except requests.RequestException as e:\n            return JSONResponse(\n                status_code=500,\n                content={\n                    \"error\": \"Failed to create session\",\n                    \"details\": str(e)\n                }\n            )\n                \n    \n    def create_user(self, user_data: dict, idp_intent_id: str, token: str):\n        \"\"\" Create a user from IDP authentication data \"\"\"\n        # ONLY WORKS WITH GOOGLE IDP AUTHENTICATION DATA NOW NEED TO MAKE MODIFICATION\n        self._ensure_valid_token()      \n        idp_info = user_data.get(\"idpInformation\", {})\n        raw_info = idp_info.get(\"rawInformation\", {})\n        user_info = raw_info.get(\"User\", {})\n        \n        payload = {\n            \"username\": user_info.get(\"email\", \"\"),\n            \"profile\": {\n                \"givenName\": user_info.get(\"given_name\", \"\"),\n                \"familyName\": user_info.get(\"family_name\", \"\"),\n                \"displayName\": user_info.get(\"name\", \"\")\n            },\n            \"email\": {\n                \"email\":  user_info.get(\"email\", \"\"),\n                \"isVerified\": user_info.get(\"email_verified\", False),\n            },\n            \"idpLinks\": [\n                {\n                    \"idpId\": idp_info.get(\"idpId\"),\n                    \"userId\": idp_info.get(\"userId\"),\n                    \"userName\": user_info.get(\"name\", \"\")\n                }\n            ],\n        }\n        try:\n            response = requests.post(\n                f\"{self.base_url}/v2/users/human\", json=payload, headers=self.headers\n            )\n            response.raise_for_status()\n\n            created_user_data = response.json()\n            user_id = created_user_data.get(\"userId\")\n\n            if not user_id:\n                return JSONResponse(\n                    status_code=500, content={\"error\": \"User creation failed\"}\n                )\n                \n            return self.create_user_session(user_id, idp_intent_id, token)\n\n        except requests.RequestException as e:\n            return JSONResponse(\n                status_code=500, content={\"error\": \"Failed to create user\", \"details\": str(e)}\n            )\n    \n    def redirect_to_idp(self, idp_id: int):\n        \"\"\" Generate an authentication url for idp login and redirect user to the url \"\"\"\n        # need to set successurl and failureUrl domain dynamically *****\n        self._ensure_valid_token()\n        try:\n            response = requests.post(\n                f\"{self.base_url}/v2/idp_intents\",\n                json={\n                    \"idpId\": f\"{idp_id}\",\n                    \"urls\": {\n                        \"successUrl\": f\"{configs.application_server}/api/v1/auth/idp/success\",\n                        \"failureUrl\": f\"{configs.application_server}/ui/login\"\n                }\n                },\n                headers=self.headers\n            )\n            response.raise_for_status()\n            auth_url = response.json().get('authUrl')\n            \n            if auth_url:\n                return RedirectResponse(url=auth_url)\n            \n            return JSONResponse(status_code=400, content={\"error\": \"authUrl not found\"})\n            \n        except requests.exceptions.RequestException as e:\n            return JSONResponse(\n                status_code=500, content={\"error\": \"Failed to retrieve IDP auth URL\", \"details\": str(e)}\n            )\n    \n    def get_user_info(self, session_id: int):\n        \"\"\" get user info from the current session \"\"\"\n        # need to add error handling when there is no userinfo retreived from the \n        # session \n        self._ensure_valid_token()\n        try:\n            response = requests.get(\n                f\"{self.base_url}/v2/sessions/{session_id}\",\n                headers=self.headers\n            )\n            response.raise_for_status()\n            session_info = response.json()\n            return session_info\n        except requests.exceptions.RequestException as e:\n               return CommonResponse(\n                status=False,\n                status_code=500,\n                message=\"User info retrieval failed\",\n                data=None,\n                error=str(e),\n            )\n        \n    def get_idp_intent_data(self,idp_intent_id: int, idp_token: str):\n        self._ensure_valid_token()\n        try:\n            response = requests.post(\n                f\"{self.base_url}/v2/idp_intents/{idp_intent_id}\",\n                json={\"idpIntentToken\": idp_token},\n                headers=self.headers\n            )  \n            response.raise_for_status()\n            return response\n        \n        except requests.exceptions.RequestException as e:\n            return JSONResponse(\n                status_code=500, content={\"error\": \"Failed to fetch user data with idp_intend_id\", \"details\": str(e)}\n            )\n        \n    def list_idp_providers(self):\n        self._ensure_valid_token()\n        try: \n            response = requests.post(\n                f\"{self.base_url}/management/v1/idps/templates/_search\",\n                json={\n                    \"query\": {\n                        \"offset\": \"0\",\n                        \"limit\": 100,\n                        \"asc\": True\n                    }\n                },\n                headers=self.headers\n                )\n            response.raise_for_status()\n            idp_data = response.json()\n            idp_list = [{\"id\" : item.get('id'), \"type\" : item.get('type')} for item in idp_data.get('result', [])]\n            \n            return {\n                \"idp_list\" : idp_list\n            }\n        \n        except requests.exceptions.RequestException as e:\n            return {\"error\": \"Failed to retrieve identity provider info\", \"details\": str(e)}, 500\n        \n    def login_with_username_password(self, username: str, password: str):\n        \"\"\"Login user with username and password.\"\"\"\n        self._ensure_valid_token()\n        try:\n            response = requests.post(\n                f\"{self.base_url}/v2/sessions\",\n                json={\n                    \"checks\": {\n                        \"user\": {\n                            \"loginName\": username\n                        }\n                    }\n                },\n                headers=self.headers,\n            )\n            response.raise_for_status()\n\n            session_data = response.json()\n            session_id = session_data.get(\"sessionId\")\n            session_token = session_data.get(\"sessionToken\")\n\n            validate_response = requests.patch(\n                f\"{self.base_url}/v2/sessions/{session_id}\",\n                json={\n                    \"checks\": {\n                        \"password\": {\n                            \"password\": password\n                        }\n                        \n                    },\n                    \"lifetime\": \"1800.000000000s\"\n                },\n                headers=self.headers,\n            )\n            validate_response.raise_for_status()\n\n            user_info = self.get_user_info(session_id)\n            user_id = user_info.get(\"session\").get(\"factors\").get(\"user\").get(\"id\")\n            username = user_info.get(\"session\").get(\"factors\").get(\"user\").get(\"displayName\")\n\n            \n            json_response = JSONResponse(\n                status_code=201,\n                content={\"message\": \"Session created successfully\", \"session_id\": session_id, \"user_id\": user_id, \"username\": username},\n            )\n            \n            json_response.set_cookie(\n                key=\"session_data\",\n                value=json.dumps({\"session_id\": session_id, \"session_token\": session_token, \"user_id\": user_id}),\n                httponly=True,\n                secure=False,\n                samesite=\"Lax\",\n                max_age=1800,\n                path=\"/\",\n            )\n            \n            return json_response\n\n        except requests.RequestException as e:\n            return JSONResponse(\n                status_code=500,\n                content={\n                    \"error\": \"Failed to create session\",\n                    \"details\": str(e)\n                }\n            )\n        \n    \n    def logout_user(self, session_id: str):\n        \"\"\"Logout user by deleting the session.\"\"\"\n        self._ensure_valid_token()\n        try:\n            response = requests.delete(\n                f\"{self.base_url}/v2/sessions/{session_id}\",\n                headers=self.headers,\n            )\n            response.raise_for_status()\n\n            return CommonResponse(\n                status=True,\n                status_code=response.status_code,\n                message=\"Logout Successful\" if response.status_code == 200 else \"Logout Unsuccessful\",\n                data=response.json(),\n                error=None,\n            )\n\n        except requests.RequestException as e:\n            return CommonResponse(\n                status=False,\n                status_code=500,\n                message=\"Logout Failed\",\n                data=None,\n                error=str(e),\n            )"
  },
  {
    "path": "app/readers/base_reader.py",
    "content": "from app.readers.text_reader import TxtLoader\nfrom app.readers.docx_reader import DocxReader\nfrom app.readers.yaml_reader import YamlLoader\nfrom app.readers.url_reader import UrlReader\nfrom app.readers.pdf_reader import PDFLoader\n\nfrom loguru import logger\n\nclass BaseReader:\n    def __init__(self, source):\n        logger.info(f\"initializing docs {source}\")\n        self.source = source\n\n    def load_data(self):\n        type = self.source[\"type\"] if \"type\" in self.source else \"\"\n        match type:\n            case \"text\":\n                loader = TxtLoader(source=self.source)\n            case \"yaml\":\n                loader = YamlLoader(source=self.source)\n            case \"docx\":\n                loader = DocxReader(source=self.source)\n            case \"url\":\n                loader = UrlReader(source=self.source)\n            case \"pdf\":\n                loader = PDFLoader(source=self.source)\n            case _:\n                raise ValueError(f\"Documentation in given format '{type}' not supported.\")\n        return loader.load()"
  },
  {
    "path": "app/readers/docs_reader.py",
    "content": "class DocsReader:\n\n    def __init__(self, source):\n        self.source = source\n\n    def load(self):\n        raise NotImplementedError(\"load method must be implemented in subclass\")\n\n"
  },
  {
    "path": "app/readers/docx_reader.py",
    "content": "from app.readers.docs_reader import DocsReader\nfrom loguru import logger\n# import textract\n\nclass DocxReader(DocsReader):\n    def load(self):\n        out = []\n        if \"path\" in self.source:\n            paths = self.source[\"path\"]\n            for path in paths:\n                try:\n                    # text = textract.process(path)\n                    text = \"\"\n\n                    metadata = {\n                        \"path\": path\n                    }\n                    out.append({\"content\": str(text), \"metadata\": metadata})\n\n                except Exception as e:\n                            logger.error(e)\n        return out"
  },
  {
    "path": "app/readers/pdf_reader.py",
    "content": "from app.readers.docs_reader import DocsReader\nfrom loguru import logger\nfrom docling.document_converter import DocumentConverter, PdfFormatOption\nfrom docling.datamodel.base_models import InputFormat\nfrom docling.datamodel.pipeline_options import PdfPipelineOptions, RapidOcrOptions\nfrom docling.backend.docling_parse_v4_backend import DoclingParseV4DocumentBackend\n\npipeline_options = PdfPipelineOptions()\npipeline_options.ocr_options = RapidOcrOptions()\npipeline_options.do_ocr = True\npipeline_options.do_table_structure = True\npipeline_options.table_structure_options.do_cell_matching = True\n\nconverter = DocumentConverter(\n    format_options={\n        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options, backend=DoclingParseV4DocumentBackend)\n    }\n)\n\n\nclass PDFLoader(DocsReader):\n    def load(self):\n        out = []\n        if \"path\" in self.source:\n            paths = self.source[\"path\"]\n\n            for path in paths:\n                try:\n                    metadata = {\"path\":path}\n                    result = converter.convert(path)\n                    temp = {}\n                    temp[\"content\"] = result.document.export_to_markdown()\n                    temp[\"metadata\"] = metadata\n                    if len(temp[\"content\"]) > 0:\n                            out.append(temp)\n                except Exception as e:\n                    logger.error(e)\n        return out\n\n\n"
  },
  {
    "path": "app/readers/text_reader.py",
    "content": "from app.readers.docs_reader import DocsReader\nfrom loguru import logger\n\nclass TxtLoader(DocsReader):\n    def load(self):\n        out = []\n        if \"path\" in self.source:\n            paths = self.source[\"path\"]\n            for path in paths:\n                try:\n                    metadata = {\"path\":path}\n                    temp = {}\n                    with open(path, 'r', encoding='utf-8') as file:\n                        content = file.read()\n                    temp[\"content\"] = str(content)\n                    temp[\"metadata\"] = metadata\n                    out.append(temp)\n                except Exception as e:\n                    logger.error(e)\n        elif \"value\" in self.source:\n            if self.source[\"value\"] is not None:\n                out.append(\n                    {\n                        \"content\": self.source[\"value\"],\n                        \"metadata\": {\n                        }\n                    }\n                )\n        return out"
  },
  {
    "path": "app/readers/url_reader.py",
    "content": "from app.readers.docs_reader import DocsReader\nfrom loguru import logger\nimport requests\nfrom bs4 import BeautifulSoup\nfrom urllib.parse import urljoin\nfrom typing import Dict\nfrom urllib.parse import urlparse\n\n\nclass UrlReader(DocsReader):\n\n    def __init__(self, source):\n        self.source = source\n        self.visited_url = set()\n\n\n\n    def load(self):\n        out = []\n        max_depth = self.source.get(\"depth\", 1)\n        depth_map: Dict[str, int] = {}\n        url_queue = []\n\n        if \"path\" in self.source:\n            urls = self.source[\"path\"]\n\n            for url in urls:\n                url_queue.append(url)\n                depth_map[url] = 1\n\n            base_domain = urlparse(urls[0]).netloc\n\n            while url_queue :\n                url = url_queue.pop(0)\n\n                current_depth = depth_map.get(url, 1)\n                logger.info(f\"scanning url {url}\")\n                if url in self.visited_url or current_depth > max_depth:\n                    continue\n                logger.info(f\"urls in queue {len(url_queue)} visited {len(self.visited_url)}\")\n                self.visited_url.add(url)\n                try:\n                    response = requests.get(url, headers=self.source.get(\"headers\", {}))\n\n                    if response.status_code == 200:\n                        soup = BeautifulSoup(response.content, 'html.parser')\n                        for a in soup.find_all('a', href = True) :\n                                absolute_url = urljoin(url, a['href'])\n                                if absolute_url not in self.visited_url and  urlparse(absolute_url).netloc == base_domain and absolute_url not in url_queue:\n                                    if current_depth + 1 <= max_depth or max_depth == 0:\n                                        url_queue.append(absolute_url)\n                                        depth_map[absolute_url] = current_depth + 1\n                        tag = soup.body\n                        text = ''.join(list(tag.strings)[:-1])\n                        metadata = {\n                            \"path\": url\n                        }\n                        out.append({\"content\": str(text), \"metadata\": metadata})\n                    else:\n                        logger.critical(f\"Failed to retrieve content, status code: {response.status_code}\")\n                except Exception as e:\n                    logger.error(e)\n        return out"
  },
  {
    "path": "app/readers/yaml_reader.py",
    "content": "from app.readers.docs_reader import DocsReader\nfrom loguru import logger\nimport yaml\n\nclass YamlLoader(DocsReader):\n    def load(self):\n        out = []\n        if \"path\" in self.source:\n            paths = self.source[\"path\"]\n            for path in paths:\n                try:\n                    metadata = {\"path\":path}\n                    temp = {}\n                    with open(path, 'r', encoding='utf-8') as file:\n                        content = file.read()\n                    body = yaml.safe_load(content)\n                    temp[\"content\"] = yaml.dump(body)\n                    temp[\"metadata\"] = metadata\n                    out.append(temp)\n                except Exception as e:\n                    logger.error(e)\n        return out"
  },
  {
    "path": "app/repository/connector.py",
    "content": "from sqlalchemy.orm import Session, joinedload\nimport app.models.connector as models\nimport app.models.provider as prov_models\nimport app.schemas.connector as schemas\nfrom sqlalchemy.exc import SQLAlchemyError\nfrom typing import List\n\nfrom app.models.environment import UserEnvironmentMapping\n\n\ndef get_connectors_by_configuration_id(configuration_id: int, db: Session):\n    try:\n        connectors = (\n            db.query(models.Connector)\n            .join(models.ConfigurationConnectorMapping, models.Connector.id == models.ConfigurationConnectorMapping.connector_id)\n            .filter(models.ConfigurationConnectorMapping.configuration_id == configuration_id)\n            .all()\n        )\n        return connectors, False\n    except Exception as e:\n        return None, str(e)    \n    \n\ndef get_all_connectors(db: Session, user_id: str):\n    try:\n        active_env = (db.query(UserEnvironmentMapping)\n            .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True)\n            .first())\n        connectors = (\n            db.query(models.Connector)\n            .filter(models.Connector.environment_id == active_env.id)  \n            .options(joinedload(models.Connector.provider))  \n            .all()\n        )\n        return connectors, False\n    except SQLAlchemyError as e:\n        return str(e), True\n\n\ndef get_connector_by_id(connector_id: int, db: Session):\n    try:\n        return db.query(models.Connector).options(joinedload(models.Connector.provider)).filter(models.Connector.id == connector_id).first(), False\n    except SQLAlchemyError as e:\n        return str(e), True\n\ndef create_new_connector(connector: schemas.ConnectorBase, db: Session, user_id: str):\n    try:\n        active_env = (db.query(UserEnvironmentMapping)\n            .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True)\n            .first())\n        db_connector = models.Connector(**connector.model_dump(),environment_id=active_env.id)\n        db.add(db_connector)\n        db.commit()\n        db.refresh(db_connector)\n        return db_connector, False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef update_existing_connector(connector_id: int, connector: schemas.ConnectorUpdate, db: Session):\n    try:\n        db_connector = db.query(models.Connector).filter(models.Connector.id == connector_id).first()\n        if db_connector:\n            for key, value in connector.model_dump(exclude_unset=True).items():\n                setattr(db_connector, key, value)\n            db.commit()\n            db.refresh(db_connector)\n        return db_connector, False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef update_schemas(connector_id: int, connector: schemas.ConnectorUpdate, db: Session):\n    try:\n        db_connector = db.query(models.Connector).filter(models.Connector.id == connector_id).first()\n\n        if db_connector and connector.schema_config:\n            db_connector.schema_config = connector.schema_config\n            db.commit()\n            db.refresh(db_connector)\n\n        return db_connector, False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\n\ndef delete_connector_by_id(connector_id: int, db: Session):\n    try:\n        db_connector = db.query(models.Connector).filter(models.Connector.id == connector_id).first()\n        if db_connector:\n            db.delete(db_connector)\n            db.commit()\n        return db_connector, False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef get_all_configurations(db: Session, user_id: str):\n    try:\n        active_env = (db.query(UserEnvironmentMapping)\n            .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True)\n            .first())\n        return (\n            db.query(models.Configuration)\n            .filter(models.Configuration.environment_id == active_env.id)\n            .options(\n                joinedload(models.Configuration.capabilities),\n                joinedload(models.Configuration.inference_mapping).joinedload(models.Inferenceconfigmapping.inference),\n                joinedload(models.Configuration.vectordb_config_mapping).joinedload(prov_models.VectorDBConfigMapping.vector_db),\n                joinedload(models.Configuration.connectors).joinedload(models.ConfigurationConnectorMapping.connector)  \n            )\n            .all(),\n            False\n        )\n    except SQLAlchemyError as e:\n        return str(e), True\n\n\ndef get_inference_by_config(config_id: int, db: Session):\n    \"\"\"\n    Retrieves the Inference based on the config_id, using joinedload to load related data.\n\n    Args:\n        config_id (int): The configuration ID to query.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: Inference instance, error message (if any).\n    \"\"\"\n    try:\n        result = db.query(models.Inferenceconfigmapping).options(joinedload(models.Inferenceconfigmapping.inference)).options(joinedload(models.Inferenceconfigmapping.configuration)).filter(models.Inferenceconfigmapping.config_id == config_id).first()\n\n        if result:\n            return result.inference, False\n        else:\n            return None, \"Inference not found for the given config_id\"\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return None, str(e)\n\ndef getbotconfiguration(db:Session):\n\n    try:\n        return (\n            db.query(models.Configuration).filter(models.Configuration.status == 2).first()\n        ), False\n\n    except SQLAlchemyError as e:\n        return str(e), True\n\ndef create_new_configuration(configuration: schemas.ConfigurationCreation, db: Session, user_id: str):\n    try:\n        active_env = (db.query(UserEnvironmentMapping)\n            .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True)\n            .first())\n        db_configuration = models.Configuration(\n            name=configuration.name,\n            short_description=configuration.short_description,\n            long_description=configuration.long_description,\n            status=configuration.status,\n            environment_id=active_env.id \n        )\n        db.add(db_configuration)\n        db.commit()\n        db.refresh(db_configuration)\n\n        for capability_id in configuration.capabilities:\n            db_capability = db.query(models.Capabilities).get(capability_id)\n            if db_capability:\n                db_capability.config_id = db_configuration.id\n                db.add(db_capability)\n\n        db.commit()\n        \n        if configuration.connectors:\n            link_configuration_to_connectors(db_configuration.id, configuration.connectors, db)\n\n        return db_configuration, False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\n\ndef link_configuration_to_connectors(config_id: int, connector_ids: list[int], db: Session):\n    \"\"\"\n    Links a configuration with selected connectors.\n    \"\"\"\n    try:\n        for connector_id in connector_ids:\n            existing_mapping = (\n                db.query(models.ConfigurationConnectorMapping)\n                .filter_by(configuration_id=config_id, connector_id=connector_id)\n                .first()\n            )\n            if not existing_mapping:\n                mapping = models.ConfigurationConnectorMapping(configuration_id=config_id, connector_id=connector_id)\n                db.add(mapping)\n\n        db.commit()\n        return True, None\n    except SQLAlchemyError as e:\n        db.rollback()\n        return False, str(e)\n\ndef update_existing_configuration(config_id: int, configuration: schemas.ConfigurationUpdate, db: Session):\n    try:\n        db_configuration = db.query(models.Configuration).filter(models.Configuration.id == config_id).first()\n        if db_configuration is None:\n            return None, True\n\n        db_configuration.name = configuration.name if configuration.name else db_configuration.name\n        db_configuration.short_description = configuration.short_description if configuration.short_description else db_configuration.short_description\n        db_configuration.long_description = configuration.long_description if configuration.long_description else db_configuration.long_description\n        db_configuration.status = configuration.status if configuration.status else db_configuration.status\n\n        db.commit()\n        db.refresh(db_configuration)\n\n        if configuration.capabilities is not None:\n            db.query(models.Capabilities).filter(models.Capabilities.config_id == config_id).update(\n                {models.Capabilities.config_id: None}, synchronize_session=False\n            )\n            db.commit()\n\n            for capability_id in configuration.capabilities:\n                query = db.query(models.Capabilities).filter(models.Capabilities.id == capability_id).first()\n                if query:\n                    query.config_id = config_id\n                    db.add(query)\n                    db.commit()\n                    db.refresh(query)\n                    \n        if configuration.connectors is not None:\n            \n            \"\"\" fetch existing connector mapping \"\"\"\n            existing_connector_ids = {\n                mapping.connector_id for mapping in db.query(models.ConfigurationConnectorMapping)\n                .filter(models.ConfigurationConnectorMapping.configuration_id == config_id)\n                .all()\n            }\n            \n            new_connector_ids = set(configuration.connectors)\n            connectors_to_remove = existing_connector_ids - new_connector_ids\n            if connectors_to_remove:\n                db.query(models.ConfigurationConnectorMapping).filter(\n                models.ConfigurationConnectorMapping.configuration_id == config_id,\n                models.ConfigurationConnectorMapping.connector_id.in_(connectors_to_remove)\n                ).delete(synchronize_session=False)\n                db.commit()\n            \n            connector_to_add = new_connector_ids - existing_connector_ids\n            if connector_to_add:\n                link_configuration_to_connectors(db_configuration.id, connector_to_add, db)\n            \n            \n        return db_configuration, False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef get_configuration_by_id(config_id: int, db: Session):\n    try:\n        return (\n            db.query(models.Configuration)\n            .filter(models.Configuration.id == config_id)\n            .options(\n                joinedload(models.Configuration.capabilities),\n                joinedload(models.Configuration.inference_mapping).joinedload(models.Inferenceconfigmapping.inference),\n                joinedload(models.Configuration.vectordb_config_mapping).joinedload(prov_models.VectorDBConfigMapping.vector_db),\n                joinedload(models.Configuration.connectors).joinedload(models.ConfigurationConnectorMapping.connector)  # 🔹 Include connectors\n            )\n            .first(), \n            False\n            )\n    except SQLAlchemyError as e:\n        return str(e), True\n    \ndef delete_configuration_by_id(configuration_id: int, db: Session):\n    try:\n        db_configuration = db.query(models.Configuration).filter(models.Configuration.id == configuration_id).options(joinedload(models.Configuration.capabilities)).first()\n        if db_configuration:\n            db.delete(db_configuration)\n            db.commit()\n        return db_configuration, False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef update_configuration_status(config_id: int,status: int, db: Session):\n    try:\n        db_config, is_error = get_configuration_by_id(config_id, db)\n\n        if db_config and not is_error:\n            db_config.status = status\n\n            db.commit()\n            db.refresh(db_config)\n\n            return db_config, False\n        else:\n            return None, True\n    except (SQLAlchemyError, ValueError) as e:\n        db.rollback()\n        return str(e), True\n    \ndef default_configuration_status(db: Session):\n    try:\n        db.query(models.Configuration).filter(\n            models.Configuration.status == 2\n            ).update({\"status\": 1})\n        db.commit()\n        return True, False\n\n    except (SQLAlchemyError, ValueError) as e:\n        db.rollback()\n        return str(e), True\n    \n    \n\n\n\ndef create_capability(capability: schemas.CapabilitiesBase, db: Session):\n    try:\n        new_capability = models.Capabilities(\n            name=capability.name,\n            description=capability.description,\n            requirements=capability.requirements,\n            config_id=capability.config_id if capability.config_id else None,\n            enable=True\n        )\n        db.add(new_capability)\n        db.commit()\n        db.refresh(new_capability)\n        return new_capability, False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef create_capability_action_mappings(capability_id: int, action_ids: List[int], db: Session):\n    try:\n        for action_id in action_ids:\n            mapping = models.CapActionsMapping(\n                capability_id=capability_id,\n                action_id=action_id,\n                enable=True\n            )\n            db.add(mapping)\n\n        db.commit()\n        return True, False  # Successful creation, no error\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True  # Error occurred\n\ndef get_all_capabilities(db: Session):\n    try:\n        capabilities = db.query(models.Capabilities).options(\n            joinedload(models.Capabilities.cap_actions_mapping).joinedload(models.CapActionsMapping.actions)\n        ).all()\n\n        return capabilities, False\n    except SQLAlchemyError as e:\n        return str(e), True\n\n\ndef update_capability(cap_id: int, capability: schemas.CapabilitiesUpdateBase, db: Session):\n    try:\n        capability_record = db.query(models.Capabilities).filter(models.Capabilities.id == cap_id).first()\n\n        if capability_record:\n            capability_record.name = capability.name if capability.name else capability_record.name\n            capability_record.description = capability.description if capability.description else capability_record.description\n            capability_record.requirements = capability.requirements if capability.requirements else capability_record.requirements\n            capability_record.config_id = capability.config_id if capability.config_id else capability_record.config_id\n\n            if capability.actions_list:\n                db.query(models.CapActionsMapping).filter(models.CapActionsMapping.capability_id == cap_id).delete()\n\n                for action_id in capability.actions_list:\n                    new_mapping = models.CapActionsMapping(\n                        capability_id=cap_id,\n                        action_id=action_id,\n                        enable=True\n                    )\n                    db.add(new_mapping)\n\n            db.commit()\n            db.refresh(capability_record)\n\n            return capability_record, False\n\n        return None, True\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef delete_capability(cap_id: int, db: Session):\n    try:\n        capability_record = db.query(models.Capabilities).filter(models.Capabilities.id == cap_id).first()\n\n        if capability_record:\n            db.query(models.CapActionsMapping).filter(models.CapActionsMapping.capability_id == cap_id).delete()\n\n            db.delete(capability_record)\n            db.commit()\n\n            return True, False\n\n        return False, True\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\n\ndef get_inference_by_id(inference_id: int, db: Session):\n    try:\n        return db.query(models.Inference).filter(models.Inference.id == inference_id).first(), False\n    except SQLAlchemyError as e:\n        return str(e), True\n\n\ndef create_inference(inference: schemas.InferenceBase, db: Session):\n    try:\n        db_inference = models.Inference(\n            name=inference.name,\n            apikey=inference.apikey,\n            llm_provider=inference.llm_provider,\n            model=inference.model,\n            endpoint=inference.endpoint\n        )\n        db.add(db_inference)\n        db.commit()\n        db.refresh(db_inference)\n\n        db_mapping = models.Inferenceconfigmapping(\n            inference_id=db_inference.id,\n            config_id=inference.config_id,\n            enable=True\n        )\n        db.add(db_mapping)\n        db.commit()\n\n        db.refresh(db_inference)\n\n        return db_inference, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef update_inference(inference_id: int, inference: schemas.InferenceBaseUpdate, db: Session):\n    try:\n        db_inference = db.query(models.Inference).filter(models.Inference.id == inference_id).first()\n\n        if db_inference is None:\n            return \"Data is None\", True\n\n        db_inference.name = inference.name if inference.name else db_inference.name\n        db_inference.apikey = inference.apikey if inference.apikey else db_inference.apikey\n        db_inference.llm_provider = inference.llm_provider if inference.llm_provider else db_inference.llm_provider\n        db_inference.model = inference.model if inference.model else db_inference.model\n        db_inference.endpoint = inference.endpoint if inference.endpoint else db_inference.endpoint\n\n        db.commit()\n        db.refresh(db_inference)\n\n        if inference.config_id:\n            db_mapping = db.query(models.Inferenceconfigmapping).filter(models.Inferenceconfigmapping.inference_id == inference_id).first()\n            if db_mapping:\n                db_mapping.config_id = inference.config_id\n            else:\n                db_mapping = models.Inferenceconfigmapping(\n                    inference_id=inference_id,\n                    config_id=inference.config_id,\n                    enable=True\n                )\n                db.add(db_mapping)\n            db.commit()\n            db.refresh(db_mapping)\n\n        return db_inference, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef get_inferences_by_config_id(config_id: int, db: Session):\n    try:\n        return db.query(models.Inferenceconfigmapping).options(joinedload(models.Inferenceconfigmapping.inference)).filter(models.Inferenceconfigmapping.config_id == config_id).all(), False\n    except SQLAlchemyError as e:\n        return str(e), True\n\ndef list_actions(db:Session):\n    try:\n        return db.query(models.Actions).all(), False\n    except SQLAlchemyError as e:\n        return str(e),\n\ndef get_action_by_id(action_id:int, db:Session):\n    try:\n        return db.query(models.Actions).filter(models.Actions.id == action_id).first(), False\n    except SQLAlchemyError as e:\n        return str(e),\n\ndef get_actions_by_connector(connector_id:int, db:Session):\n    try:\n        return db.query(models.Actions).filter(models.Actions.connector_id == connector_id).all(), False\n    except SQLAlchemyError as e:\n        return str(e), True\n\ndef create_action(action:schemas.Actions, db:Session):\n    try:\n        db_action = models.Actions(\n            name=action.name,\n            description=action.description if action.description else None,\n            types=action.types,\n            connector_id = action.connector_id,\n            condition = action.condition if action.condition else None,\n            table = action.table if action.table else None,\n            body = action.body\n        )\n        db.add(db_action)\n        db.commit()\n        db.refresh(db_action)\n        return db_action, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\n\ndef update_action(action_id: int, action: schemas.ActionsUpdate, db: Session):\n    try:\n        db_action = db.query(models.Actions).filter(models.Actions.id == action_id).first()\n\n        if db_action is None:\n            return \"Data is None\", True\n\n        db_action.name = action.name if action.name else db_action.name\n        db_action.description = action.description if action.description else db_action.description\n        db_action.types = action.types if action.types else db_action.types\n        db_action.connector_id = action.connector_id if action.connector_id else db_action.connector_id\n        db_action.condition = action.condition if action.condition else db_action.condition\n        db_action.table = action.table if action.table else db_action.table\n        db_action.body = action.body if action.body else db_action.body\n\n        db.commit()\n        db.refresh(db_action)\n\n        return db_action, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\n\ndef delete_action_by_id(action_id: int, db: Session):\n    try:\n        db_action = db.query(models.Actions).filter(models.Actions.id == action_id).first()\n\n        if db_action is None:\n            return \"Data is None\", True\n\n        db.delete(db_action)\n        db.commit()\n\n        return True, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True"
  },
  {
    "path": "app/repository/environment.py",
    "content": "from sqlalchemy.orm import Session\nimport app.models.environment as models\nimport app.schemas.environment as schemas\nfrom sqlalchemy.exc import SQLAlchemyError\n\ndef create_environment(name: str, db: Session):\n    \"\"\" creates a new environment with a given name\"\"\"\n    new_env = models.Environment(name=name)\n    db.add(new_env)\n    db.commit()\n    db.refresh(new_env)\n    return new_env\n\ndef get_or_create_default_environment(db: Session):\n    default_env = db.query(models.Environment).filter(models.Environment.name == \"Default Environment\").first()\n\n    if not default_env:\n        default_env = models.Environment(name=\"Default Environment\", is_active=True)\n        db.add(default_env)\n        db.commit()\n        db.refresh(default_env)\n\n    return default_env\n\ndef assign_user_to_environment(user_id: int, environment_id: int, db: Session):\n    try:\n        user_env_mapping = models.UserEnvironmentMapping(user_id=user_id, environment_id=environment_id,  is_active=True)\n        db.add(user_env_mapping)\n        db.commit()\n        return user_env_mapping, None\n    except SQLAlchemyError as e:\n        db.rollback()\n        return None, str(e)\n\n\n\ndef get_current_env_id(user_id: int, db: Session):\n    try:\n        active_env = (db.query(models.UserEnvironmentMapping)\n        .filter(models.UserEnvironmentMapping.user_id == user_id, models.UserEnvironmentMapping.is_active == True)\n        .first())\n        return active_env.id, None\n    \n    except SQLAlchemyError as e:\n        return None, str(e)"
  },
  {
    "path": "app/repository/llmchat.py",
    "content": "from sqlalchemy.orm import Session\nfrom app.models.llmchat import ChatHistory\nfrom app.schemas import llmchat as schemas\nfrom sqlalchemy.exc import SQLAlchemyError\n\n\n\ndef get_chat_by_context_and_id(chat_context_id: str, chat_id: int, db: Session):\n    try:\n        chat = db.query(ChatHistory).filter(ChatHistory.chat_context_id == chat_context_id, ChatHistory.chat_id == chat_id).first()\n        return chat, False\n    except SQLAlchemyError as e:\n        return e, True\n\ndef create_new_chat(chat: schemas.ChatHistoryCreate, db: Session):\n    try:\n        existing_chat = db.query(ChatHistory).filter(ChatHistory.chat_context_id == chat.chat_context_id).first()\n\n        chat.primary_chat=existing_chat is None\n\n        db_chat = ChatHistory(\n            **chat.model_dump()\n        )\n\n        db.add(db_chat)\n        db.commit()\n        db.refresh(db_chat)\n        return db_chat, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\n# based on feedback\ndef update_chat_feedback(feedback: schemas.FeedbackCreate, db: Session):\n    chat, is_error = get_chat_by_context_and_id(feedback.chat_context_id, feedback.chat_id, db)\n    if is_error:\n        return chat, True\n\n    if not chat:\n        return None, False\n\n    chat.feedback_status = feedback.feedback_status\n    chat.feedback_json = feedback.feedback_json\n\n    try:\n        db.commit()\n        db.refresh(chat)\n        return chat, False\n    except SQLAlchemyError as e:\n        return e, True\n\n\ndef get_primary_chat(env_id: int, db: Session):\n    try:\n        \n        data = db.query(ChatHistory).filter(ChatHistory.primary_chat == True, ChatHistory.environment_id == env_id).distinct(ChatHistory.chat_context_id).all()\n        return data, False\n    except SQLAlchemyError as e:\n        return e, True\n\n\ndef get_all_chats_by_context_id(context_id: str, db: Session):\n    try:\n        data = db.query(ChatHistory).filter(ChatHistory.chat_context_id == context_id).all()\n        return data, False\n    except SQLAlchemyError as e:\n        return e, True"
  },
  {
    "path": "app/repository/provider.py",
    "content": "from sqlalchemy.orm import Session\nimport app.models.provider as models\nimport app.models.connector as conn_model\nfrom sqlalchemy.orm import joinedload\nfrom sqlalchemy.exc import SQLAlchemyError\nfrom typing import Any, Dict\nimport app.schemas.provider as schemas\n\nfrom app.models.environment import UserEnvironmentMapping\n\n\ndef insert_or_update_data(db: Session, model: Any, filters: Dict[str, Any], data: Dict[str, Any]) -> tuple:\n    try:\n        existing_record = db.query(model).filter_by(**filters).first()\n\n        if existing_record:\n            for key, value in data.items():\n                setattr(existing_record, key, value)\n\n            db.commit()\n            db.refresh(existing_record)\n            return existing_record, False\n        else:\n            new_record = model(**data)\n            db.add(new_record)\n            db.commit()\n            db.refresh(new_record)\n            return new_record, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        db.expunge_all()\n        return str(e), True\n\n\n\ndef get_all_providers(db: Session):\n    try:\n        return db.query(models.Provider).options(joinedload(models.Provider.providerconfig)).all(), False\n    except SQLAlchemyError as e:\n        return e, True\n\ndef get_provider_by_id(provider_id: int, db: Session):\n    try:\n        provider = db.query(models.Provider).options(joinedload(models.Provider.providerconfig)).filter(models.Provider.id == provider_id).first()\n        return provider, False\n    except SQLAlchemyError as e:\n        return e, True\ndef get_vector_db_config(db: Session, key: str):\n    try:\n        return db.query(models.VectorDBConfig).filter(models.VectorDBConfig.key==key).first(), False\n    except SQLAlchemyError as e:\n        return e, True\n\ndef get_vectordb_providers(db:Session):\n    try:\n        return db.query(models.VectorDBConfig).all(), False\n    except SQLAlchemyError as e:\n        return e, True\n\ndef get_config_types(provider_id: int, db:Session):\n    try:\n        return db.query(models.ProviderConfig).filter(models.ProviderConfig.provider_id==provider_id).all(), False\n    except SQLAlchemyError as e:\n        return e, True\n\ndef get_sql_by_connector(id:int, db:Session):\n    try:\n        return db.query(models.SampleSQL).filter(models.SampleSQL.connector_id == id).all(), False\n    except SQLAlchemyError as e:\n        return e, True\n\ndef list_sql(db:Session, user_id: str):\n    try:\n        active_env = (db.query(UserEnvironmentMapping)\n            .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True)\n            .first())\n        sql = (\n            db.query(models.SampleSQL)\n            .filter(models.SampleSQL.environment_id == active_env.id)\n            .all()\n        )\n        return sql, False\n    except SQLAlchemyError as e:\n        return e, True\n\ndef get_sql(id:int,db:Session):\n    try:\n        return db.query(models.SampleSQL).filter(models.SampleSQL.id == id).first(), False\n    except SQLAlchemyError as e:\n        return e, True\n\ndef create_sql(sql:schemas.SampleSQLBase, db:Session, user_id: str):\n\n    try:\n        active_env = (db.query(UserEnvironmentMapping)\n            .filter(UserEnvironmentMapping.user_id == user_id, UserEnvironmentMapping.is_active == True)\n            .first())\n        db_sql = models.SampleSQL(\n            description=sql.description,\n            sql_metadata=sql.sql_metadata,\n            connector_id = sql.connector_id,\n            environment_id = active_env.id\n        )\n        db.add(db_sql)\n        db.commit()\n        db.refresh(db_sql)\n        return db_sql, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef update_sql(sql_id:int, sql:schemas.SampleSQLUpdate, db:Session):\n    try:\n        db_sql = db.query(models.SampleSQL).filter(models.SampleSQL.id == sql_id).first()\n\n        if db_sql is None:\n            return \"Data is None\", True\n\n        db_sql.description = sql.description if sql.description else db_sql.description\n        db_sql.sql_metadata = sql.sql_metadata if sql.sql_metadata else db_sql.sql_metadata\n        db_sql.connector_id = sql.connector_id if sql.connector_id else db_sql.connector_id\n        db.commit()\n        return db_sql, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\n\ndef delete_sql(sql_id:int, db: Session):\n    try:\n        db_sql = db.query(models.SampleSQL).filter(models.SampleSQL.id == sql_id).first()\n        if db_sql is None:\n            return \"Data is None\", True\n        db.delete(db_sql)\n        db.commit()\n        return None, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef get_sql_by_key(key: str, db: Session):\n    try:\n        return db.query(models.SampleSQL).options(joinedload(models.SampleSQL.connectors)).filter(conn_model.Connector.connector_name == key).first(), False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e),True\n\ndef revoke_existing_vectordb_confg(id: int, db: Session):\n    \"\"\"\n    Revoke (delete) existing VectorDB configurations based on vector_db_id.\n\n    Args:\n        id (int): The vector_db_id to delete the mappings for.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: (Success message or error, Boolean indicating if an error occurred)\n    \"\"\"\n    try:\n        existing_mappings = db.query(models.VectorDB).join(models.VectorDBConfigMapping)\\\n            .filter(models.VectorDBConfigMapping.vector_db_id == id).all()\n\n        for mapping in existing_mappings:\n            db.delete(mapping)\n\n        db.commit()\n\n        return \"VectorDB configurations revoked successfully\", False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\n\n\ndef create_vectordb_with_embedding(key,id, vectordb, db: Session):\n\n    if key == \"update\":\n        result, is_error = revoke_existing_vectordb_confg(id, db)\n\n        if is_error:\n            return result, True\n\n    try:\n        db_vectordb = models.VectorDB(\n            vectordb=vectordb.vectordb,\n            vectordb_config=vectordb.vectordb_config,\n        )\n        db.add(db_vectordb)\n        db.commit()\n        db.refresh(db_vectordb)\n\n\n        db_vectordb_mapping = models.VectorDBConfigMapping(\n            vector_db_id=db_vectordb.id,\n            config_id=vectordb.config_id,\n        )\n        db.add(db_vectordb_mapping)\n        db.commit()\n        db.refresh(db_vectordb_mapping)\n\n        if vectordb.embedding_config:\n            db_embedding = models.Embeddings(\n                provider=vectordb.embedding_config['provider'],\n                config=vectordb.embedding_config['params'],\n            )\n            db.add(db_embedding)\n            db.commit()\n            db.refresh(db_embedding)\n\n            db_embedding_mapping = models.VectorEmbeddingMapping(\n                vector_db_id=db_vectordb.id,\n                embedding_id=db_embedding.id,\n            )\n            db.add(db_embedding_mapping)\n            db.commit()\n            db.refresh(db_embedding_mapping)\n\n            return {\n                'vectordb': db_vectordb,\n                'vectordb_mapping': db_vectordb_mapping,\n                'embedding': db_embedding,\n            }, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\n\n\ndef get_vectordb_instance(id: int, db: Session):\n    \"\"\"\n    Retrieves a VectorDB instance by its ID, along with its associated VectorDBConfigMapping, using joinedload.\n\n    Args:\n        id (int): The ID of the VectorDB instance.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: The VectorDB instance and its associated config mapping, or an error message.\n    \"\"\"\n    try:\n        db_vectordb = db.query(models.VectorDB).join(models.VectorDBConfigMapping)\\\n            .options(joinedload(models.VectorDB.vectordb_config_mapping))\\\n            .filter(models.VectorDBConfigMapping.config_id == id).first()\n\n        embedding = db.query(models.Embeddings).join(models.VectorEmbeddingMapping)\\\n                    .filter(models.VectorEmbeddingMapping.vector_db_id == db_vectordb.id).first()\n\n        if not db_vectordb:\n            return \"VectorDB not found\", True\n\n        if not embedding:\n            return \"No embedding found for VectorDB\", True\n\n        return (db_vectordb, embedding), False\n\n    except SQLAlchemyError as e:\n        return str(e), True\n\ndef get_mapped_vector_store(db: Session, config_id: int):\n    try:\n\n        vectordb = db.query(models.VectorDB).join(models.VectorDBConfigMapping, models.VectorDB.id == models.VectorDBConfigMapping.vector_db_id)\\\n            .options(joinedload(models.VectorDB.vectordb_config_mapping))\\\n            .filter(models.VectorDBConfigMapping.config_id == config_id).first()\n\n        if not vectordb:\n            return None, False\n\n        embedding = db.query(models.Embeddings).join(models.VectorEmbeddingMapping, models.Embeddings.id == models.VectorEmbeddingMapping.embedding_id)\\\n            .filter(models.VectorEmbeddingMapping.vector_db_id == vectordb.id).first()\n\n        embedding_details = {\n            \"vectordb\": vectordb.vectordb,\n            \"vectordb_config\": vectordb.vectordb_config,\n        }\n\n        if embedding:\n            embedding_details.update({\n                \"em_provider\": embedding.provider,\n                \"embedding_config\": embedding.config\n            })\n\n        return embedding_details, False\n\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True"
  },
  {
    "path": "app/repository/user.py",
    "content": "from sqlalchemy.orm import Session\nimport app.models.user as models\nimport app.schemas.user as schemas\nfrom sqlalchemy.exc import SQLAlchemyError\n\ndef create_user(user: schemas.UserCreate, db: Session):\n    try:\n        db_user = models.User(**user.model_dump())\n        db.add(db_user)\n        db.commit()\n        db.refresh(db_user)\n        return db_user, False\n    except SQLAlchemyError as e:\n        db.rollback()\n        return str(e), True\n\ndef get_user_by_id(user_id: int, db: Session):\n    try:\n        return db.query(models.User).filter(models.User.id == user_id).first(), False\n    except SQLAlchemyError as e:\n        return str(e), True\n"
  },
  {
    "path": "app/schemas/common.py",
    "content": "from pydantic import BaseModel\nfrom typing import Optional, Any\n\nclass DBConfig(BaseModel):\n    host: str\n    port: int\n    username: str\n    password: str\n    dbname: str\n\nclass CommonResponse(BaseModel):\n    status: bool\n    status_code: int\n    data: Optional[Any] = None\n    message: Optional[str] = None\n    error: Optional[str] = None\n\nclass LoginData(BaseModel):\n    username: str\n    password: str"
  },
  {
    "path": "app/schemas/connector.py",
    "content": "from pydantic import BaseModel\nfrom typing import List, Dict, Optional, Union\nfrom app.schemas.provider import VectorDBResponse\nclass ConnectorBase(BaseModel):\n    connector_type: int\n    connector_name: str\n    connector_description: Optional[str] = None\n    connector_config: dict\n    schema_config: Optional[Union[List[Dict], Dict]] = None\n    connector_docs: Optional[str]= None\n    enable: Optional[bool] = True\n\nclass ConnectorResponse(ConnectorBase):\n    connector_id:int\n    connector_key :Optional[str]=None\n    icon:Optional[str]=None\n    provider_id: Optional[int] = None\n\nclass ConnectorUpdate(BaseModel):\n    connector_type: Optional[int] = None\n    connector_name: Optional[str] = None\n    connector_description: Optional[str] = None\n    connector_config: Optional[dict] = None\n    connector_docs: Optional[str]= None\n    schema_config: Optional[List[Dict]] = None\n\nclass SchemaUpdate(BaseModel):\n    schema_config : Optional[List[Dict]]=None\n\nclass CapabilitiesBase(BaseModel):\n    id:Optional[int]=None\n    name:str\n    description:str\n    requirements:List[Dict]\n    config_id:Optional[int]=None\n    actions_list: Optional[List[int]]=None\n    actions:Optional[List[Dict]]=None\n\nclass CapabilitiesArray(BaseModel):\n    capabilities:List[CapabilitiesBase]\n\nclass CapabilitiesUpdateBase(BaseModel):\n    id:Optional[int]=None\n    name:Optional[str]=None\n    description:Optional[str]=None\n    requirements:Optional[List[Dict]]=None\n    config_id:Optional[int]=None\n    actions_list: Optional[List[int]]=None\n\nclass ConfigurationBase(BaseModel):\n    short_description: str\n    long_description: Optional[str]\n    name:str\n    status: int\n\nclass ConfigurationCreation(ConfigurationBase):\n    capabilities: List[int]\n    connectors: List[int]\n\n\n\nclass ConfigurationUpdate(BaseModel):\n    name:Optional[str]=None\n    short_description: Optional[str] = None\n    long_description: Optional[str] = None\n    status: Optional[int] = 0\n    capabilities: Optional[List[int]]=None\n    connectors: List[int]\n\n\nclass InferenceBase(BaseModel):\n    name:str\n    apikey:str\n    llm_provider:str\n    model:str\n    config_id:Optional[int]=None\n    endpoint:str\n\nclass InferenceBaseUpdate(BaseModel):\n    name:Optional[str]=None\n    apikey:Optional[str]=None\n    llm_provider:Optional[str]=None\n    model:Optional[str]=None\n    config_id:Optional[int]=None\n    endpoint:Optional[str]=None\n\nclass InferenceResponse(InferenceBase):\n    id:int\n\nclass ConfigurationResponse(ConfigurationBase):\n    id: int\n    capabilities: List[CapabilitiesBase]\n    inference: Optional[List[InferenceResponse]]=None\n    vectordb: Optional[List[VectorDBResponse]]=None\n    connector: Optional[List[ConnectorResponse]]=None\n\nclass Actions(BaseModel):\n    name: str\n    description: Optional[str] = None\n    types: str\n    condition: Optional[Dict] = None\n    table : Optional[str] = None\n    connector_id: Optional[int] = None\n    body : Dict\n\n\nclass ActionsResponse(Actions):\n    id: int\n    enable: Optional[bool] =True\n\nclass ActionsUpdate(BaseModel):\n    name: Optional[str] = None\n    description: Optional[str] = None\n    types: Optional[str] = None\n    condition: Optional[Dict] = None\n    table : Optional[str] = None\n    connector_id: Optional[int] = None\n    body : Optional[Dict] = None\n\nclass LLMProviderBase(BaseModel):\n    key:str\n    api_key:str\n    kind:Optional[str]=None\n    unique_name: Optional[str]=None"
  },
  {
    "path": "app/schemas/environment.py",
    "content": "from pydantic import BaseModel\nfrom datetime import datetime\nfrom typing import Optional\n\nclass EnvironmentBase(BaseModel):\n    name: str\n\nclass EnvironmentResponse(EnvironmentBase):\n    id: int\n    is_active: bool \n\nclass UserEnvironmentMappingBase(BaseModel):\n    user_id: int\n    environment_id: int\n\nclass UserEnvironmentMappingResponse(UserEnvironmentMappingBase):\n    id: int"
  },
  {
    "path": "app/schemas/llmchat.py",
    "content": "from pydantic import BaseModel\nfrom typing import Optional, Dict\nfrom datetime import datetime\n\n\nclass ChatHistoryBase(BaseModel):\n    chat_context_id: str\n    chat_query: str\n    chat_answer: dict\n    chat_summary: str\n    chat_status: Optional[int]=None\n    feedback_status: Optional[int]=None\n    feedback_json: Optional[dict] = None\n    user_id: Optional[int]=None\n    primary_chat: Optional[bool]=False\n    configuration_id: Optional[int]=None\n    environment_id: Optional[int]=None\n\nclass ChatHistoryCreate(ChatHistoryBase):\n    pass\n\n\nclass ChatHistory(ChatHistoryBase):\n    chat_id: int\n\n\nclass ChatResponse(ChatHistory):\n    created_at: datetime\n    updated_at: Optional[datetime] = None\n\nclass FeedbackCreate(BaseModel):\n    chat_context_id: str\n    chat_id: int\n    feedback_status: int\n    feedback_json: Optional[Dict] = None\n\nclass ListPrimaryContext(BaseModel):\n    chat_context_id: str\n    chat_query: str\n    chat_answer: Dict\n    user_id: int\n    primary_chat: bool\n"
  },
  {
    "path": "app/schemas/provider.py",
    "content": "from pydantic import BaseModel\nfrom typing import List, Optional, Any, Dict\nfrom datetime import datetime\n\n\nclass ProviderConfigBase(BaseModel):\n    name: str\n    description: str\n    field: str\n    slug: str\n    provider_id: int\n    config_type:int\n    order:int\n    required:bool\n    value:Any\n\nclass ProviderConfigResponse(ProviderConfigBase):\n    id: int\n\nclass ProviderBase(BaseModel):\n    name: str\n    description: str\n    icon: str\n    category_id: int\n    enable: Optional[bool] = True\n\nclass ProviderResp(ProviderBase):\n    id:int\n    key: str\n    configs: List[ProviderConfigResponse]\n\nclass ProviderCreate(ProviderBase):\n    pass\n\nclass ProviderUpdate(ProviderBase):\n    pass\n\nclass ProviderInDBBase(ProviderBase):\n    id: int\n    created_at: datetime\n    updated_at: Optional[datetime] = None\n    deleted_at: Optional[datetime] = None\n\n\nclass Provider(ProviderInDBBase):\n    pass\n\nclass ProviderList(BaseModel):\n    providers: List[Provider]\n\n\nclass CategoryBase(BaseModel):\n    name: str\n    description: str\n    enable: Optional[bool] = True\n\nclass CategoryResponse(CategoryBase):\n    id: int\n\n\nclass CategoryCreate(CategoryBase):\n    pass\n\nclass CategoryList(BaseModel):\n    categories: List[CategoryResponse]\n\n\nclass ProviderConfigBase(BaseModel):\n    name: str\n    description: str\n    field: str\n    slug: str\n    enable: Optional[bool] = True\n    provider_id: int\n\nclass ProviderConfigResponse(ProviderConfigBase):\n    id: int\n\nclass ProviderConfigList(BaseModel):\n    category: List[ProviderConfigResponse]\n\n\n\nclass TestCredentials(BaseModel):\n    provider_config: Dict[str, Any]\n    connector_name: str\n\nclass TestVectorDBCredentials(BaseModel):\n    vectordb_config: Dict[str, Any]\n    embedding_config: Optional[Dict[str, Any]] = None\n\nclass SampleSQLBase(BaseModel):\n    description: str\n    sql_metadata: Optional[Dict] = None\n    connector_id: int\n\nclass SampleSQLUpdate(BaseModel):\n    description: Optional[str] = None\n    sql_metadata: Optional[Dict] = None\n    connector_id: Optional[int] = None\n\nclass SampleSQLResponse(SampleSQLBase):\n    id: int\n\nclass CredentialsHelper(BaseModel):\n    provider_config: Dict[str, Any]\n\n\nclass VectorDBConfigBase(BaseModel):\n    name: str\n    description: str\n    key: str\n    icon: str\n    config: List[Dict[str,Any]]\n\nclass VectorDBConfigResponse(VectorDBConfigBase):\n    id: int\n\nclass VectorDBUpdateBase(BaseModel):\n    vectordb: Optional[str] = None\n    vectordb_config : Optional[Dict[str,Any]] = None\n    config_id: Optional[int] = None\n    embedding_config: Optional[Dict[str,Any]] = None\n\nclass VectorDBBase(BaseModel):\n    vectordb: Optional[str] = None\n    vectordb_config : Optional[Dict[str,Any]] = None\n    config_id: int\n    embedding_config: Optional[Dict[str,Any]] = None\n\n\nclass VectorDBResponse(VectorDBBase):\n    id: int\n"
  },
  {
    "path": "app/schemas/user.py",
    "content": "from datetime import datetime\nfrom typing import Optional\nfrom pydantic import BaseModel\n\nclass UserBase(BaseModel):\n    id: int\n    username: str\n\nclass UserResponse(UserBase):\n    role: Optional[str] = None\n    created_at: Optional[datetime] = None\n    updated_at: Optional[datetime] = None\n\nclass UserCreate(UserBase):  # Used when creating a new user\n    pass\n\n\n"
  },
  {
    "path": "app/services/connector.py",
    "content": "from sqlalchemy.orm import Session\nimport app.repository.connector as repo\nimport app.repository.provider as config_repo\nimport app.schemas.connector as schemas\nfrom app.services import provider as provider_svc\nfrom app.schemas.provider import VectorDBResponse\nimport requests\nimport os\nimport uuid\nfrom loguru import logger\nfrom app.services.connector_details import get_plugin_metadata\nfrom fastapi import Request\nfrom app.providers.data_preperation import SourceDocuments\nfrom app.loaders.base_loader import BaseLoader\n\n\n\n\n\ndef list_connectors(db: Session, user_id: str):\n\n    \"\"\"\n    Retrieves all connector records from the database.\n\n    Args:\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: List of connector responses and error message (if any).\n    \"\"\"\n\n    connectors, is_error = repo.get_all_connectors(db, user_id)\n\n    if is_error:\n        return connectors, \"DB Error\"\n\n    if not connectors:\n        return [], None\n\n    connectors_response = [schemas.ConnectorResponse(\n        connector_id=connector.id,\n        connector_type=connector.connector_type,\n        connector_name=connector.connector_name,\n        connector_description=connector.connector_description,\n        connector_config=connector.connector_config,\n        schema_config=connector.schema_config,\n        connector_docs=connector.connector_docs,\n        connector_key=connector.provider.key,\n        enable=connector.enable,\n        icon=connector.provider.icon,\n        provider_id=connector.provider.category_id\n    ) for connector in connectors]\n\n    return connectors_response, None\n\ndef list_connectors_by_provider_category(category_ids: int, db: Session, user_id: str):\n    \"\"\"\n    Retrieves all connector records from the database filtered by provider category.\n\n    Args:\n        category_id (int): The ID of the provider category.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: List of connector responses and error message (if any).\n    \"\"\"\n    connectors, error = list_connectors(db, user_id)\n\n    if error:\n        return [], error\n\n    filtered_connectors = []\n    for category_id in category_ids:\n        filtered_connectors.extend([connector for connector in connectors if connector.provider_id == category_id])\n\n    return filtered_connectors, None\n\n\n\ndef get_connector(connector_id: int, db: Session):\n\n    \"\"\"\n    Retrieves the details of a specific connector by its ID.\n\n    Args:\n        connector_id (int): The ID of the connector.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: Connector response and error message (if any).\n\n    \"\"\"\n\n\n    connector, is_error = repo.get_connector_by_id(connector_id, db)\n\n    if is_error:\n        return connector, \"DB Error\"\n\n    if connector is None:\n        return [], None\n\n    connector_response = schemas.ConnectorResponse(\n        connector_id=connector.id,\n        connector_type=connector.connector_type,\n        connector_name=connector.connector_name,\n        connector_description=connector.connector_description,\n        connector_config=connector.connector_config,\n        connector_key=connector.provider.key,\n        schema_config=connector.schema_config,\n        connector_docs=connector.connector_docs,\n        enable=connector.enable,\n        icon=connector.provider.icon\n    )\n\n    return connector_response, None\n\ndef download_and_save_pdf(connector_name: str, url: str) -> str:\n\n    \"\"\"\n    Downloads the PDF from the specified URL and saves it to the assets directory.\n\n    Args:\n        connector_name (str): Name of the connector.\n        url (str): URL of the PDF to download.\n\n        Returns:\n            str: Path of the saved PDF file.\n            str: Error message (if any).\n    \"\"\"\n\n\n    response = requests.get(url)\n    connector_name = connector_name.replace(\" \", \"_\")\n    file_path = f\"./assets/source_{connector_name}.pdf\"\n    with open(file_path, 'wb') as file:\n        file.write(response.content)\n    return file_path\n\nasync def fileValidation(file):\n\n    \"\"\"\n    Validates the uploaded file for format and size constraints.\n\n    Args:\n        file (UploadFile): The uploaded document file.\n\n    Returns:\n        Tuple[str, int]: An error message if validation fails, or the size of the file if it passes.\n    \"\"\"\n\n    if not file.filename.endswith((\".pdf\", \".txt\", \".yaml\", \".docx\",\".csv\")):\n        return \"Invalid file format\", None\n\n    content = await file.read()\n    file_size = len(content)\n\n    await file.seek(0)\n\n    max_file_size_bytes = 100 * 1024 * 1024\n    if file_size > max_file_size_bytes:\n        return \"File size exceeds the limit\", None\n\n    return None, file_size\n\n\nasync def upload_pdf(file):\n    \"\"\"\n    Uploads a document file to the specified connector.\n\n    Args:\n        file (UploadFile): The uploaded document file.\n\n    Returns:\n        Tuple: Connector response and error message (if any).\n    \"\"\"\n\n    uuid_str = str(uuid.uuid4())\n    file_path = f\"./assets/datasource/documents/{uuid_str}/{file.filename}\"\n\n    try:\n        os.makedirs(os.path.dirname(file_path), exist_ok=True)\n        with open(file_path, 'wb') as f:\n            f.write(await file.read())\n\n        return {\"file_path\": file_path,\"file_id\":uuid_str}, None\n    except Exception as e:\n        return None, f\"Failed to write file: {str(e)}\"\n\n\ndef create_connector(connector: schemas.ConnectorBase, db: Session, user_id: str):\n\n    \"\"\"\n    Creates a new connector record in the database.\n\n    Args:\n        connector (ConnectorBase): The data for the new connector.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Connector response and error message (if any).\n    \"\"\"\n\n    provider, is_error = config_repo.get_provider_by_id(connector.connector_type, db)\n    if is_error:\n        return provider, \"DB Error\"\n\n    provider_configs, is_error = config_repo.get_config_types(connector.connector_type, db)\n\n    if is_error:\n        return None, \"DB Error\"\n\n    match provider.category_id:\n        case 2 | 5:\n            logger.info(\"creating plugin with category database\")\n            schema_details, is_error = get_plugin_metadata(provider_configs, connector.connector_config, connector.connector_name, provider.key)\n            if is_error is None:\n                connector.schema_config = schema_details\n            else:\n                return None, \"Failed to create connector\"\n        case 1:\n            logger.info(\"creating plugin with category remote documents\")\n        case 4:\n            logger.info(\"creating plugin with category offline documents\")\n        case _:\n            return None, \"Invalid Connector Type.\"\n\n    new_connector, is_error = repo.create_new_connector(connector, db, user_id)\n    if is_error:\n        return None, \"Failed to create connector\"\n\n    connector_response = schemas.ConnectorResponse(\n                connector_id=new_connector.id,\n                connector_type=new_connector.connector_type,\n                connector_name=new_connector.connector_name,\n                connector_description=new_connector.connector_description,\n                connector_config=new_connector.connector_config,\n                connector_key=new_connector.provider.key,\n                schema_config=new_connector.schema_config,\n                connector_docs=new_connector.connector_docs,\n                enable=new_connector.enable\n            )\n\n    return connector_response, None\n\n\n\ndef update_connector(connector_id: int, connector: schemas.ConnectorUpdate, db: Session):\n\n    \"\"\"\n    Updates an existing connector based on its ID.\n\n    Args:\n        connector_id (int): The ID of the connector to update.\n        connector (ConnectorUpdate): The updated data for the connector.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Connector response and error message (if any).\n    \"\"\"\n\n    updated_connector, is_error = repo.update_existing_connector(connector_id, connector, db)\n\n    if is_error:\n        return updated_connector, \"DB Error\"\n\n    if updated_connector is None:\n        return [], None\n\n    connector_response = schemas.ConnectorResponse(\n        connector_id=updated_connector.id,\n        connector_type=updated_connector.connector_type,\n        connector_name=updated_connector.connector_name,\n        connector_description=updated_connector.connector_description,\n        connector_config=updated_connector.connector_config,\n        schema_config=updated_connector.schema_config,\n        connector_docs=updated_connector.connector_docs,\n        enable=updated_connector.enable\n    )\n\n    return connector_response, None\n\ndef delete_connector(connector_id: int, db: Session):\n\n    \"\"\"\n    Deletes a connector based on its ID.\n\n    Args:\n        connector_id (int): The ID of the connector to delete.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Connector response and error message (if any).\n\n    \"\"\"\n\n    deleted_connector, is_error = repo.delete_connector_by_id(connector_id, db)\n\n    if is_error:\n        return deleted_connector, \"DB Error\"\n\n    if deleted_connector is None:\n        return [], None\n\n    connector_response = schemas.ConnectorResponse(\n        connector_id=deleted_connector.id,\n        connector_type=deleted_connector.connector_type,\n        connector_name=deleted_connector.connector_name,\n        connector_description=deleted_connector.connector_description,\n        connector_config=deleted_connector.connector_config,\n        schema_config=deleted_connector.schema_config,\n        connector_docs=deleted_connector.connector_docs,\n        enable=deleted_connector.enable\n    )\n\n    return connector_response, None\n\n\ndef updateschemas(connector_id: int, connector: schemas.SchemaUpdate, db: Session):\n\n    \"\"\"\n    Updates the schema configuration for a connector.\n\n    Args:\n        connector_id (int): The ID of the connector.\n        connector (SchemaUpdate): The updated schema configuration for the connector.\n        db (Session): Database session dependency.\n    Returns:\n        Tuple: Schema update response and error message (if any).\n\n    \"\"\"\n\n    updated_connector, is_error = repo.update_existing_connector(connector_id, connector, db)\n\n    if is_error:\n        return updated_connector, \"DB Error\"\n\n    if updated_connector is None:\n        return [], None\n\n    connector_response = schemas.SchemaUpdate(\n        schema_config=updated_connector.schema_config,\n    )\n\n    return connector_response, None\n\n\ndef get_inference_by_config_id(config_id:int , db:Session):\n    \"\"\"\n    Retrieves the inference configuration based on the configuration ID.\n\n    Args:\n        config_id (int): The ID of the configuration.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Inference configuration response and error message (if any).\n    \"\"\"\n\n    inference_mapping, is_error = repo.get_inference_by_config(config_id, db)\n\n    if is_error:\n        return inference_mapping, \"DB Error\"\n\n    if inference_mapping is None:\n        return schemas.InferenceResponse(), None\n\n    return schemas.InferenceResponse(\n        id=inference_mapping.inference.id,\n        name=inference_mapping.inference.name,\n        apikey=inference_mapping.inference.apikey,\n        config_id=inference_mapping.inference.config_id,\n        llm_provider=inference_mapping.inference.llm_provider,\n        model=inference_mapping.inference.model,\n        endpoint=inference_mapping.inference.endpoint,\n    ), None\n\n\ndef list_configurations(db: Session, user_id: str):\n\n    \"\"\"\n    Retrieves all configurations from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: List of configuration responses and error message (if any).\n    \"\"\"\n\n    configurations, is_error = repo.get_all_configurations(db, user_id)\n\n    if is_error:\n        return configurations, \"DB Error\"\n\n    if not configurations:\n        return [], None\n\n    config_list = [schemas.ConfigurationResponse(\n        id=config.id,\n        name=config.name,\n        short_description=config.short_description,\n        long_description=config.long_description,\n        status=config.status,\n        capabilities=[schemas.CapabilitiesBase(\n            id=capabilities.id,\n            name=capabilities.name,\n            requirements=capabilities.requirements,\n            description=capabilities.description,\n            config_id=capabilities.config_id,\n        ) for capabilities in config.capabilities],\n        inference=[schemas.InferenceResponse(\n            id=inference_mapping.inference.id,\n            name=inference_mapping.inference.name,\n            apikey=inference_mapping.inference.apikey,\n            llm_provider=inference_mapping.inference.llm_provider,\n            model=inference_mapping.inference.model,\n            endpoint=inference_mapping.inference.endpoint,\n            config_id=inference_mapping.config_id\n        ) for inference_mapping in config.inference_mapping],\n        vectordb=[VectorDBResponse(\n            id= vector_db.vector_db.id,\n            vectordb=vector_db.vector_db.vectordb,\n            vectordb_config=vector_db.vector_db.vectordb_config,\n            config_id=config.id,\n        ) for vector_db in config.vectordb_config_mapping if vector_db.vector_db]\n    ) for config in configurations]\n\n    return config_list, None\n\ndef get_configuration(db: Session, config_id: int):\n    \"\"\"\n    Retrieves a configuration by its ID.\n\n    Args:\n        db (Session): Database session dependency.\n        config_id (int): ID of the configuration to retrieve.\n\n    Returns:\n        Tuple: Configuration response and error message (if any).\n    \"\"\"\n    configuration, is_error = repo.get_configuration_by_id(config_id, db)\n\n    if is_error:\n        return configuration, \"DB Error\"\n\n    if not configuration:\n        return None, \"Configuration not found\"\n\n    config_response = schemas.ConfigurationResponse(\n        id=configuration.id,\n        name=configuration.name,\n        short_description=configuration.short_description,\n        long_description=configuration.long_description,\n        status=configuration.status,\n        connector=[\n            schemas.ConnectorResponse(\n                connector_id=connector.connector.id,\n                connector_type=connector.connector.connector_type,\n                connector_name=connector.connector.connector_name,\n                connector_description=connector.connector.connector_description,\n                connector_config=connector.connector.connector_config,\n                schema_config=connector.connector.schema_config,\n                connector_docs=connector.connector.connector_docs,\n                enable=connector.connector.enable\n            ) for connector in configuration.connectors\n        ],\n        capabilities=[\n            schemas.CapabilitiesBase(\n                id=capabilities.id,\n                name=capabilities.name,\n                requirements=capabilities.requirements,\n                description=capabilities.description,\n                config_id=capabilities.config_id,\n            ) for capabilities in configuration.capabilities\n        ],\n        inference=[\n            schemas.InferenceResponse(\n                id=inference_mapping.inference.id,\n                name=inference_mapping.inference.name,\n                apikey=inference_mapping.inference.apikey,\n                llm_provider=inference_mapping.inference.llm_provider,\n                model=inference_mapping.inference.model,\n                endpoint=inference_mapping.inference.endpoint,\n                config_id=inference_mapping.config_id\n            ) for inference_mapping in configuration.inference_mapping\n        ],\n        vectordb=[\n            VectorDBResponse(\n                id=vector_db.vector_db.id,\n                vectordb=vector_db.vector_db.vectordb,\n                vectordb_config=vector_db.vector_db.vectordb_config,\n                config_id=configuration.id,\n            ) for vector_db in configuration.vectordb_config_mapping if vector_db.vector_db\n        ]\n    )\n\n    return config_response, None\n\ndef delete_configuration(db: Session, config_id: int):\n    \"\"\"\n    Deletes a configuration by its ID.\n\n    Args:\n        db (Session): Database session dependency.\n        config_id (int): ID of the configuration to retrieve.\n\n    Returns:\n        Tuple: Configuration response and error message (if any).\n    \"\"\"\n    configuration, is_error = repo.delete_configuration_by_id(config_id, db)\n\n    if is_error:\n        return configuration, \"DB Error\"\n\n    if not configuration:\n        return None, \"Configuration not found\"\n\n    config_response = schemas.ConfigurationResponse(\n        id=configuration.id,\n        name=configuration.name,\n        short_description=configuration.short_description,\n        long_description=configuration.long_description,\n        status=configuration.status,\n        capabilities=[\n            schemas.CapabilitiesBase(\n                id=capabilities.id,\n                name=capabilities.name,\n                requirements=capabilities.requirements,\n                description=capabilities.description,\n                config_id=capabilities.config_id,\n            ) for capabilities in configuration.capabilities\n        ],\n    )\n\n    return config_response, None\n\n\ndef create_configuration(configuration: schemas.ConfigurationCreation, db: Session, user_id: str):\n\n    \"\"\"\n    Creates a new configuration in the database.\n\n    Args:\n        configuration (ConfigurationCreation): The data for the new configuration.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Configuration response and error message (if any).\n    \"\"\"\n\n    new_config, is_error = repo.create_new_configuration(configuration, db, user_id)\n    if is_error:\n        return new_config, \"DB Error\"\n\n    if not new_config:\n        return [], None\n\n\n\n    config_response = schemas.ConfigurationResponse(\n        id=new_config.id,\n        name=new_config.name,\n        short_description=new_config.short_description,\n        long_description=new_config.long_description,\n        status=new_config.status,\n        capabilities=[schemas.CapabilitiesBase(\n            id=capabilities.id,\n            name=capabilities.name,\n            requirements=capabilities.requirements,\n            description=capabilities.description,\n            config_id=capabilities.config_id,\n        ) for capabilities in new_config.capabilities],\n    )\n\n    return config_response, None\n\ndef update_configuration(config_id: int, configuration: schemas.ConfigurationUpdate, db: Session):\n\n    \"\"\"\n    Updates an existing configuration based on its ID.\n\n    Args:\n        config_id (int): The ID of the configuration to update.\n        configuration (ConfigurationUpdate): The updated data for the configuration.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Configuration response and error message (if any).\n    \"\"\"\n\n    updated_config, is_error = repo.update_existing_configuration(config_id, configuration, db)\n\n    if is_error:\n        return updated_config, \"DB Error\"\n\n    if updated_config is None:\n        return [], None\n\n    config_response = schemas.ConfigurationResponse(\n        id=updated_config.id,\n        name=updated_config.name,\n        short_description=updated_config.short_description,\n        long_description=updated_config.long_description,\n        status=updated_config.status,\n        capabilities=[schemas.CapabilitiesBase(\n            id=capabilities.id,\n            name=capabilities.name,\n            requirements=capabilities.requirements,\n            description=capabilities.description,\n            config_id=capabilities.config_id,\n        ) for capabilities in updated_config.capabilities],\n    )\n\n    return config_response, None\n\n\ndef create_capabilities(capabilities: schemas.CapabilitiesBase, db: Session):\n\n    \"\"\"\n    Creates a new capability in the database.\n\n    Args:\n        capabilities (CapabilitiesBase): The data for the new capability.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Capability response and error message (if any).\n    \"\"\"\n\n    new_capability, is_error = repo.create_capability(capabilities, db)\n\n    if is_error:\n        return new_capability, \"DB Error\"\n\n    if capabilities.actions_list:\n        result, is_mapping_error = repo.create_capability_action_mappings(\n            capability_id=new_capability.id,\n            action_ids=capabilities.actions_list,\n            db=db\n        )\n        if is_mapping_error:\n            return result, \"DB Error while creating capability-action mappings\"\n\n    capability_response = schemas.CapabilitiesBase(\n        id=new_capability.id,\n        name=new_capability.name,\n        description=new_capability.description,\n        requirements=new_capability.requirements,\n        config_id=new_capability.config_id,\n        actions=[{\n        \"id\": mapping.actions.id,\n        \"name\": mapping.actions.name,\n        \"description\": mapping.actions.description,\n        \"types\": mapping.actions.types,\n        \"table\": mapping.actions.table,\n        \"enable\": mapping.actions.enable,\n        } for mapping in new_capability.cap_actions_mapping]\n    )\n\n    return capability_response, None\n\n\ndef get_all_capabilities(db: Session):\n\n    \"\"\"\n    Retrieves all capabilities from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: List of capability responses and error message (if any).\n    \"\"\"\n\n    capabilities, is_error = repo.get_all_capabilities(db)\n\n    if is_error:\n        return capabilities, \"DB Error\"\n\n    if not capabilities:\n        return [], None\n\n    capabilities_response = []\n\n    for cap in capabilities:\n        capabilities_response.append(\n            schemas.CapabilitiesBase(\n                id=cap.id,\n                name=cap.name,\n                description=cap.description,\n                requirements=cap.requirements,\n                config_id=cap.config_id,\n                actions=[{\n                \"id\": mapping.actions.id,\n                \"name\": mapping.actions.name,\n                \"description\": mapping.actions.description,\n                \"types\": mapping.actions.types,\n                \"table\": mapping.actions.table,\n                \"enable\": mapping.actions.enable,\n                } for mapping in cap.cap_actions_mapping]\n            )\n        )\n\n    return capabilities_response, None\n\ndef update_capability(cap_id: int, capability: schemas.CapabilitiesUpdateBase, db: Session):\n\n    \"\"\"\n    Updates an existing capability based on its ID.\n\n    Args:\n        cap_id (int): The ID of the capability to update.\n        capability (CapabilitiesUpdateBase): The updated data for the capability.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Capability response and error message (if any).\n    \"\"\"\n\n    updated_capability, is_error = repo.update_capability(cap_id, capability, db)\n\n    if is_error:\n        return updated_capability, \"DB Error\"\n\n    if not updated_capability:\n        return [], None\n\n    capability_response = schemas.CapabilitiesBase(\n        id=updated_capability.id,\n        name=updated_capability.name,\n        description=updated_capability.description,\n        requirements=updated_capability.requirements,\n        config_id=updated_capability.config_id,\n        actions=[{\n            \"id\": mapping.actions.id,\n            \"name\": mapping.actions.name,\n            \"description\": mapping.actions.description,\n            \"types\": mapping.actions.types,\n            \"table\": mapping.actions.table,\n            \"enable\": mapping.actions.enable,\n            } for mapping in updated_capability.cap_actions_mapping]\n    )\n\n    return capability_response, None\n\ndef delete_capability(cap_id: int, db: Session):\n\n    \"\"\"\n    Deletes a capability from the database based on its ID.\n\n    Args:\n        cap_id (int): The ID of the capability to delete.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Boolean indicating whether the deletion was successful and error message (if any).\n    \"\"\"\n\n    deleted, is_error = repo.delete_capability(cap_id, db)\n\n    if is_error:\n        return deleted, \"DB Error\"\n\n    if not deleted:\n        return [], None\n\n    return True, None\n\n\ndef update_datasource_documentations(db: Session, vector_store, datasources, id_name_mappings, config_id, index):\n        logger.info(\"Updating datasource documentations\")\n        repo.update_configuration_status(config_id, 1, db)\n        active_datsources = {}\n        vector_store.clear_collection(config_id)\n        for key, datasource in datasources.items():\n            connector_details = id_name_mappings.get(key, {})\n            if \"id\" not in connector_details:\n                logger.warning(\"Connector not found\")\n                continue\n\n            logger.info(f\"initialising datasource {key}\")\n            logger.info(\"mappings connector_details, id:{}\".format(connector_details[\"id\"]))\n\n            datasource.connect()\n            success, err = datasource.healthcheck()\n            if not success:\n                logger.error(f\"Datasource health failed for {key}, cause: {err}\")\n                logger.warning(f\"skipping datasource initialization for {key}\")\n                continue\n\n            active_datsources[key] = datasource\n            logger.info(\"Pushing plugin metadata to vector store\")\n\n            sd = SourceDocuments([], [], [])\n            queries = []\n            if index:\n                match datasource.__category__:\n                    case 1:\n                        documentations = datasource.fetch_data()\n                        sd = SourceDocuments([], [], documentations)\n                    case 2 | 5:\n                        schema_config = connector_details.get(\"schema_config\",[])\n                        schema_details, metadata = datasource.fetch_schema_details()\n                        sd = SourceDocuments(schema_details, schema_config, [])\n                        queries = get_all_connector_samples(connector_details.get(\"id\"), db)\n                    case 4:\n                        documentations = datasource.fetch_data()\n                        sd = SourceDocuments([], [], documentations)\n\n                chunked_document, chunked_schema = sd.get_source_documents()\n                vector_store.prepare_data(key, chunked_document,chunked_schema, queries, int(config_id))\n        \n        \n        repo.update_configuration_status(config_id, 2, db)\n        return active_datsources, None\n\ndef get_inference_and_plugin_configurations(db: Session, config_id: int):\n\n    \"\"\"\n    Retrieves all inference and plugin configurations from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Configuration response and error message (if any).\n    \"\"\"\n\n    configuration={}\n    connectors, status = repo.get_connectors_by_configuration_id(config_id, db)\n    if status:\n        return configuration\n    configs, is_error = repo.get_configuration_by_id(config_id, db)\n    if configs is None:\n        configuration[\"models\"]=[]\n    else:\n        inference, is_error = create_inference_yaml(configs.id, db)\n        configuration[\"models\"] = inference\n\n    datasources = []\n    mappings  = {}\n\n    for conn in connectors:\n        provider, is_error = config_repo.get_provider_by_id(conn.connector_type, db)\n        if is_error:\n            continue\n        datasource = formatting_datasource(conn, provider)\n        if datasource:\n\n            datasource['name'] = str(conn.connector_name).replace(\" \", \"_\").lower()\n            mappings[datasource['name']] = {\n                \"id\": conn.id,\n                \"schema_config\": conn.schema_config\n            }\n            datasource['description'] = conn.connector_description\n            datasources.append(datasource)\n    configuration[\"datasources\"] = datasources\n    configuration[\"mappings\"] = mappings\n    return configuration\n\ndef create_inference_yaml(config_id:int, db:Session):\n\n    \"\"\"\n    Creates a YAML file for inference configurations based on the given configuration ID.\n\n    Args:\n        config_id (int): The ID of the configuration.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: List of inference configurations and error message (if any).\n    \"\"\"\n\n    inference, is_error = repo.get_inferences_by_config_id(config_id, db)\n\n    if is_error:\n        return inference, \"Inference configuration not found\"\n\n    inference_yaml = []\n\n    for inf in inference:\n        model_data = {\n            \"unique_name\": inf.inference.name,\n            \"name\": inf.inference.model,\n            \"api_key\": inf.inference.apikey,\n            \"endpoint\": inf.inference.endpoint,\n            \"kind\": inf.inference.llm_provider,\n        }\n        inference_yaml.append(model_data)\n\n    return inference_yaml, None\n\ndef get_all_connector_samples(connector_id: int, db: Session):\n    sqls, is_error = provider_svc.getsqlbyconnector(connector_id, db)\n\n    if is_error:\n        logger.error(f\"Error getting SQL from connector {connector_id}:{is_error}\")\n\n\n    queries = []\n    for sql in sqls:\n        queries.append({\n                \"description\": sql.description,\n                \"metadata\": sql.sql_metadata\n            })\n    return queries\n\n\ndef create_yaml_file(request:Request, config_id: int, db: Session):\n\n    \"\"\"\n    Creates a YAML file for configurations based on the given configuration ID.\n\n    Args:\n        request (Request): Request object for logging purposes.\n        config_id (int): The ID of the configuration.\n        db (Session): Database session dependency.\n    Returns:\n    Tuple: Configuration YAML and error message (if any).\n\n    \"\"\"\n\n    configuration, is_error = repo.get_configuration_by_id(config_id, db)\n    if (configuration == [] or configuration==None) or is_error:\n        return None, None, \"Configuration Not Found\"\n\n    inferences, is_error = repo.get_inferences_by_config_id(config_id, db)\n    if (inferences == [] or inferences==None) or is_error:\n        return None, None, \"Inference configuration not found\"\n\n    connectors, is_error = repo.get_connectors_by_configuration_id(config_id, db)\n    if (connectors == [] or connectors==None) or is_error:\n        return None, None, \"Connector not found\"\n\n    datasources = []\n    for conn in connectors:\n        provider, is_error = config_repo.get_provider_by_id(conn.connector_type, db)\n        if is_error:\n            continue\n\n        datasource = formatting_datasource(conn, provider)\n        if datasource:\n            datasource['name'] = str(conn.connector_name).replace(\" \", \"_\").lower()\n            datasource['description'] = conn.connector_description\n            datasource['mappings'] =  {\"id\": conn.id, \"schema_config\":conn.schema_config}\n            datasources.append(datasource)\n\n    use_case = dict({\n        'short_description': configuration.short_description,\n        'long_description': configuration.long_description,\n        'capabilities': [\n                {\n                \"name\": cap.name if cap.name else \"default\",\n                \"description\": cap.description if cap.description else \"No description provided\",\n                \"requirements\": cap.requirements if cap.requirements else [],\n                \"analysis\": [],\n                \"action\": {}\n                } for cap in configuration.capabilities\n         ]\n    })\n\n    return datasources, use_case, None\n\n\n\ndef formatting_datasource(connector, provider):\n\n    \"\"\"\n    Formats the datasource based on the provider category.\n\n    Args:\n        connector (Connector): The connector object.\n        provider (Provider): The provider object.\n\n    Returns:\n        dict: Formatted datasource or None if the provider category is not recognized.\n    \"\"\"\n\n    if provider.category_id == 1:\n        return {\n            'type': provider.key,\n            'params': connector.connector_config,\n            'documentations': [{'type': 'text', 'value': connector.connector_docs}]\n        }\n    elif provider.category_id == 2 or provider.category_id == 5:\n        return {\n            'type': provider.key,\n            'params': connector.connector_config,\n            'documentations': [{'type': 'text', 'value': connector.connector_docs}]\n        }\n    elif provider.category_id == 4:\n        return {\n            'type': provider.key,\n            'params': connector.connector_config\n        }\n    else:\n        return None\n\ndef get_llm_provider_models(llm_provider: schemas.LLMProviderBase):\n    \"\"\"\n    Retrieves the models available for a given LLM provider.\n    Args:\n        llm_provider (schemas.LLMProviderBase): The LLM provider object.\n    Returns:\n        Tuple: List of models and error message (if any).\n    \"\"\"\n    if llm_provider.key:\n        llm_provider.kind = llm_provider.key\n        llm_provider.unique_name = llm_provider.key\n        return BaseLoader(model_configs=[dict(llm_provider)]).load_model(unique_name=llm_provider.key).get_models()\n    else:\n        return None, \"Missing LLM provider key\"\n\ndef get_inference(inference_id: int, db: Session):\n\n    \"\"\"\n    Retrieves an inference from the database based on its ID.\n\n    Args:\n        inference_id (int): The ID of the inference.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Inference response and error message (if any).\n    \"\"\"\n\n    inference, is_error = repo.get_inference_by_id(inference_id, db)\n\n    if is_error:\n        return inference, \"DB Error\"\n\n    if inference is None:\n        return [], None\n\n    data = schemas.InferenceResponse(\n        name=inference.name,\n        apikey=inference.apikey,\n        model=inference.model,\n        endpoint=inference.endpoint,\n        llm_provider=inference.llm_provider,\n        id=inference.id\n    )\n\n    return data, None\n\ndef create_inference(inference: schemas.InferenceBase, db: Session):\n\n    \"\"\"\n    Creates a new inference in the database.\n\n    Args:\n        inference (schemas.InferenceBase): The inference object to be created.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Inference response and error message (if any).\n    \"\"\"\n\n    inference_created, is_error = repo.create_inference(inference, db)\n\n    if is_error:\n        return inference_created, \"DB Error\"\n\n    data = schemas.InferenceResponse(\n        name=inference_created.name,\n        apikey=inference_created.apikey,\n        model=inference_created.model,\n        endpoint=inference_created.endpoint,\n        llm_provider=inference_created.llm_provider,\n        id=inference_created.id\n    )\n\n    return data, None\n\ndef update_inference(inference_id: int, inference: schemas.InferenceBaseUpdate, db: Session):\n\n    \"\"\"\n    Updates an inference in the database based on its ID.\n\n    Args:\n        inference_id (int): The ID of the inference to be updated.\n        inference (schemas.InferenceBaseUpdate): The inference object with updated values.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Inference response and error message (if any).\n    \"\"\"\n\n    updated_inference, is_error = repo.update_inference(inference_id, inference, db)\n\n    if is_error:\n        return updated_inference, \"DB Error\"\n\n    if updated_inference is None:\n        return [], None\n\n    data = schemas.InferenceResponse(\n        name=updated_inference.name,\n        apikey=updated_inference.apikey,\n        model=updated_inference.model,\n        endpoint=updated_inference.endpoint,\n        llm_provider=updated_inference.llm_provider,\n        id=updated_inference.id\n    )\n\n    return data, None\n\ndef list_actions(db:Session):\n\n    \"\"\"\n    Retrieves all actions from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: List of actions and error message (if any).\n    \"\"\"\n\n    actions, is_error = repo.list_actions(db)\n\n    if is_error:\n        return actions, \"DB Error\"\n\n    if actions is None:\n        return [], None\n\n    return [\n        schemas.ActionsResponse(\n            id=action.id,\n            name=action.name,\n            description=action.description,\n            types=action.types,\n            condition=action.condition,\n            table = action.table,\n            connector_id=action.connector_id,\n            body = action.body,\n            enable = action.enable,\n            ) for action in actions], False\n\ndef get_actions(action_id:int, db:Session):\n\n    \"\"\"\n    Retrieves an action from the database based on its ID.\n\n    Args:\n        action_id (int): The ID of the action.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Action response and error message (if any).\n    \"\"\"\n\n    action, is_error = repo.get_action_by_id(action_id, db)\n\n    if is_error:\n        return action, \"DB Error\"\n\n    if action is None:\n        return [], None\n\n    return schemas.ActionsResponse(\n        id=action.id,\n        name=action.name,\n        description=action.description,\n        types=action.types,\n        condition=action.condition,\n        table = action.table,\n        connector_id=action.connector_id,\n        enable = action.enable,\n        body = action.body,\n    ), False\n\ndef get_actions_by_connector(connector_id:int, db:Session):\n\n    \"\"\"\n    Retrieves all actions associated with a specific connector from the database.\n\n    Args:\n        connector_id (int): The ID of the connector.\n        db (Session): Database session dependency.\n    Returns:\n        Tuple: List of actions and error message (if any).\n    \"\"\"\n\n    actions, is_error = repo.get_actions_by_connector(connector_id, db)\n\n    if is_error:\n        return actions, \"DB Error\"\n\n    if actions is None:\n        return [], None\n\n    return [\n        schemas.ActionsResponse(\n            id=action.id,\n            name=action.name,\n            description=action.description,\n            types=action.types,\n            condition=action.condition,\n            table = action.table,\n            connector_id=action.connector_id,\n            enable = action.enable,\n            body = action.body,\n            ) for action in actions], False\n\ndef create_action(action: schemas.Actions, db:Session):\n\n    \"\"\"\n    Creates a new action in the database.\n\n    Args:\n        action (schemas.Actions): The action object to be created.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Action response and error message (if any).\n    \"\"\"\n\n    action_created, is_error = repo.create_action(action, db)\n\n    if is_error:\n        return action_created, \"DB Error\"\n\n    return schemas.ActionsResponse(\n        id=action_created.id,\n        name=action_created.name,\n        description=action_created.description,\n        types=action_created.types,\n        condition=action_created.condition,\n        table = action_created.table,\n        connector_id=action_created.connector_id,\n        enable = action_created.enable,\n        body = action.body,\n    ), False\n\n\ndef update_action(action_id: int, action: schemas.ActionsUpdate, db: Session):\n\n    \"\"\"\n    Updates an action in the database based on its ID.\n\n    Args:\n        action_id (int): The ID of the action to be updated.\n        action (schemas.ActionsUpdate): The action object with updated values.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Action response and error message (if any).\n    \"\"\"\n\n    updated_action, is_error = repo.update_action(action_id, action, db)\n\n    if is_error:\n        return updated_action, \"DB Error\"\n\n    if updated_action is None:\n        return [], None\n\n    return schemas.ActionsResponse(\n        id=updated_action.id,\n        name=updated_action.name,\n        description=updated_action.description,\n        types=updated_action.types,\n        condition=updated_action.condition,\n        table = updated_action.table,\n        connector_id=updated_action.connector_id,\n        enable = updated_action.enable,\n        body = updated_action.body,\n    ), False\n\n\ndef delete_action(action_id: int, db: Session):\n\n    \"\"\"\n    Deletes an action from the database based on its ID.\n\n    Args:\n        action_id (int): The ID of the action to be deleted.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: Action response and error message (if any).\n    \"\"\"\n\n    result, is_error = repo.delete_action_by_id(action_id, db)\n\n    if is_error:\n        return None, \"DB Error\"\n\n    return result, False\n\n\ndef get_use_cases(db: Session):\n\n    \"\"\"\n    Retrieves all use cases from the database.\n\n    Args:\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: List of use cases and error message (if any).\n\n    \"\"\"\n\n    configurations, status = repo.get_all_configurations(db)\n    use_cases = []\n    for conf in configurations:\n        use_case = {}\n        use_case['short_description'] = conf.short_description\n        use_case['long_description'] = conf.long_description\n        use_case['capabilities'] = []\n        capabilities = [cap for cap in conf.capabilities]\n        for cap in capabilities:\n            capability = {}\n            capability['name'] = cap.name\n            capability['description'] = cap.description\n            capability['requirements'] = cap.requirements\n            use_case['capabilities'].append(capability)\n        use_cases.append(use_case)\n\n    if len(use_cases) > 0:\n        return use_cases[0]\n    else:\n        return {\n            \"short_description\": \"\",\n            \"long_description\": \"\",\n            \"capabilities\": []\n        }\n\n"
  },
  {
    "path": "app/services/connector_details.py",
    "content": "from typing import  Any\nfrom app.plugins.loader import DSLoader\nfrom loguru import logger\n\nfrom app.repository import connector as repo\nfrom sqlalchemy.orm import Session\nfrom app.vectordb import chromadb, mongodb, loader\n\n\ndef test_plugin_connection(db_configs, config, provider_class):\n    params = {}\n    for conf in db_configs:\n        if conf.slug not in config.provider_config:\n            return None, f\"Missing required config key: {conf.slug}\"\n        else:\n            params[conf.field] = config.provider_config[conf.slug]\n\n    params = {\n        \"type\" : provider_class,\n        \"connector_name\" : config.connector_name,\n        \"params\": params,\n    }\n\n    datasource = DSLoader(params).load_ds()\n    success, err = datasource.connect()\n\n    if not success and err:\n        return None, f\"Test Credentials Failed: {str(err)}\"\n\n    success, err = datasource.healthcheck()\n    if not success and err:\n        return None, f\"Connection to {provider_class} is not established: {str(err)}\"\n\n    return True, \"Test Credentials successfully completed\"\n\ndef get_plugin_metadata(db_configs, config, connector_name, provider_class):\n\n    params = {}\n    for conf in db_configs:\n        if conf.slug not in config:\n            return {}, Exception(f\"Missing required config key: {conf.slug}\")\n        else:\n            params[conf.field] = config.get(conf.slug, \"\")\n    params = {\n        \"type\" : provider_class,\n        \"connector_name\" : connector_name,\n        \"params\": params,\n    }\n\n    datasource = DSLoader(\n            params\n        ).load_ds()\n\n    success, err=datasource.connect()\n\n    if not success and err:\n        return {}, Exception(\"Test Credentials Failed\")\n\n\n    success, err = datasource.healthcheck()\n    if not success and err:\n        logger.warning(\"Datasource health failed\")\n        return {}, Exception(\"Connection to \"+provider_class+\" is not established\")\n\n    schema_ddl, schema_config = datasource.fetch_schema_details()\n    if len(schema_config) > 0:\n        return schema_config, None\n    else:\n        return {}, Exception(\"Failed to fetch schema details\")\n\n\ndef check_configurations_availability(db: Session)-> Any:\n    conf, is_error = repo.getbotconfiguration(db)\n\n    if (conf == [] or conf==None) or is_error:\n        return \"Configuration Not Found\"\n\n    inference, is_error = repo.get_inference_by_id(conf.id,db)\n    if (inference == [] or inference==None) or is_error:\n        return \"Inference configuration not found\"\n\n    connectors, is_error = repo.get_all_connectors(db)\n    if (connectors == [] or connectors==None) or is_error:\n        return \"Connector not found\"\n\n    return None\n\n\ndef test_vector_db_credentials(db_config, config, key):\n    if isinstance(db_config.config, list):\n        configs = [i.get(\"slug\") for i in db_config.config if isinstance(i, dict)]\n        flag = any(con == d_conf for con in configs for d_conf in config.vectordb_config)\n\n        if not flag:\n            return f\"Missing required config key: {db_config.key}\", True\n\n        vectordb_config = config.vectordb_config.copy()\n        vectordb_config.pop(\"key\", None)\n        vectorloader = loader.VectorDBLoader(config={\"name\":db_config.key, \"params\":vectordb_config}).load_class()\n        err = vectorloader.connect()\n\n        if err is not None:\n            return f\"Failed to connect to {db_config.key}: {err}\", True\n\n        err = vectorloader.health_check()\n\n        if err is not None:\n            return f\"Failed to connect to {db_config.key}: {err}\", True\n\n    return f\"{db_config.key} Test Credential Successfully Completed\", False\n\n\n\n\n\n\n"
  },
  {
    "path": "app/services/llmchat.py",
    "content": "from sqlalchemy.orm import Session\nfrom app.repository import llmchat as repo\nfrom app.schemas import llmchat as schemas\n\n\ndef create_chat(chat: schemas.ChatHistoryCreate, db: Session):\n\n    \"\"\"\n    Creates a new chat record in the database.\n\n    Args:\n        chat (schemas.ChatHistoryCreate): Data required to create a new chat.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: Chat history schema and error message (if any).\n    \"\"\"\n\n    result, is_error = repo.create_new_chat(chat, db)\n\n    if is_error:\n        return result, \"DB Error\"\n\n    data = schemas.ChatHistory(\n        chat_context_id=result.chat_context_id,\n        chat_answer=result.chat_answer,\n        chat_id=result.chat_id,\n        chat_query=result.chat_query,\n        chat_status=result.chat_status,\n        chat_summary=result.chat_summary,\n        primary_chat=result.primary_chat,\n        feedback_json=result.feedback_json,\n        feedback_status=result.feedback_status,\n        user_id=result.user_id\n    )\n\n    return data, None\n\n\ndef create_feedback(feedback: schemas.FeedbackCreate, db: Session):\n\n    \"\"\"\n    Updates an existing chat record with feedback data.\n\n    Args:\n        feedback (schemas.FeedbackCreate): Feedback data to update the chat record.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: Updated chat history schema and error message (if any).\n    \"\"\"\n\n    result, is_error = repo.update_chat_feedback(feedback, db)\n\n    if is_error:\n        return result, \"DB Error\"\n\n    if result is None:\n        return [], None\n\n    data = schemas.ChatHistory(\n        chat_context_id=result.chat_context_id,\n        chat_answer=result.chat_answer,\n        chat_id=result.chat_id,\n        chat_query=result.chat_query,\n        chat_status=result.chat_status,\n        chat_summary=result.chat_summary,\n        primary_chat=result.primary_chat,\n        feedback_json=result.feedback_json,\n        feedback_status=result.feedback_status,\n        user_id=result.user_id\n    )\n\n    return data, None\n\n\ndef list_chats_by_context(env_id: int, db: Session):\n\n    \"\"\"\n    Retrieves the primary chat records from the database.\n\n    Args:\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: List of chat responses and error message (if any).\n    \"\"\"\n\n    result, is_error = repo.get_primary_chat(env_id, db)\n\n    if is_error:\n        return result, \"DB Error\"\n\n    if not result:\n        return [], None\n\n    chat_data = [\n        schemas.ChatResponse(\n            chat_context_id=chat.chat_context_id,\n            chat_answer=chat.chat_answer,\n            chat_id=chat.chat_id,\n            chat_query=chat.chat_query,\n            chat_status=chat.chat_status,\n            chat_summary=chat.chat_summary,\n            primary_chat=chat.primary_chat,\n            feedback_json=chat.feedback_json,\n            feedback_status=chat.feedback_status,\n            user_id=chat.user_id,\n            configuration_id=chat.configuration_id,\n            created_at=chat.created_at,\n            updated_at=chat.updated_at\n        ) for chat in result\n    ]\n\n    return chat_data, None\n\n\ndef list_all_chats_by_context_id(context_id: str, db: Session):\n\n    \"\"\"\n    Retrieves all chat records based on the context ID from the database.\n\n    Args:\n        context_id (str): The ID of the context to filter chats.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: List of chat responses and error message (if any).\n    \"\"\"\n\n    result, is_error = repo.get_all_chats_by_context_id(context_id, db)\n\n    if is_error:\n        return result, \"DB Error\"\n\n    if not result:\n        return [], None\n\n    chat_data = [\n        schemas.ChatResponse(\n            chat_context_id=chat.chat_context_id,\n            chat_answer=chat.chat_answer,\n            chat_id=chat.chat_id,\n            chat_query=chat.chat_query,\n            chat_status=chat.chat_status,\n            chat_summary=chat.chat_summary,\n            primary_chat=chat.primary_chat,\n            feedback_json=chat.feedback_json,\n            feedback_status=chat.feedback_status,\n            user_id=chat.user_id,\n            created_at=chat.created_at,\n            updated_at=chat.updated_at\n        ) for chat in result\n    ]\n\n    return chat_data, None\n\n"
  },
  {
    "path": "app/services/provider.py",
    "content": "from sqlalchemy.orm import Session\nimport app.repository.provider as repo\nimport app.schemas.provider as schemas\nimport app.schemas.connector as conn_schemas\nfrom app.services.connector_details import test_plugin_connection, test_vector_db_credentials\nfrom app.loaders.base_loader import BaseLoader\nfrom app.repository import connector as conn_repo\nfrom fastapi import Request\nfrom app.utils.module_reader import get_plugin_providers, get_vectordb_providers\nfrom app.models.provider import Provider, ProviderConfig, VectorDBConfig\nfrom loguru import logger\nfrom app.utils.module_reader import get_llm_providers, get_all_embedding\nfrom app.vectordb.loader import VectorDBLoader\nfrom app.embeddings.loader import EmLoader\n\ndef test_inference_credentials(inference: conn_schemas.InferenceBase):\n    \"\"\"\n    Tests the connection credentials for a specific LLM inference based on its provider.\n\n    Args:\n        inference (conn_schemas.InferenceBase):\n            A configuration object containing the provider details for testing the credentials.\n\n    Returns:\n        Tuple[bool, str]:\n            - (True, \"Test Credentials successfully completed\") if the credentials are valid and the test is successful.\n            - (None, error_message) if there was an error during the test or inference.\n            - (False, \"Unsupported Inference\") if the LLM provider is not recognized or unsupported.\n    \"\"\"\n\n    model_configs = [{\n        \"unique_name\": inference.name,\n        \"name\": inference.model,\n        \"api_key\": inference.apikey,\n        \"endpoint\": inference.endpoint,\n        \"kind\" : inference.llm_provider,\n    }]\n\n    try:\n        inference_model = BaseLoader(model_configs= model_configs).load_model(inference.name)\n    except Exception as error:\n        return None, str(error)\n\n    output, response_metadata = inference_model.do_inference(\n            \"hi\", []\n    )\n    if output['error'] is not None:\n        return None, output['error']\n    return True, \"Test Credentials successfully completed\"\n\ndef initialize_vectordb_provider(db:Session):\n    \"\"\"\n    Initializes the vector database by fetching the vector database data and inserting or updating\n    their details in the database.\n\n    Args:\n        db (Session): Database session used for performing transactions.\n    \"\"\"\n\n    vector_dbs = get_vectordb_providers()\n\n    for i in vector_dbs:\n        data, is_error = repo.insert_or_update_data(db,VectorDBConfig, {\"key\":i['vectordb_name']},{\n            \"name\":i[\"display_name\"],\n            \"description\":i[\"description\"],\n            \"icon\":i[\"icon\"],\n            \"key\":i[\"vectordb_name\"],\n            \"config\": i[\"config\"] if i[\"config\"] is not None else None\n        })\n\n        if is_error:\n            logger.error(f\"Error inserting {i['vectordb_name']} {data}\")\n\ndef initialize_embeddings(db:Session):\n    pass\n\n\ndef initialize_plugin_providers(db:Session):\n\n    \"\"\"\n    Initializes the plugin providers by fetching the plugin provider data and inserting or updating\n    their details in the database. It also updates the provider configuration for each plugin.\n\n    Args:\n        db (Session): Database session used for performing transactions.\n    \"\"\"\n\n    providers = get_plugin_providers()\n\n    for i in providers:\n\n        data, is_error = repo.insert_or_update_data(db,Provider,{\"key\":i['plugin_name']},{\n            \"name\":i[\"display_name\"],\n            \"description\":i[\"description\"],\n            \"icon\":i[\"icon\"],\n            \"category_id\":i[\"category\"],\n            \"key\":i[\"plugin_name\"]\n        })\n\n        if is_error:\n            logger.error(f\"Error inserting {i['plugin_name']} {data}\")\n        else:\n\n            for conf in i[\"args\"].values():\n                confdata, is_error = repo.insert_or_update_data(db,ProviderConfig, {\"provider_id\":data.id,\"slug\":conf.slug},{\n                    \"provider_id\":data.id,\n                    \"name\":conf.generic_name,\n                    \"description\":conf.description,\n                    \"field\":conf.slug,\n                    \"slug\":conf.slug,\n                    \"value\":conf.value,\n                    \"order\":conf.order,\n                    \"required\":conf.required,\n                    \"config_type\":conf.type\n                })\n                if is_error:\n                    logger.error(\"Error inserting\", conf.name, confdata)\n\n\n\ndef list_providers(db: Session):\n\n    \"\"\"\n    Lists all available providers from the database and returns their details along with configurations.\n\n    Args:\n        db (Session): Database session used for performing transactions.\n\n    Returns:\n        (List[schemas.ProviderResp], str | None): List of provider details or an error message.\n    \"\"\"\n\n    providers, is_error = repo.get_all_providers(db)\n\n    if is_error:\n        return providers, \"DB Error\"\n\n    if not providers:\n        return [],None\n\n    provider_list = [\n        schemas.ProviderResp(\n            id=provider.id,\n            name=provider.name,\n            description=provider.description,\n            enable=provider.enable,\n            icon=provider.icon,\n            category_id=provider.category_id,\n            key = provider.key,\n            configs=[\n                {\n                    'id': config.id,\n                    'name': config.name,\n                    'description': config.description,\n                    'field': config.field,\n                    'slug': config.slug,\n                    'provider_id': config.provider_id,\n                    'config_type': config.config_type,\n                    'order': config.order,\n                    'required':config.required,\n                    'value':config.value\n                }\n                for config in provider.providerconfig\n            ]\n        )\n        for provider in providers\n    ]\n\n    return provider_list, None\n\ndef get_provider(provider_id: int,db: Session):\n\n    \"\"\"\n    Retrieves the details of a specific provider by its ID.\n\n    Args:\n        provider_id (int): The unique identifier of the provider.\n        db (Session): Database session used for performing transactions.\n\n    Returns:\n        (schemas.ProviderResp, str | None): The provider details or an error message.\n    \"\"\"\n\n    provider, is_error = repo.get_provider_by_id(provider_id,db)\n\n    if is_error:\n        return provider, \"DB Error\"\n\n    if not provider:\n        return {}, None\n\n    provider_data = {\n        'id': provider.id,\n        'name': provider.name,\n        'description': provider.description,\n        'enable': provider.enable,\n        'icon': provider.icon,\n        'category_id': provider.category_id,\n        'key': provider.key,\n        'configs': [\n            {\n                'id': config.id,\n                'name': config.name,\n                'description': config.description,\n                'field': config.field,\n                'slug': config.slug,\n                'provider_id': config.provider_id,\n                'config_type': config.config_type,\n                'order': config.order,\n                'required':config.required,\n                'value':config.value\n            }\n            for config in provider.providerconfig\n        ]\n    }\n\n    provider_resp = schemas.ProviderResp(**provider_data)\n\n    return provider_resp, None\n\ndef test_vectordb_credentials(config:schemas.TestVectorDBCredentials, db:Session):\n    \"\"\"\n    Tests the credentials of a specific vector database based on its configuration.\n\n    Args:\n        config (schemas.TestVectorDBCredentials): Credentials to test.\n        db (Session): Database session used for performing transactions.\n\n    Returns:\n        (str, str | None): A success message or an error message if unsupported.\n    \"\"\"\n    db_config, is_error = repo.get_vector_db_config(db, config.vectordb_config[\"key\"])\n\n    if is_error:\n        return None, db_config\n\n    # if config.embedding_config:\n    #     config.embedding_config[\"vectordb\"] = config.vectordb_config[\"key\"]\n\n\n    return vector_embedding_connector(config, db_config)\n\ndef vector_embedding_connector(config, db_config):\n\n    # if config.embedding_config:\n    #     err = EmLoader(config.embedding_config).load_embclass().health_check()\n    #     if err:\n    #         return err, False\n\n    match config.vectordb_config[\"key\"]:\n        case (\"chroma\" | \"mongodb\"):\n            return test_vector_db_credentials(db_config,config, config.vectordb_config[\"key\"])\n        case _:\n            return None, \"Unsupported Vector Database Provider\"\n\n\n\n\ndef test_credentials(provider_id: int, config: schemas.TestCredentials, db: Session):\n\n    \"\"\"\n    Tests the credentials of a specific provider based on its configuration.\n\n    Args:\n        provider_id (int): The unique identifier of the provider.\n        config (schemas.TestCredentials): Credentials to test.\n        db (Session): Database session used for performing transactions.\n\n    Returns:\n        (str, str | None): A success message or an error message if unsupported.\n    \"\"\"\n\n    provider, is_error = repo.get_provider_by_id(provider_id, db)\n    if provider is None or is_error:\n        return provider, \"Provider Not Found\"\n\n    provider_configs, is_error = repo.get_config_types(provider_id, db)\n    if is_error:\n        return provider_configs, \"Failed to get provider configurations\"\n\n    match provider.category_id:\n        case 1:\n            return test_plugin_connection(provider_configs, config, provider.key)\n        case 2:\n            return test_plugin_connection(provider_configs, config, provider.key)\n        case 4:\n            return test_plugin_connection(provider_configs, config, provider.key)\n        case 5:\n            return test_plugin_connection(provider_configs, config, provider.key)\n        case _:\n            return None, \"Unsupported Provider\"\n\ndef getvectordbs(db: Session):\n    \"\"\"\n    Returns a list of available vector databases.\n\n    Args:\n        request (Request): Request object used for handling incoming requests.\n\n    Returns:\n        dict: List of available vector databases.\n    \"\"\"\n\n    vector_dbs,is_error = repo.get_vectordb_providers(db)\n\n    if is_error:\n        return vector_dbs, \"DB Error\"\n\n    if not vector_dbs:\n        return [], None\n\n    resp = [\n        schemas.VectorDBConfigResponse(\n            id=db.id,\n            name=db.name,\n            description=db.description,\n            icon=db.icon,\n            key=db.key,\n            config=db.config if db.config is not None else [],\n        ) for db in vector_dbs\n    ]\n\n    return resp, None\n\ndef getllmproviders(request: Request):\n\n    \"\"\"\n    Returns a list of available LLM providers.\n\n    Args:\n        request (Request): Request object used for handling incoming requests.\n\n    Returns:\n        dict: List of available LLM providers.\n    \"\"\"\n\n    providers = get_llm_providers()\n\n    return {\"providers\": providers}, None\n\ndef getsqlbyconnector(id:int, db:Session):\n\n    \"\"\"\n    Retrieves SQL metadata based on a connector ID.\n\n    Args:\n        id (int): The unique identifier of the connector.\n        db (Session): Database session used for performing transactions.\n\n    Returns:\n        (List[schemas.SampleSQLResponse], str | None): List of SQL metadata or an error message.\n    \"\"\"\n\n    sqls, is_error = repo.get_sql_by_connector(id, db)\n\n\n    if is_error:\n        return sqls, \"DB Error\"\n\n    if not sqls:\n        return [], None\n\n    sql_list = [\n        schemas.SampleSQLResponse(\n            id=sql.id,\n            description=sql.description,\n            sql_metadata=sql.sql_metadata,\n            connector_id=sql.connector_id,\n        )\n        for sql in sqls\n    ]\n\n    return sql_list, None\ndef listsql(db:Session, user_id: str):\n\n    \"\"\"\n    Retrieves a list of SQL samples from the database.\n\n    Args:\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: List of SampleSQLResponse schemas and error message (if any).\n    \"\"\"\n\n    sqls, is_error = repo.list_sql(db, user_id)\n\n    if is_error:\n        return sqls, \"DB Error\"\n\n    if not sqls:\n        return [], None\n\n    sql_list = [\n        schemas.SampleSQLResponse(\n            id=sql.id,\n            description=sql.description,\n            sql_metadata=sql.sql_metadata,\n            connector_id=sql.connector_id,\n        )\n        for sql in sqls\n    ]\n\n    return sql_list, None\n\ndef getsql(id:int, db:Session):\n\n    \"\"\"\n    Retrieves a specific SQL sample by its ID from the database.\n\n    Args:\n        id (int): ID of the SQL sample to retrieve.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: SampleSQLResponse schema and error message (if any).\n    \"\"\"\n\n    sqls, is_error = repo.get_sql(id,db)\n\n    if is_error:\n        return sqls, \"DB Error\"\n\n    if not sqls:\n        return {}, None\n\n    sql_data = {\n        'id': sqls.id,\n        'description': sqls.description,\n       'sql_metadata': sqls.sql_metadata,\n        'connector_id': sqls.connector_id,\n    }\n\n    sql_resp = schemas.SampleSQLResponse(**sql_data)\n\n    return sql_resp, None\n\ndef create_sql(request: Request,sql:schemas.SampleSQLBase,db:Session, user_id: str):\n\n    \"\"\"\n    Creates a new SQL sample in the database and updates the vector store.\n\n    Args:\n        request (Request): Request object to access app components.\n        sql (schemas.SampleSQLBase): Data for the new SQL sample.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: SampleSQLResponse schema and error message (if any).\n    \"\"\"\n\n    sql, is_error =  repo.create_sql(sql,db,user_id)\n\n    if is_error:\n        return sql, \"DB Error\"\n    if not sql:\n        return [], None\n\n    insert_vector_store(request, sql, db)\n\n    return schemas.SampleSQLResponse(\n        description=sql.description,\n        sql_metadata=sql.sql_metadata,\n        connector_id=sql.connector_id,\n        id= sql.id,\n    ), False\n\ndef update_sql(request: Request, sql_id: int, sql: schemas.SampleSQLUpdate, db: Session):\n\n    \"\"\"\n    Updates an existing SQL sample in the database and updates the vector store.\n\n    Args:\n        request (Request): Request object to access app components.\n        sql_id (int): ID of the SQL sample to update.\n        sql (schemas.SampleSQLUpdate): Updated data for the SQL sample.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: SampleSQLResponse schema and error message (if any).\n    \"\"\"\n\n    sql, is_error = repo.update_sql(sql_id, sql, db)\n\n    if is_error:\n        return sql, \"DB Error\"\n\n    if not sql:\n        return {}, None\n\n    insert_vector_store(request, sql, db)\n\n    return schemas.SampleSQLResponse(\n        description=sql.description,\n        sql_metadata=sql.sql_metadata,\n        connector_id=sql.connector_id,\n        id= sql.id,\n    ), False\n\ndef delete_sql(sql_id: int, db: Session):\n\n    \"\"\"\n    Deletes an SQL sample by its ID from the database.\n\n    Args:\n        sql_id (int): ID of the SQL sample to delete.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: SampleSQLResponse schema and error message (if any).\n    \"\"\"\n\n    sql, is_error = repo.delete_sql(sql_id, db)\n\n    if is_error:\n        return sql, \"DB Error\"\n\n    if not sql:\n        return {}, None\n\n    return schemas.SampleSQLResponse(\n        description=sql.description,\n        sql_metadata=sql.sql_metadata,\n        connector_id=sql.connector_id,\n        id=sql.id,\n    ), False\n\ndef get_quries_by_key(key:str, db: Session):\n\n    \"\"\"\n    Retrieves SQL samples based on a specific key.\n\n    Args:\n        key (str): Key to filter SQL samples (Connector Name).\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: List of dictionaries containing SQL descriptions and metadata, and error message (if any).\n    \"\"\"\n\n    sql, is_error = repo.get_sql_by_key(key, db)\n    if is_error:\n        return sql, \"DB Error\"\n\n    if not sql:\n        return {}, None\n\n    return [\n        {\n            \"description\": sql.description,\n            \"metadata\": sql.sql_metadata\n        }\n    ], None\n\ndef insert_vector_store(request, sql, db: Session):\n\n    \"\"\"\n    Inserts SQL data into the vector store.\n\n    Args:\n        request (Request): Request object to access app components.\n        sql: SQL sample data to be inserted.\n        db (Session): Database session object.\n\n    Returns:\n        str: Error message if an exception occurs, otherwise None.\n    \"\"\"\n\n    datasource, is_error = conn_repo.get_connector_by_id(sql.connector_id, db)\n\n    vector_store = request.app.vector_store\n    queries = [\n        {\n            \"description\": sql.description,\n            \"metadata\": sql.sql_metadata\n        }\n    ]\n\n    try :\n        vector_store.prepare_data(datasource_name=datasource.connector_name, queries=queries, chunked_document = None, chunked_schema = None)\n    except Exception as e:\n\n        return str(e)\n\ndef create_vector_db_default_config(vectordb):\n    if vectordb.embedding_config is None:\n        vectordb.embedding_config = {\"provider\": \"default\", \"params\": {}}\n\n    if not vectordb.vectordb:\n        vectordb.vectordb = \"chroma\"\n        vectordb.vectordb_config = {\"path\": \"./vector_db\"}\n\n    return vectordb\n\ndef attach_vector_config_if_missing(vectordb, db):\n\n    inference, is_error = conn_repo.get_inference_by_config(vectordb.config_id, db)\n\n    if is_error:\n        return \"Inference not found\", is_error\n\n    if vectordb.embedding_config.get(\"provider\") == inference.llm_provider and not vectordb.embedding_config[\"params\"].get(\"api_key\"):\n        vectordb.embedding_config[\"params\"][\"api_key\"] = inference.apikey\n\n    return vectordb, None\n\n\ndef create_vectordb_and_embedding(key,id,vectordb, db):\n\n    \"\"\"\n    Creates a new VectorDB instance and inserts an embedding into the vector store.\n\n    Args:\n        vectordb (schemas.VectorDB): VectorDB instance data.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: VectorDBResponse schema and error message (if any).\n    \"\"\"\n\n    vectordb = create_vector_db_default_config(vectordb)\n\n    vectordb, is_error = attach_vector_config_if_missing(vectordb, db)\n\n    if is_error:\n        return vectordb, is_error\n\n    db_data, is_error = repo.create_vectordb_with_embedding(key,id, vectordb, db)\n\n    if is_error:\n        return vectordb, \"DB Error\"\n\n    response_data = {\n        'id': db_data['vectordb'].id,\n        'vectordb': db_data['vectordb'].vectordb,\n        'vectordb_config': db_data['vectordb'].vectordb_config,\n        'config_id': db_data['vectordb_mapping'].config_id,\n    }\n\n    return schemas.VectorDBResponse(**response_data), None\n\n\ndef get_vectordb_instance(id: int, db: Session):\n    \"\"\"\n    Retrieves a VectorDB instance by its ID.\n\n    Args:\n        id (int): The ID of the VectorDB instance.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: VectorDBResponse schema and error message (if any).\n    \"\"\"\n\n    (vectordb_instance, embedding), is_error = repo.get_vectordb_instance(id, db)\n\n    if is_error:\n        return vectordb_instance, \"DB Error\"\n\n\n    return schemas.VectorDBResponse(\n        id=vectordb_instance.id,\n        vectordb=vectordb_instance.vectordb,\n        vectordb_config=vectordb_instance.vectordb_config,\n        config_id=vectordb_instance.vectordb_config_mapping[0].config_id,\n        embedding_config={\"provider\": embedding.provider,\"config\": embedding.config}\n    ), None\n\ndef delete_vectordb_instance(id: int, db: Session):\n    \"\"\"\n    Deletes a VectorDB instance and its associated config mapping by ID.\n\n    Args:\n        id (int): The ID of the VectorDB instance to delete.\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: Success message and error message (if any).\n    \"\"\"\n\n    success, is_error = repo.revoke_existing_vectordb_confg(id, db)\n\n    if is_error:\n        return success, \"DB Error or VectorDB not found\"\n\n    return success, None\n\ndef create_vectorstore_instance(db:Session, config_id: int):\n    \"\"\"\n    Creates a new vector store instance.\n\n    Args:\n        db (Session): Database session object.\n\n    Returns:\n        Tuple: VectorStoreConfigResponse schema and error message (if any).\n    \"\"\"\n    configs, is_error = conn_repo.get_configuration_by_id(config_id, db)\n    vector_store_formatting=None\n    vector_store = None\n\n    if is_error:\n        return configs, \"DB Error\"\n\n    if configs:\n\n        vector_store, is_error = repo.get_mapped_vector_store(db, configs.id)\n\n    if vector_store:\n        vector_store_formatting = {\n            \"name\": vector_store.get(\"vectordb\"),\n            \"params\": {**vector_store.get(\"vectordb_config\", {})}\n        }\n\n\n        vectordb_config = vector_store.get(\"vectordb_config\", {})\n\n        if vectordb_config:\n            embeddings = vector_store.get(\"embedding_config\", {})\n\n            vector_store_formatting[\"embeddings\"] = {\n                **embeddings,\n                \"provider\": vector_store.get(\"em_provider\"),\n                \"vectordb\": vector_store.get(\"vectordb\")\n            }\n\n            vector_store_formatting={**vector_store_formatting,**vectordb_config}\n\n    vectorloader = VectorDBLoader(vector_store_formatting) if vector_store_formatting else VectorDBLoader(config={\"name\":\"chroma\", \"params\":{\"path\":\"./chromadb\"}})\n\n    return vectorloader.load_class(), None\n\n\ndef get_all_embeddings():\n\n    \"\"\"\n    Returns a list of available LLM providers.\n\n    Args:\n        request (Request): Request object used for handling incoming requests.\n\n    Returns:\n        dict: List of available LLM providers.\n    \"\"\"\n\n    embeddings = get_all_embedding()\n\n    return embeddings, None"
  },
  {
    "path": "app/services/user.py",
    "content": "from sqlalchemy.orm import Session\nimport app.repository.user as repo\nimport app.repository.environment as env_repo\nimport app.schemas.user as schemas\n\ndef get_or_create_user(user: schemas.UserCreate, db: Session):\n    \"\"\"\n    Retrieves an existing user or creates a new one if not found.\n    \n    Args:\n        user (UserBase): The data for the new user.\n        db (Session): Database session dependency.\n\n    Returns:\n        Tuple: UserResponse object and error message (if any).\n    \"\"\"\n    \n    existing_user, is_error = repo.get_user_by_id(user.id, db)\n    if existing_user:\n        return existing_user, None\n    \n    new_user, is_error = repo.create_user(user, db)\n    if is_error:\n        return None, \"Failed to create user\"\n    \n    unique_env = env_repo.create_environment(f\"{new_user.username} env\", db)\n    assign_result, env_error = env_repo.assign_user_to_environment(new_user.id, unique_env.id, db)\n    \n    if env_error:\n        return None, f\"User created but failed to assign environment: {env_error}\"\n\n    user_response = schemas.UserResponse(\n        id=new_user.id,\n        username=new_user.username,\n    )\n\n    return user_response, None\n\n\ndef get_users_active_env(user_id: int, db: Session):\n    \n    env_id, error = env_repo.get_current_env_id(user_id, db)\n    \n    if error:\n        return None, \"Failed to get user's current active env_id\"\n    \n    return env_id, None"
  },
  {
    "path": "app/utils/database.py",
    "content": "from sqlalchemy import create_engine\nfrom sqlalchemy.orm import sessionmaker\nfrom sqlalchemy.orm import declarative_base\nfrom app.providers.config import configs\n\nDATABASE_URL = configs.DATABASE_URL\n\nengine = create_engine(DATABASE_URL)\nSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)\nBase = declarative_base()\n\n\ndef get_db():\n    db = SessionLocal()\n    try:\n        yield db\n    finally:\n        db.close()\n"
  },
  {
    "path": "app/utils/jwt.py",
    "content": "import jwt\nfrom jwt import PyJWTError\nfrom datetime import datetime, timedelta\n\nclass JWTUtils:\n    def __init__(self, secret_key, algorithm=\"HS256\"):\n        self.SECRET_KEY = secret_key\n        self.ALGORITHM = algorithm\n\n    def create_jwt_token(self, data: dict, expires_delta: timedelta = timedelta(minutes=30)):\n        to_encode = data.copy()\n        expire = datetime.now() + expires_delta\n        to_encode.update({\"exp\": expire})\n        encoded_jwt = jwt.encode(to_encode, self.SECRET_KEY, algorithm=self.ALGORITHM)\n        return encoded_jwt\n\n    def decode_jwt_token(self, token: str):\n        try:\n            payload = jwt.decode(token, self.SECRET_KEY, algorithms=[self.ALGORITHM])\n            return payload\n        except PyJWTError:\n            return None\n\n\n\n"
  },
  {
    "path": "app/utils/module_reader.py",
    "content": "from loguru import logger\nimport importlib\nimport pkgutil\n\n\ndef get_vectordb_providers():\n    vectordb = importlib.import_module(\"app.vectordb\")\n    modules = []\n    for module_info in pkgutil.iter_modules(vectordb.__path__):\n        try:\n            module = importlib.import_module(f\"{vectordb.__name__}.{module_info.name}\")\n            modules.append({\n                \"icon\": getattr(module, '__icon__'),\n                \"vectordb_name\": getattr(module, '__vectordb_name__'),\n                \"display_name\": getattr(module, '__display_name__'),\n                \"description\": getattr(module, '__description__'),\n                \"config\": getattr(module, \"__connection_args__\")\n            })\n\n        except Exception as e:\n            if module_info.name!= \"loader\":\n                logger.warning(f\"failed loading {module_info.name} {e}\")\n\n    return modules\n\ndef get_plugin_providers():\n    plugins = importlib.import_module(\"app.plugins\")\n    modules = []\n    for module_info in pkgutil.iter_modules(plugins.__path__):\n        module_name = f\"{plugins.__name__}.{module_info.name}\"\n        try:\n            module = importlib.import_module(module_name)\n            modules.append({\n                \"version\": getattr(module, '__version__'),\n                \"icon\": getattr(module, '__icon__'),\n                \"plugin_name\": getattr(module, '__plugin_name__'),\n                \"display_name\": getattr(module, '__display_name__'),\n                \"description\": getattr(module, '__description__'),\n                \"category\": getattr(module, '__category__'),\n                \"args\": getattr(module, \"__connection_args__\")\n            })\n\n        except Exception as e:\n            if module_info.name != \"loader\":\n                logger.warning(f\"failed loading {module_info.name} {e}\")\n\n    return modules\n\ndef get_llm_providers():\n    plugins = importlib.import_module(\"app.loaders\")\n    modules = []\n    for module_info in pkgutil.iter_modules(plugins.__path__):\n        module_name = f\"{plugins.__name__}.{module_info.name}\"\n        try:\n            module = importlib.import_module(module_name)\n            modules.append({\n                \"display_name\": getattr(module, '__display_name__'),\n                \"unique_name\": getattr(module, '__unique_name__'),\n                \"icon\": getattr(module, '__icon__')\n            })\n\n        except Exception as e:\n            if module_info.name != \"base_loader\":\n                logger.info(f\"failed loading {module_info.name} cause {e}\")\n\n    return modules\n\ndef get_all_embedding():\n    embeddings = importlib.import_module(\"app.embeddings\")\n    modules = []\n    for module_info in pkgutil.iter_modules(embeddings.__path__):\n        module_name = f\"{embeddings.__name__}.{module_info.name}\"\n        try:\n            module = importlib.import_module(module_name)\n            modules.append({\n                \"provider\": getattr(module, '__provider_name__'),\n                \"vector_dbs\": getattr(module, '__vectordb_name__'),\n                \"config\": getattr(module, '__connection_args__'),\n                \"icon\": getattr(module, '__icon__')\n            })\n\n        except Exception as e:\n            logger.info(f\"failed loading {module_info.name} cause {e}\")\n    return modules"
  },
  {
    "path": "app/utils/parser.py",
    "content": "import json\nfrom loguru import logger\n\ndef parse_llm_response(body):\n        text = body.replace(\"\\\\n\",\"\")\n        text = text.replace(\"\\n\",\"\")\n        text = text.replace(\"\\\\_\",\"_\")\n        if '\\\\\"' not in text:\n            text = text.replace(\"\\\\\",\"\")\n        text = text.removeprefix(\"```json\")\n        text = text.removesuffix(\"```\")\n        text = text.removesuffix(\"User:\")\n        try:\n            out = json.loads(text)\n        except Exception as e:\n            logger.info(\"error parsing llm response\")\n            logger.critical(e)\n            out = {}\n\n        return out\n\ndef markdown_parse_llm_response(body):\n        # text = body.replace(\"\\\\n\",\"\")\n        # text = text.replace(\"\\n\",\"\")\n        # text = text.replace(\"\\\\\",\"\")\n        # text = text.replace(\"\\\\_\",\"_\")\n        # if '\\\\\"' not in text:\n        #     text = text.replace(\"\\\\\",\"\")\n        text = body.removeprefix(\"```json\")\n        text = text.removesuffix(\"```\")\n        text = text.removesuffix(\"User:\")\n\n        try:\n            out = json.loads(text)\n        except Exception as e:\n            logger.info(\"error parsing llm response\")\n            logger.critical(e)\n            out = {}\n\n        return out\n\n"
  },
  {
    "path": "app/utils/read_config.py",
    "content": "import yaml\nfrom loguru import logger\n\n\n\ndef read_yaml_file(config_file) -> dict:\n    \"\"\"\n    Reads a YAML file and returns its contents as a dictionary.\n\n    :param file_path: Path to the YAML file.\n    :return: Dictionary containing the file contents.\n    \"\"\"\n    try:\n        # Read YAML config file\n        with open(config_file, \"r\") as yaml_file:\n            yaml_config = yaml.safe_load(yaml_file)\n        return yaml_config\n    except Exception as e:\n        logger.warning(e)\n        return {}\n\n\n\n"
  },
  {
    "path": "app/vectordb/loader.py",
    "content": "from app.vectordb.chromadb.handler import ChromaDataBase\nfrom app.vectordb.mongodb.handler import AltasMongoDB\n\nfrom loguru import logger\n\n\n\nclass VectorDBLoader:\n    def __init__(self, config):\n        self.config = config\n\n    def load_class(self):\n        vectordb_classes = {\n            \"chroma\": ChromaDataBase,\n            \"mongodb\": AltasMongoDB,\n        }\n        vectordb_provider = self.config.get('name',{})\n        connection_params = self.config.get('params',{})\n\n\n        vectordb_class = vectordb_classes.get(vectordb_provider)\n        logger.info(f\"vectordb provider: {vectordb_provider}\")\n        logger.info(f\"connection_params:{connection_params}\")\n\n\n        if vectordb_class:\n            return vectordb_class(**connection_params)\n        else:\n            logger.info(\"No specified vectordb providers\")\n            return ChromaDataBase()"
  },
  {
    "path": "app/vectordb/mongodb/__init__.py",
    "content": "from collections import OrderedDict\nfrom app.models.request import ConnectionArgument\n\n# Plugin Metadata\n__version__ = '1.0.0'\n__vectordb_name__ = 'mongodb'\n__display_name__ = 'MongoDB Atlas'\n__description__ = 'MongoDB for Vector Storage'\n__icon__ = '/assets/vectordb/logos/mongodb.svg'\n__connection_args__ = [\n    {\n        \"config_type\": 1,\n        \"name\": \"MongoDB URI\",\n        \"description\": \"URI to connect to MongoDB\",\n        \"order\": 1,\n        \"required\": True,\n        \"slug\": \"uri\",\n        \"field\": \"uri\",\n        \"placeholder\": \"mongodb+srv://admin:<password>@cluster0.lwqw4z.mongodb.net/\",\n    }\n]\n\n\n\n\n\n__all__ = [\n    __version__, __vectordb_name__, __display_name__ , __description__, __icon__, __connection_args__\n]"
  },
  {
    "path": "app/vectordb/mongodb/handler.py",
    "content": "import pymongo\nfrom loguru import logger\nfrom app.base.base_vectordb import BaseVectorDB\nimport certifi\n\n\nclass AltasMongoDB(BaseVectorDB):\n    def __init__(self, uri: str , embeddings: dict={\"provider\": \"default\", \"vectordb\": \"mongodb\"}):\n        self.uri = uri\n        self.client = None\n        self.embeddings = embeddings\n        self.EMBEDDING_FIELD_NAME = \"embeddings\"\n\n    def connect(self):\n        try:\n            self.client = pymongo.MongoClient(self.uri, tlsCAFile=certifi.where())\n            logger.info(f\"Connected to Altas MongoDB Vector Database\")\n            self.db = self.client.get_database('context_store')\n            self.schema_collection = self.db.get_collection('schema')\n            self.doc_collection = self.db.get_collection('documents')\n            self.cache_collection = self.db.get_collection('cache')\n            self.schema_index_name = \"schema\"\n            self.doc_index_name = \"doc\"\n            self.cache_index_name = \"cache\"\n            self.emf = self.load_embeddings_function()\n            return None\n        except Exception as e:\n            logger.critical(f\"Failed connecting Altas MongoDB Vector Database: {e}\")\n            return str(e)\n\n    def health_check(self):\n        try:\n            sample = {\n                    \"_id\": \"doc1\",\n                    \"datasource\":\"psql_db\",\n                    \"document\": \"This referes to the user data which consist of username, password, email and address\",\n                    \"metadata\":{\n                        \"username\": \"username\"\n                    }\n                }\n            sample[self.EMBEDDING_FIELD_NAME] = self.generate_embedding(sample['document'])\n\n            self.doc_collection.insert_many([sample])\n            # self.schema_collection.insert_many([sample])\n            # self.cache_collection.insert_many([sample])\n\n            collection_list = self.db.list_collection_names()\n            logger.info(f\"collections available:{collection_list}\")\n            self.doc_collection.delete_many({ \"datasource\": \"psql_db\" })\n            if len(collection_list) > 0:\n                return None\n            else:\n                return \"Collections cannot be created in DB\"\n\n        except Exception as e:\n            logger.error(f\"Health check failed: {e}\")\n            return f\"Failed to connect with Altas MongoDB {e}\"\n\n\n    def clear_collection(self, config_id):\n    #     self.schema_collection.delete_many({})  # Delete all documents in the collection\n    #     self.doc_collection.delete_many({})\n    #     self.cache_collection.delete_many({})\n        self.config_id = config_id\n        self.cache_collection.delete_many({ \"metadatas.config_id\": config_id })\n        self.schema_collection.delete_many({ \"metadatas.config_id\": config_id })\n        self.doc_collection.delete_many({ \"metadatas.config_id\": config_id })\n\n    def generate_embedding(self, context: str) -> list[float]:\n        array = self.emf([context])[0]\n        return array.tolist()\n\n    def prepare_data(self, datasource_name, chunked_document, chunked_schema, queries, config_id):\n        if chunked_document:\n            documents = []\n            document_count = self.doc_collection.count_documents({})\n            for i, doc in enumerate(chunked_document, start = document_count):\n                sample = {\n                    # \"_id\": \"doc\" + str(i),\n                    \"document\": doc.page_content,\n                    \"metadatas\": {**doc.metadata,\"datasource\": datasource_name, \"config_id\": config_id}\n                }\n                sample[self.EMBEDDING_FIELD_NAME] = self.generate_embedding(sample['document'])\n                documents.append(sample)\n\n            self.doc_collection.insert_many(documents)\n\n        if chunked_schema:\n            schemas = []\n            schema_count = self.schema_collection.count_documents({})\n            for i, doc in enumerate(chunked_schema, start = schema_count):\n                sample = {\n                    # \"_id\": \"doc\" + str(i),\n                    \"document\": doc.page_content,\n                    \"metadatas\": {**doc.metadata,\"datasource\": datasource_name, \"config_id\": config_id}\n                }\n                sample[self.EMBEDDING_FIELD_NAME] = self.generate_embedding(sample['document'])\n                schemas.append(sample)\n            self.schema_collection.insert_many(schemas)\n\n        if queries:\n            caches = []\n            queries_count = self.cache_collection.count_documents({})\n            for i, doc in enumerate(queries, start = queries_count):\n                sample = {\n                    # \"_id\": \"doc\" + str(i),\n                    \"document\": doc['description'],\n                    \"metadatas\": {**doc['metadata'], \"datasource\": datasource_name, \"config_id\": config_id}\n                }\n                sample[self.EMBEDDING_FIELD_NAME] = self.generate_embedding(sample['document'])\n                caches.append(sample)\n\n            self.cache_collection.insert_many(caches)\n\n        self.create_knn_index()\n\n    def _create_index(self, collection, index_name):\n        index = list(collection.list_search_indexes())\n\n        if len(index)==0:\n            collection.create_search_index({\n                \"definition\": {\n                    \"mappings\": {\n                        \"dynamic\": True,\n                        \"fields\": {\n                            self.EMBEDDING_FIELD_NAME: {\n                                \"dimensions\": 384,\n                                \"similarity\": \"cosine\",\n                                \"type\": \"knnVector\"\n                            }\n                        }\n                    }\n                },\n                \"name\": index_name  # Renamed for consistency\n            })\n            logger.info(f\"Index created:{index_name}\")\n\n        else:\n            logger.info(f\"{index_name} Index already exists\")\n\n\n    def create_knn_index(self):\n        self._create_index(self.doc_collection, self.doc_index_name)\n        self._create_index(self.schema_collection, self.schema_index_name)\n        self._create_index(self.cache_collection, self.cache_index_name)\n\n    async def _find_similar(self, datasource, collection, query, count, index_name):\n        logger.info(f\"datasources:{datasource}\")\n        logger.info(f\"collection:{collection}\")\n        logger.info(f\"index_name:{index_name}\")\n\n\n        res = collection.aggregate([\n\n            {\n                '$vectorSearch': {\n                    \"index\": index_name,\n                    \"path\": self.EMBEDDING_FIELD_NAME,\n                    \"queryVector\": self.generate_embedding(query),\n                    \"numCandidates\": 50,\n                    \"limit\": count,\n\n                }\n            },\n            {\n            '$match': {\n                'metadatas.datasource': datasource  # Filter for the specified datasource\n            }\n            },\n            {\n            \"$project\": {\n            \"_id\" : 1,\n            \"datasource\" : 1,\n            \"document\": 1,\n            \"metadatas\": 1,\n            \"score\": {\"$meta\": \"vectorSearchScore\"}\n            }\n        }\n        ])\n        results = list(res)\n        for result in results:\n            result['distances'] = 1 - result['score']\n        return results\n\n    async def find_similar_schema(self, datasource, query,count):\n       return await self. _find_similar(datasource, self.schema_collection, query, count, self.schema_index_name)\n\n    async def find_similar_documentation(self, datasource, query, count):\n       return await self. _find_similar(datasource, self.doc_collection, query, count, self.doc_index_name)\n\n    async def find_similar_cache(self, datasource, query,count = 3):\n       return await self. _find_similar(datasource, self.cache_collection, query, count, self.cache_index_name)"
  },
  {
    "path": "commands/cli.py",
    "content": "import click\nfrom loguru import logger\nfrom app.utils.read_config import read_yaml_file\nimport sys\n\n@click.group()\n@click.option('--debug', default=False, envvar='DEBUG_MODE', help='Enable debug mode')\n@click.option('--config', prompt='please provide config file', help='Path to the configuration file')\n@click.pass_context\ndef cli(ctx, debug, config):\n    \"\"\"\n    CLI for managing application commands.\n\n    :param ctx: Click context object for passing configurations.\n    :param debug: Flag to enable or disable debug mode.\n    :param config: Path to the configuration file.\n    \"\"\"\n    \n    if debug:\n        logger.debug(\"Debug mode enabled\")\n        \n    \n    logger.info(\"loading configurations\")\n    config = read_yaml_file(config)\n\n    \n    if len(config) > 0:\n        ctx.obj = config\n    else:\n        logger.critical(\"Configuration data is empty or invalid\")\n        sys.exit(1) \n"
  },
  {
    "path": "commands/llm.py",
    "content": "import click\nfrom commands.cli import cli\nfrom loguru import logger\nfrom app.providers.config import configs\nfrom app.main import create_app\nimport uvicorn\nimport sys\n\n\n\n@cli.command()\n@click.pass_obj\ndef llm(ctx) -> None:\n    \"\"\"\n    Starts the LLM chain server using Uvicorn.\n\n    :param ctx: Configuration context passed from the CLI command.\n    \"\"\"\n\n    logger.info(\"Intializing fastapi application server\")\n    # try:\n\n    app = create_app(config=ctx)\n    logger.info(\"Intialized fastapi application\")\n    logger.info(\"Starting Uvicorn server...\")\n    uvicorn.run(app,\n                host=\"0.0.0.0\",\n                port=configs.application_port,\n                reload=False)\n\n    # except Exception as e:\n    #     logger.critical(f\"Failed to start the LLM server: {e}\")\n    #     sys.exit(1)\n\n\n# Registering llm command\ncli.add_command(llm)\n"
  },
  {
    "path": "config.yaml",
    "content": "vector_db:\n  name: \"chroma\"\n  params:\n    path: \"./vector_db\"\n    embeddings:\n      provider: \"chroma_default\"\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "services:\r\n  nginx:\r\n    image: nginx:latest\r\n    container_name: nginx\r\n    ports:\r\n      - \"80:80\"\r\n      - \"82:82\"\r\n      - \"443:443\"\r\n    volumes:\r\n      - ./nginx.conf:/etc/nginx/nginx.conf  # Mount custom nginx.conf to container\r\n    restart: always\r\n    depends_on:\r\n      - zitadel\r\n      - backend\r\n        \r\n\r\n  db:\r\n    image: postgres:16-alpine\r\n    environment:\r\n      PGUSER: postgres\r\n      POSTGRES_PASSWORD: postgres\r\n    healthcheck:\r\n      test: [\"CMD-SHELL\", \"pg_isready\", \"-d\", \"zitadel\", \"-U\", \"postgres\", \"||\", \"exit 1\"]\r\n      interval: 10s\r\n      timeout: 30s\r\n      retries: 5\r\n      start_period: 20s\r\n    volumes:\r\n      - ./pgdata:/var/lib/postgresql/data\r\n\r\n\r\n  zitadel:\r\n    user: \"${UID:-1000}\"\r\n    restart: always\r\n    image: 'ghcr.io/zitadel/zitadel:latest'\r\n    command: 'start-from-init --masterkey \"MasterkeyNeedsToHave32Characters\" --tlsMode disabled'\r\n    ports:\r\n      - '8080:8080'\r\n    environment:\r\n      ZITADEL_DATABASE_POSTGRES_HOST: db\r\n      ZITADEL_DATABASE_POSTGRES_PORT: 5432\r\n      ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel\r\n      ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel\r\n      ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: zitadel\r\n      ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable\r\n      ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: postgres\r\n      ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: postgres\r\n      ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable\r\n      ZITADEL_EXTERNALSECURE: \"false\"\r\n      ZITADEL_EXTERNALDOMAIN: \"zitadel\"\r\n      ZITADEL_EXTERNALPORT: \"82\"\r\n      ZITADEL_FIRSTINSTANCE_MACHINEKEYPATH: /machinekey/zitadel-admin-sa.json\r\n      ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_USERNAME: zitadel-admin-sa\r\n      ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_NAME: Admin\r\n      ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINEKEY_TYPE: 1\r\n    volumes:\r\n      - ./machinekey:/machinekey\r\n    depends_on:\r\n      db:\r\n        condition: service_healthy\r\n\r\n  backend:\r\n    build:\r\n      context: .\r\n      dockerfile: Dockerfile\r\n    ports:\r\n      - '8001:8001'\r\n    volumes:\r\n      - ./raggenie.db:/app/raggenie.db\r\n      - ./assets:/app/assets\r\n      - ./chromadb:/app/chromadb\r\n      - ./machinekey:/app/machinekey\r\n    environment:\r\n      - PYTHONDONTWRITEBYTECODE=1\r\n      - PYTHONUNBUFFERED=1\r\n      - ZITADEL_TOKEN_URL=http://zitadel:8080/oauth/v2/token\r\n      - ZITADEL_DOMAIN=http://zitadel:8080 \r\n      - APP_SERVER=http://localhost:8001\r\n      - CLIENT_PRIVATE_KEY_FILE_PATH=machinekey/zitadel-admin-sa.json\r\n    command: 'python3 main.py --config ./config.yaml llm'\r\n    depends_on:\r\n      - zitadel\r\n"
  },
  {
    "path": "documents/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "documents/README.md",
    "content": "# Website\n\nThis website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.\n\n### Installation\n\n```\n$ yarn\n```\n\n### Local Development\n\n```\n$ yarn start\n```\n\nThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.\n\n### Build\n\n```\n$ yarn build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n\n### Deployment\n\nUsing SSH:\n\n```\n$ USE_SSH=true yarn deploy\n```\n\nNot using SSH:\n\n```\n$ GIT_USER=<Your GitHub username> yarn deploy\n```\n\nIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.\n"
  },
  {
    "path": "documents/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "documents/docs/Configuring agents.md",
    "content": "---\nsidebar_position: 7\n---\n\n# Configuring agents"
  },
  {
    "path": "documents/docs/Connectors/Airtable.md",
    "content": "---\nsidebar_position: 2\n---\n\n# Airtable Plugin\n\n### Plugin name\nThe name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction.\n\n### Plugin Description\nA 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.\n\n### Airtable token\nThe 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.\n\n### Airtable workspace id\nThe 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."
  },
  {
    "path": "documents/docs/Connectors/Bigquery.md",
    "content": "---\nsidebar_position: 3\n---\n\n# Bigquery Plugin\n\n### Plugin name\nThe name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction.\n\n### Plugin Description\nA 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.\n\n### Service account JSON\nThe 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.\n\n### Project id\nThe 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."
  },
  {
    "path": "documents/docs/Connectors/Connectors.md",
    "content": "---\nsidebar_position: 4\n---\n\n# Connectors/pluggins\nDifferent components in your LLM app can be inserted using plugins.\n\n## Data Sources\nCurrently these are the datasource plugins that are available in raggenie.\n\n### Structred Datasources\n* [Postgressql](./Postgressql)\n* [Airtable](./Airtable)\n* [Bigquery](./Bigquery)\n\n### Unstrunctured Datasources\n* [PDFs](./PDFs)\n* [Websites](./Websites)"
  },
  {
    "path": "documents/docs/Connectors/PDFs.md",
    "content": "---\nsidebar_position: 4\n---\n\n# PDFs Plugin\n\n### Plugin name\nThe name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction.\n\n### Plugin Description\nA 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.\n\n### File upload\nThe 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."
  },
  {
    "path": "documents/docs/Connectors/Postgressql.md",
    "content": "---\nsidebar_position: 1\n---\n\n# Postgressql Plugin\n\nYou can connect to an instance of postgress using the postgressql plugin.\n\n### Plugin name\nThe name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction.\n\n### Plugin Description\nA 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.\n\n### Database sslmode\nSSL 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.\n\n* 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.\n\n* 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.\n\n### Database name\nThe 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.\n\n### Database host\nThe 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.\n\n### Database port\nThe 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.\n\n### Password\nThe password of the user trying to access the postgressql database.\n\n### User name\nThe 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."
  },
  {
    "path": "documents/docs/Connectors/Websites.md",
    "content": "---\nsidebar_position: 5\n---\n\n# Websites Plugin\n\n### Plugin name\nThe name of the plugin is used to differentiare between different connected plugins. These would be used for LLM calls during intent extraction.\n\n### Plugin Description\nA 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.\n\n### Website URL\nThe 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."
  },
  {
    "path": "documents/docs/Examples.md",
    "content": "---\nsidebar_position: 4\n---\n\n# Examples"
  },
  {
    "path": "documents/docs/How to configure raggenie/Configuration.md",
    "content": "---\nsidebar_position: 2\n---\n\n# Configuration\n\n## Configuration details\nYou should provide a bot name, a short discription about the bot and a long discription about the bots usecase.\nNote:- 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.\n\n## Inference endpoint\nTo add an LLM endpoint choose your LLM inference provider and specify a unique name to reference the particular model.\n![LLM inference plugin image](../../static/img/inferance_end_point.png?raw=true)\n\nSpecify the model name, inference provider endpoint, and the API key.\n\n## Capabilities\nCapabilities 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.\n### Add Capability Name and Description\nCapability 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.\n![Capability initialisation image](../../static/img/Capbilities.png?raw=true)\n### Add Capability Parameters\nYou 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\n![Capability parameters image](../../static/img/Create_parameter.png?raw=true)\nthese parameters can be used to trigger an action."
  },
  {
    "path": "documents/docs/How to configure raggenie/Deploy.md",
    "content": "---\nsidebar_position: 4\n---\n\n# Deploy\n\n`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.\n\nYou can get the live preview URL from here to be shared with your end users."
  },
  {
    "path": "documents/docs/How to configure raggenie/Plugins.md",
    "content": "---\nsidebar_position: 1\n---\n\n# Plugins\n\n## Configuration\nPlugin configuration is used to specify the metadata of different datasources such as datasource name, description and login details.\nYou need to specify informations such as:\n* Plugin Name: Plugin name is used to differentiate between different connected plugins.\n* 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.\n* Database login details: These are specific for different plugins. Refer [Plugins](../Connectors) for more details\nafter entering all the details use `connection test` button perform a health check. If the health check passes use `save & continue` to save the plugin.\n\n## Database schema\nRaggenie 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`.\n\n## Documentation\nYou 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."
  },
  {
    "path": "documents/docs/How to configure raggenie/Preview.md",
    "content": "---\nsidebar_position: 5\n---\n\n# Preview\n\nYou 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."
  },
  {
    "path": "documents/docs/How to configure raggenie/Samples.md",
    "content": "---\nsidebar_position: 3\n---\n\n# Samples\n\nYou 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.\n* Question: This is the user query that the model is supposed to generate a response for.\n* Connector: This is the plugin that contains the data, which is needed to get the correct LLM response.\n* Query: This is the query that should be generated by the LLM to get the correct data.\n* Metadata: This can be used to give additional data about the example. This is optional.\n`Save` your changes for updating the sample respose."
  },
  {
    "path": "documents/docs/How to configure raggenie/_category_.json",
    "content": "{\n  \"label\": \"How to configure raggenie\",\n  \"position\": 3,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"description\": \"Steps to configure Raggenie\"\n  }\n}\n"
  },
  {
    "path": "documents/docs/How to run raggenie/To run raggenie backend Server.md",
    "content": "---\nsidebar_position: 1\n---\n\n# To run raggenie backend Server\n\n### Clone the project\nThe 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.\n```bash\ngit clone https://github.com/sirocco-ventures/raggenie\n```\nMove into the project using\n```bash\ncd raggenie\n```\n\n### Install Requirements\nOnce 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.\n```bash\npoetry install\n```\nYou can find more info for setting up poetry [here](../Prerequesites.md)\n\n### To run server\nAfter 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.\n```bash\npython main.py --config ./config/config.yaml llm\n```\n\nBelow is a sample configuration for the vector database setup in `config.yaml`:\n\n```yaml\nvector_db:\nname: \"chroma\"\nparams:\n    path: \"./vector_db\"\n    embeddings:\n    provider: \"chroma_default\"\n```\n"
  },
  {
    "path": "documents/docs/How to run raggenie/To run raggenie ui server.md",
    "content": "---\nsidebar_position: 2\n---\n\n# To run raggenie ui server\n\n### Go to the project ui directory\nThe 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.\n```bash\ncd raggenie/ui\n```\n\n### Install dependencies\nOnce 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.\n```bash\nnpm install\n```\nRaggenie uses Node.js for frontend, for more details visit [Prerequesites](../Prerequesites.md)\n\n### Start the server\nAfter installing the dependencies, you can start the development server, which will launch the raggenie UI in your browser.\n```bash\nnpm run dev\n```"
  },
  {
    "path": "documents/docs/How to run raggenie/Using Docker.md",
    "content": "---\nsidebar_position: 3\n---\n\n# Using Docker\nThe 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.\n\nIf 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.\n```bash\ndocker compose up\n```"
  },
  {
    "path": "documents/docs/How to run raggenie/_category_.json",
    "content": "{\n  \"label\": \"How to run raggenie\",\n  \"position\": 2,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"description\": \"Steps to run raggenie\"\n  }\n}\n"
  },
  {
    "path": "documents/docs/LLM Inferences.md",
    "content": "---\nsidebar_position: 6\n---\n\n# LLM Inferences\n\nWe currently support these LLM Inference endpoints.\n* [OpenAI](https://openai.com/index/openai-api/)\n* [Together.ai](https://www.together.ai/)"
  },
  {
    "path": "documents/docs/Prerequesites.md",
    "content": "---\nsidebar_position: 1\n---\n\n# Prerequesites\n\n## Backend\n\n### Python\nRaggenie 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.\n\n#### Poetry\nPoetry is required to install and run the dependancies for raggenie backend, you can install poetry,\n\n* using pip\n  ```bash\n  pip install poetry\n  ```\n\n* using curl\n  ```bash\n  curl -sSL https://install.python-poetry.org | python3 -\n  ```\nFor more detailed explanation you can follow official [documentation](https://python-poetry.org/docs/#installation).\n\nTo install rest of dependancies run\n```bash\npoetry install\n```\n\n## Frontend\n\n### Node.js\nThe 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.\n\n### Npm\nYou needs to use npm to install the requirements for ui, it is usually installed with Node.js\nTo install ui dependancies\n* go to ui folder\n  ```bash\n  cd ui\n  ```\n\n* install dependancies\n  ```bash\n  npm install\n  ```\n\n## Docker\n\nRaggenie 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)"
  },
  {
    "path": "documents/docusaurus.config.js",
    "content": "// @ts-check\n// `@type` JSDoc annotations allow editor autocompletion and type checking\n// (when paired with `@ts-check`).\n// There are various equivalent ways to declare your Docusaurus config.\n// See: https://docusaurus.io/docs/api/docusaurus-config\n\nimport {themes as prismThemes} from 'prism-react-renderer';\n\n/** @type {import('@docusaurus/types').Config} */\nconst config = {\n  title: 'Raggenie',\n  // tagline: 'Dinosaurs are cool'\n\n  // Set the production url of your site here\n  url: 'https://sirocco-ventures.github.io',\n  // Set the /<baseUrl>/ pathname under which your site is served\n  // For GitHub pages deployment, it is often '/<projectName>/'\n  baseUrl: '/raggenie/',\n\n  // GitHub pages deployment config.\n  // If you aren't using GitHub pages, you don't need these.\n  organizationName: 'sirocco ventures', // Usually your GitHub org/user name.\n  projectName: 'raggenie', // Usually your repo name.\n\n  onBrokenLinks: 'throw',\n  onBrokenMarkdownLinks: 'warn',\n\n  // Even if you don't use internationalization, you can use this field to set\n  // useful metadata like html lang. For example, if your site is Chinese, you\n  // may want to replace \"en\" with \"zh-Hans\".\n  i18n: {\n    defaultLocale: 'en',\n    locales: ['en'],\n  },\n\n  presets: [\n    [\n      'classic',\n      /** @type {import('@docusaurus/preset-classic').Options} */\n      ({\n        docs: {\n          sidebarPath: './sidebars.js',\n          // Please change this to your repo.\n          // Remove this to remove the \"edit this page\" links.\n          editUrl:\n            'https://sirocco-ventures.github.io/raggenie/tree/main/documents',\n        },\n        blog: false,\n        theme: {\n          customCss: './src/css/custom.css',\n        },\n      }),\n    ],\n  ],\n\n  themeConfig:\n    /** @type {import('@docusaurus/preset-classic').ThemeConfig} */\n    ({\n      // Replace with your project's social card\n      image: 'img/docusaurus-social-card.jpg',\n      navbar: {\n        title: 'RAGGENIE',\n        logo: {\n          alt: 'raggenie Logo',\n          src: 'https://cdn.prod.website-files.com/664e485574efd184749b7301/6658314c55210573e334ac1b_Group%2042.png',\n        },\n        items: [\n          {\n            type: 'docSidebar',\n            sidebarId: 'documentSidebar',\n            position: 'left',\n            label: 'Documents',\n          },\n          {\n            href: 'https://github.com/sirocco-ventures/raggenie',\n            label: 'GitHub',\n            position: 'right',\n          },\n        ],\n      },\n      footer: {\n        style: 'dark',\n        links: [\n          {\n            title: 'Documents',\n            items: [\n              {\n                label: 'Docs',\n                to: '/docs/Prerequesites',\n              },\n            ],\n          },\n          {\n            title: 'Community',\n            items: [\n              {\n                label: 'Slack',\n                href: 'https://join.slack.com/t/theailounge/shared_invite/zt-2ogkrruyf-FPOHuPr5hdqXl34bDWjHjw',\n              },\n            ],\n          },\n          {\n            title: 'More',\n            items: [\n              {\n                label: 'GitHub',\n                href: 'https://github.com/sirocco-ventures/raggenie',\n              },\n            ],\n          },\n        ],\n        copyright: `Copyright © ${new Date().getFullYear()} RAGGENIE DOCS. Built with Docusaurus.`,\n      },\n      prism: {\n        theme: prismThemes.github,\n        darkTheme: prismThemes.dracula,\n      },\n    }),\n};\n\nexport default config;\n"
  },
  {
    "path": "documents/package.json",
    "content": "{\n  \"name\": \"documents\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"3.5.2\",\n    \"@docusaurus/preset-classic\": \"3.5.2\",\n    \"@mdx-js/react\": \"^3.0.0\",\n    \"clsx\": \"^2.0.0\",\n    \"prism-react-renderer\": \"^2.3.0\",\n    \"react\": \"^18.0.0\",\n    \"react-dom\": \"^18.0.0\"\n  },\n  \"devDependencies\": {\n    \"@docusaurus/module-type-aliases\": \"3.5.2\",\n    \"@docusaurus/types\": \"3.5.2\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 3 chrome version\",\n      \"last 3 firefox version\",\n      \"last 5 safari version\"\n    ]\n  },\n  \"engines\": {\n    \"node\": \">=18.0\"\n  }\n}\n"
  },
  {
    "path": "documents/sidebars.js",
    "content": "/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n\n The sidebars can be generated from the filesystem, or explicitly defined here.\n\n Create as many sidebars as you want.\n */\n\n// @ts-check\n\n/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */\nconst sidebars = {\n  // By default, Docusaurus generates a sidebar from the docs folder structure\n  documentSidebar: [{type: 'autogenerated', dirName: '.'}],\n\n  // But you can create a sidebar manually\n  /*\n  tutorialSidebar: [\n    'intro',\n    'hello',\n    {\n      type: 'category',\n      label: 'Tutorial',\n      items: ['tutorial-basics/create-a-document'],\n    },\n  ],\n   */\n};\n\nexport default sidebars;\n"
  },
  {
    "path": "documents/src/css/custom.css",
    "content": "/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n:root {\n  --ifm-color-primary: #3893ff;\n  --ifm-color-primary-dark: #29784c;\n  --ifm-color-primary-darker: #277148;\n  --ifm-color-primary-darkest: #205d3b;\n  --ifm-color-primary-light: #33925d;\n  --ifm-color-primary-lighter: #359962;\n  --ifm-color-primary-lightest: #3cad6e;\n  --ifm-code-font-size: 95%;\n  --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);\n}\n\n/* For readability concerns, you should choose a lighter palette in dark mode. */\n[data-theme='dark'] {\n  --ifm-color-primary: #3893ff;\n  --ifm-color-primary-dark: #21af90;\n  --ifm-color-primary-darker: #1fa588;\n  --ifm-color-primary-darkest: #1a8870;\n  --ifm-color-primary-light: #29d5b0;\n  --ifm-color-primary-lighter: #32d8b4;\n  --ifm-color-primary-lightest: #4fddbf;\n  --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);\n}\n"
  },
  {
    "path": "documents/src/pages/index.md",
    "content": "<p align=\"center\">\n  <a href=\"https://www.raggenie.com/\">\n    <img src=\"https://cdn.prod.website-files.com/664e485574efd184749b7301/6658314c55210573e334ac1b_Group%2042.png\" width=\"150\" alt=\"RAGGENIE Logo\"></img>\n  </a>\n</p>\n\n<h1 align=\"center\">\nRAGGENIE\n</h1>\n\n## Quick start\n\n### Clone the project\n```bash\ngit clone https://github.com/sirocco-ventures/raggenie\n```\n\n### Raggenie Backend\n\n* Installing dependencies\n\n  * **Using `requirements.txt`**\n\n    To install the required dependencies with `pip`, run:\n    \n    ```bash\n    pip install -r requirements.txt\n    ```\n\n  * **Using Poetry**\n\n    First, install Poetry:\n    \n    ```bash\n    curl -sSL https://install.python-poetry.org | python3 -\n    ```\n    \n    Then, to install the dependencies, run:\n    \n    ```bash\n    poetry install\n    ```\n\n\n* Running RAGGENIE backend\n\n  To run **RAGGENIE** in API mode, specify the config file to use by running the following command:\n\n  ```bash\n  python main.py --config ./config.yaml llm\n  ```\n\n  Below is a sample configuration for the vector database setup in `config.yaml`:\n\n  ```yaml\n  vector_db:\n    name: \"chroma\"\n    params:\n      path: \"./vector_db\"\n      embeddings:\n        provider: \"chroma_default\"\n  ```\n  This configuration ensures that the RAGGENIE system connects to the `chroma` vector database and uses the default embeddings provided by Chroma.\n\n### Raggenie Frontend\n\n* **Move into the ui folder.**\n  ```\n  cd ./ui\n  ```\n\n* Install dependencies\n  ```bash\n  npm install\n  ```\n\n* Running RAGGENIE Frontend\n\n  * To run **RAGGENIE** frontend, create a .env file and add the URL to backend as env variables\n    ```env\n    VITE_BACKEND_URL=${BACKEND_URL}\n    ```\n\n  * To start the server, run\n    ```bash\n    npm run dev\n    ```\n\n\n<!-- ### Using RAGGENIE backend API\nTo run just the backend API you can run -->\n### Using Docker\nBoth docker file and the docker compose files are present in the root folder. To run the model you can run\n```bash\ndocker compose up\n```\n\n## Connectors/pluggins\nDifferent components in your LLM app can be inserted using plugins.\n### Data Sources\nCurrently these are the datasource plugins that are available in raggenie.\n#### Structred Datasources\n* [Postgressql](./docs/Connectors/Postgressql)\n* [Airtable](./docs/Connectors/Airtable)\n* [Bigquery](./docs/Connectors/Bigquery)\n#### Unstrunctured Datasources\n* [PDFs](./docs/Connectors/PDFs)\n* [Websites](./docs/Connectors/Websites)\n\n\n## LLM Inferences\nWe currently support these LLM Inference endpoints.\n* [OpenAI](https://openai.com/index/openai-api/)\n* [Together.ai](https://www.together.ai/)"
  },
  {
    "path": "documents/src/pages/index.module.css",
    "content": "/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 4rem 0;\n  text-align: center;\n  position: relative;\n  overflow: hidden;\n}\n\n@media screen and (max-width: 996px) {\n  .heroBanner {\n    padding: 2rem;\n  }\n}\n\n.buttons {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n"
  },
  {
    "path": "documents/static/.nojekyll",
    "content": ""
  },
  {
    "path": "embeddings/onnx/tokenizer.json",
    "content": "{\n  \"version\": \"1.0\",\n  \"truncation\": {\n    \"direction\": \"Right\",\n    \"max_length\": 128,\n    \"strategy\": \"LongestFirst\",\n    \"stride\": 0\n  },\n  \"padding\": {\n    \"strategy\": {\n      \"Fixed\": 128\n    },\n    \"direction\": \"Right\",\n    \"pad_to_multiple_of\": null,\n    \"pad_id\": 0,\n    \"pad_type_id\": 0,\n    \"pad_token\": \"[PAD]\"\n  },\n  \"added_tokens\": [\n    {\n      \"id\": 0,\n      \"content\": \"[PAD]\",\n      \"single_word\": false,\n      \"lstrip\": false,\n      \"rstrip\": false,\n      \"normalized\": false,\n      \"special\": true\n    },\n    {\n      \"id\": 100,\n      \"content\": \"[UNK]\",\n      \"single_word\": false,\n      \"lstrip\": false,\n      \"rstrip\": false,\n      \"normalized\": false,\n      \"special\": true\n    },\n    {\n      \"id\": 101,\n      \"content\": \"[CLS]\",\n      \"single_word\": false,\n      \"lstrip\": false,\n      \"rstrip\": false,\n      \"normalized\": false,\n      \"special\": true\n    },\n    {\n      \"id\": 102,\n      \"content\": \"[SEP]\",\n      \"single_word\": false,\n      \"lstrip\": false,\n      \"rstrip\": false,\n      \"normalized\": false,\n      \"special\": true\n    },\n    {\n      \"id\": 103,\n      \"content\": \"[MASK]\",\n      \"single_word\": false,\n      \"lstrip\": false,\n      \"rstrip\": false,\n      \"normalized\": false,\n      \"special\": true\n    }\n  ],\n  \"normalizer\": {\n    \"type\": \"BertNormalizer\",\n    \"clean_text\": true,\n    \"handle_chinese_chars\": true,\n    \"strip_accents\": null,\n    \"lowercase\": true\n  },\n  \"pre_tokenizer\": {\n    \"type\": \"BertPreTokenizer\"\n  },\n  \"post_processor\": {\n    \"type\": \"TemplateProcessing\",\n    \"single\": [\n      {\n        \"SpecialToken\": {\n          \"id\": \"[CLS]\",\n          \"type_id\": 0\n        }\n      },\n      {\n        \"Sequence\": {\n          \"id\": \"A\",\n          \"type_id\": 0\n        }\n      },\n      {\n        \"SpecialToken\": {\n          \"id\": \"[SEP]\",\n          \"type_id\": 0\n        }\n      }\n    ],\n    \"pair\": [\n      {\n        \"SpecialToken\": {\n          \"id\": \"[CLS]\",\n          \"type_id\": 0\n        }\n      },\n      {\n        \"Sequence\": {\n          \"id\": \"A\",\n          \"type_id\": 0\n        }\n      },\n      {\n        \"SpecialToken\": {\n          \"id\": \"[SEP]\",\n          \"type_id\": 0\n        }\n      },\n      {\n        \"Sequence\": {\n          \"id\": \"B\",\n          \"type_id\": 1\n        }\n      },\n      {\n        \"SpecialToken\": {\n          \"id\": \"[SEP]\",\n          \"type_id\": 1\n        }\n      }\n    ],\n    \"special_tokens\": {\n      \"[CLS]\": {\n        \"id\": \"[CLS]\",\n        \"ids\": [\n          101\n        ],\n        \"tokens\": [\n          \"[CLS]\"\n        ]\n      },\n      \"[SEP]\": {\n        \"id\": \"[SEP]\",\n        \"ids\": [\n          102\n        ],\n        \"tokens\": [\n          \"[SEP]\"\n        ]\n      }\n    }\n  },\n  \"decoder\": {\n    \"type\": \"WordPiece\",\n    \"prefix\": \"##\",\n    \"cleanup\": true\n  },\n  \"model\": {\n    \"type\": \"WordPiece\",\n    \"unk_token\": \"[UNK]\",\n    \"continuing_subword_prefix\": \"##\",\n    \"max_input_chars_per_word\": 100,\n    \"vocab\": {\n      \"[PAD]\": 0,\n      \"[unused0]\": 1,\n      \"[unused1]\": 2,\n      \"[unused2]\": 3,\n      \"[unused3]\": 4,\n      \"[unused4]\": 5,\n      \"[unused5]\": 6,\n      \"[unused6]\": 7,\n      \"[unused7]\": 8,\n      \"[unused8]\": 9,\n      \"[unused9]\": 10,\n      \"[unused10]\": 11,\n      \"[unused11]\": 12,\n      \"[unused12]\": 13,\n      \"[unused13]\": 14,\n      \"[unused14]\": 15,\n      \"[unused15]\": 16,\n      \"[unused16]\": 17,\n      \"[unused17]\": 18,\n      \"[unused18]\": 19,\n      \"[unused19]\": 20,\n      \"[unused20]\": 21,\n      \"[unused21]\": 22,\n      \"[unused22]\": 23,\n      \"[unused23]\": 24,\n      \"[unused24]\": 25,\n      \"[unused25]\": 26,\n      \"[unused26]\": 27,\n      \"[unused27]\": 28,\n      \"[unused28]\": 29,\n      \"[unused29]\": 30,\n      \"[unused30]\": 31,\n      \"[unused31]\": 32,\n      \"[unused32]\": 33,\n      \"[unused33]\": 34,\n      \"[unused34]\": 35,\n      \"[unused35]\": 36,\n      \"[unused36]\": 37,\n      \"[unused37]\": 38,\n      \"[unused38]\": 39,\n      \"[unused39]\": 40,\n      \"[unused40]\": 41,\n      \"[unused41]\": 42,\n      \"[unused42]\": 43,\n      \"[unused43]\": 44,\n      \"[unused44]\": 45,\n      \"[unused45]\": 46,\n      \"[unused46]\": 47,\n      \"[unused47]\": 48,\n      \"[unused48]\": 49,\n      \"[unused49]\": 50,\n      \"[unused50]\": 51,\n      \"[unused51]\": 52,\n      \"[unused52]\": 53,\n      \"[unused53]\": 54,\n      \"[unused54]\": 55,\n      \"[unused55]\": 56,\n      \"[unused56]\": 57,\n      \"[unused57]\": 58,\n      \"[unused58]\": 59,\n      \"[unused59]\": 60,\n      \"[unused60]\": 61,\n      \"[unused61]\": 62,\n      \"[unused62]\": 63,\n      \"[unused63]\": 64,\n      \"[unused64]\": 65,\n      \"[unused65]\": 66,\n      \"[unused66]\": 67,\n      \"[unused67]\": 68,\n      \"[unused68]\": 69,\n      \"[unused69]\": 70,\n      \"[unused70]\": 71,\n      \"[unused71]\": 72,\n      \"[unused72]\": 73,\n      \"[unused73]\": 74,\n      \"[unused74]\": 75,\n      \"[unused75]\": 76,\n      \"[unused76]\": 77,\n      \"[unused77]\": 78,\n      \"[unused78]\": 79,\n      \"[unused79]\": 80,\n      \"[unused80]\": 81,\n      \"[unused81]\": 82,\n      \"[unused82]\": 83,\n      \"[unused83]\": 84,\n      \"[unused84]\": 85,\n      \"[unused85]\": 86,\n      \"[unused86]\": 87,\n      \"[unused87]\": 88,\n      \"[unused88]\": 89,\n      \"[unused89]\": 90,\n      \"[unused90]\": 91,\n      \"[unused91]\": 92,\n      \"[unused92]\": 93,\n      \"[unused93]\": 94,\n      \"[unused94]\": 95,\n      \"[unused95]\": 96,\n      \"[unused96]\": 97,\n      \"[unused97]\": 98,\n      \"[unused98]\": 99,\n      \"[UNK]\": 100,\n      \"[CLS]\": 101,\n      \"[SEP]\": 102,\n      \"[MASK]\": 103,\n      \"[unused99]\": 104,\n      \"[unused100]\": 105,\n      \"[unused101]\": 106,\n      \"[unused102]\": 107,\n      \"[unused103]\": 108,\n      \"[unused104]\": 109,\n      \"[unused105]\": 110,\n      \"[unused106]\": 111,\n      \"[unused107]\": 112,\n      \"[unused108]\": 113,\n      \"[unused109]\": 114,\n      \"[unused110]\": 115,\n      \"[unused111]\": 116,\n      \"[unused112]\": 117,\n      \"[unused113]\": 118,\n      \"[unused114]\": 119,\n      \"[unused115]\": 120,\n      \"[unused116]\": 121,\n      \"[unused117]\": 122,\n      \"[unused118]\": 123,\n      \"[unused119]\": 124,\n      \"[unused120]\": 125,\n      \"[unused121]\": 126,\n      \"[unused122]\": 127,\n      \"[unused123]\": 128,\n      \"[unused124]\": 129,\n      \"[unused125]\": 130,\n      \"[unused126]\": 131,\n      \"[unused127]\": 132,\n      \"[unused128]\": 133,\n      \"[unused129]\": 134,\n      \"[unused130]\": 135,\n      \"[unused131]\": 136,\n      \"[unused132]\": 137,\n      \"[unused133]\": 138,\n      \"[unused134]\": 139,\n      \"[unused135]\": 140,\n      \"[unused136]\": 141,\n      \"[unused137]\": 142,\n      \"[unused138]\": 143,\n      \"[unused139]\": 144,\n      \"[unused140]\": 145,\n      \"[unused141]\": 146,\n      \"[unused142]\": 147,\n      \"[unused143]\": 148,\n      \"[unused144]\": 149,\n      \"[unused145]\": 150,\n      \"[unused146]\": 151,\n      \"[unused147]\": 152,\n      \"[unused148]\": 153,\n      \"[unused149]\": 154,\n      \"[unused150]\": 155,\n      \"[unused151]\": 156,\n      \"[unused152]\": 157,\n      \"[unused153]\": 158,\n      \"[unused154]\": 159,\n      \"[unused155]\": 160,\n      \"[unused156]\": 161,\n      \"[unused157]\": 162,\n      \"[unused158]\": 163,\n      \"[unused159]\": 164,\n      \"[unused160]\": 165,\n      \"[unused161]\": 166,\n      \"[unused162]\": 167,\n      \"[unused163]\": 168,\n      \"[unused164]\": 169,\n      \"[unused165]\": 170,\n      \"[unused166]\": 171,\n      \"[unused167]\": 172,\n      \"[unused168]\": 173,\n      \"[unused169]\": 174,\n      \"[unused170]\": 175,\n      \"[unused171]\": 176,\n      \"[unused172]\": 177,\n      \"[unused173]\": 178,\n      \"[unused174]\": 179,\n      \"[unused175]\": 180,\n      \"[unused176]\": 181,\n      \"[unused177]\": 182,\n      \"[unused178]\": 183,\n      \"[unused179]\": 184,\n      \"[unused180]\": 185,\n      \"[unused181]\": 186,\n      \"[unused182]\": 187,\n      \"[unused183]\": 188,\n      \"[unused184]\": 189,\n      \"[unused185]\": 190,\n      \"[unused186]\": 191,\n      \"[unused187]\": 192,\n      \"[unused188]\": 193,\n      \"[unused189]\": 194,\n      \"[unused190]\": 195,\n      \"[unused191]\": 196,\n      \"[unused192]\": 197,\n      \"[unused193]\": 198,\n      \"[unused194]\": 199,\n      \"[unused195]\": 200,\n      \"[unused196]\": 201,\n      \"[unused197]\": 202,\n      \"[unused198]\": 203,\n      \"[unused199]\": 204,\n      \"[unused200]\": 205,\n      \"[unused201]\": 206,\n      \"[unused202]\": 207,\n      \"[unused203]\": 208,\n      \"[unused204]\": 209,\n      \"[unused205]\": 210,\n      \"[unused206]\": 211,\n      \"[unused207]\": 212,\n      \"[unused208]\": 213,\n      \"[unused209]\": 214,\n      \"[unused210]\": 215,\n      \"[unused211]\": 216,\n      \"[unused212]\": 217,\n      \"[unused213]\": 218,\n      \"[unused214]\": 219,\n      \"[unused215]\": 220,\n      \"[unused216]\": 221,\n      \"[unused217]\": 222,\n      \"[unused218]\": 223,\n      \"[unused219]\": 224,\n      \"[unused220]\": 225,\n      \"[unused221]\": 226,\n      \"[unused222]\": 227,\n      \"[unused223]\": 228,\n      \"[unused224]\": 229,\n      \"[unused225]\": 230,\n      \"[unused226]\": 231,\n      \"[unused227]\": 232,\n      \"[unused228]\": 233,\n      \"[unused229]\": 234,\n      \"[unused230]\": 235,\n      \"[unused231]\": 236,\n      \"[unused232]\": 237,\n      \"[unused233]\": 238,\n      \"[unused234]\": 239,\n      \"[unused235]\": 240,\n      \"[unused236]\": 241,\n      \"[unused237]\": 242,\n      \"[unused238]\": 243,\n      \"[unused239]\": 244,\n      \"[unused240]\": 245,\n      \"[unused241]\": 246,\n      \"[unused242]\": 247,\n      \"[unused243]\": 248,\n      \"[unused244]\": 249,\n      \"[unused245]\": 250,\n      \"[unused246]\": 251,\n      \"[unused247]\": 252,\n      \"[unused248]\": 253,\n      \"[unused249]\": 254,\n      \"[unused250]\": 255,\n      \"[unused251]\": 256,\n      \"[unused252]\": 257,\n      \"[unused253]\": 258,\n      \"[unused254]\": 259,\n      \"[unused255]\": 260,\n      \"[unused256]\": 261,\n      \"[unused257]\": 262,\n      \"[unused258]\": 263,\n      \"[unused259]\": 264,\n      \"[unused260]\": 265,\n      \"[unused261]\": 266,\n      \"[unused262]\": 267,\n      \"[unused263]\": 268,\n      \"[unused264]\": 269,\n      \"[unused265]\": 270,\n      \"[unused266]\": 271,\n      \"[unused267]\": 272,\n      \"[unused268]\": 273,\n      \"[unused269]\": 274,\n      \"[unused270]\": 275,\n      \"[unused271]\": 276,\n      \"[unused272]\": 277,\n      \"[unused273]\": 278,\n      \"[unused274]\": 279,\n      \"[unused275]\": 280,\n      \"[unused276]\": 281,\n      \"[unused277]\": 282,\n      \"[unused278]\": 283,\n      \"[unused279]\": 284,\n      \"[unused280]\": 285,\n      \"[unused281]\": 286,\n      \"[unused282]\": 287,\n      \"[unused283]\": 288,\n      \"[unused284]\": 289,\n      \"[unused285]\": 290,\n      \"[unused286]\": 291,\n      \"[unused287]\": 292,\n      \"[unused288]\": 293,\n      \"[unused289]\": 294,\n      \"[unused290]\": 295,\n      \"[unused291]\": 296,\n      \"[unused292]\": 297,\n      \"[unused293]\": 298,\n      \"[unused294]\": 299,\n      \"[unused295]\": 300,\n      \"[unused296]\": 301,\n      \"[unused297]\": 302,\n      \"[unused298]\": 303,\n      \"[unused299]\": 304,\n      \"[unused300]\": 305,\n      \"[unused301]\": 306,\n      \"[unused302]\": 307,\n      \"[unused303]\": 308,\n      \"[unused304]\": 309,\n      \"[unused305]\": 310,\n      \"[unused306]\": 311,\n      \"[unused307]\": 312,\n      \"[unused308]\": 313,\n      \"[unused309]\": 314,\n      \"[unused310]\": 315,\n      \"[unused311]\": 316,\n      \"[unused312]\": 317,\n      \"[unused313]\": 318,\n      \"[unused314]\": 319,\n      \"[unused315]\": 320,\n      \"[unused316]\": 321,\n      \"[unused317]\": 322,\n      \"[unused318]\": 323,\n      \"[unused319]\": 324,\n      \"[unused320]\": 325,\n      \"[unused321]\": 326,\n      \"[unused322]\": 327,\n      \"[unused323]\": 328,\n      \"[unused324]\": 329,\n      \"[unused325]\": 330,\n      \"[unused326]\": 331,\n      \"[unused327]\": 332,\n      \"[unused328]\": 333,\n      \"[unused329]\": 334,\n      \"[unused330]\": 335,\n      \"[unused331]\": 336,\n      \"[unused332]\": 337,\n      \"[unused333]\": 338,\n      \"[unused334]\": 339,\n      \"[unused335]\": 340,\n      \"[unused336]\": 341,\n      \"[unused337]\": 342,\n      \"[unused338]\": 343,\n      \"[unused339]\": 344,\n      \"[unused340]\": 345,\n      \"[unused341]\": 346,\n      \"[unused342]\": 347,\n      \"[unused343]\": 348,\n      \"[unused344]\": 349,\n      \"[unused345]\": 350,\n      \"[unused346]\": 351,\n      \"[unused347]\": 352,\n      \"[unused348]\": 353,\n      \"[unused349]\": 354,\n      \"[unused350]\": 355,\n      \"[unused351]\": 356,\n      \"[unused352]\": 357,\n      \"[unused353]\": 358,\n      \"[unused354]\": 359,\n      \"[unused355]\": 360,\n      \"[unused356]\": 361,\n      \"[unused357]\": 362,\n      \"[unused358]\": 363,\n      \"[unused359]\": 364,\n      \"[unused360]\": 365,\n      \"[unused361]\": 366,\n      \"[unused362]\": 367,\n      \"[unused363]\": 368,\n      \"[unused364]\": 369,\n      \"[unused365]\": 370,\n      \"[unused366]\": 371,\n      \"[unused367]\": 372,\n      \"[unused368]\": 373,\n      \"[unused369]\": 374,\n      \"[unused370]\": 375,\n      \"[unused371]\": 376,\n      \"[unused372]\": 377,\n      \"[unused373]\": 378,\n      \"[unused374]\": 379,\n      \"[unused375]\": 380,\n      \"[unused376]\": 381,\n      \"[unused377]\": 382,\n      \"[unused378]\": 383,\n      \"[unused379]\": 384,\n      \"[unused380]\": 385,\n      \"[unused381]\": 386,\n      \"[unused382]\": 387,\n      \"[unused383]\": 388,\n      \"[unused384]\": 389,\n      \"[unused385]\": 390,\n      \"[unused386]\": 391,\n      \"[unused387]\": 392,\n      \"[unused388]\": 393,\n      \"[unused389]\": 394,\n      \"[unused390]\": 395,\n      \"[unused391]\": 396,\n      \"[unused392]\": 397,\n      \"[unused393]\": 398,\n      \"[unused394]\": 399,\n      \"[unused395]\": 400,\n      \"[unused396]\": 401,\n      \"[unused397]\": 402,\n      \"[unused398]\": 403,\n      \"[unused399]\": 404,\n      \"[unused400]\": 405,\n      \"[unused401]\": 406,\n      \"[unused402]\": 407,\n      \"[unused403]\": 408,\n      \"[unused404]\": 409,\n      \"[unused405]\": 410,\n      \"[unused406]\": 411,\n      \"[unused407]\": 412,\n      \"[unused408]\": 413,\n      \"[unused409]\": 414,\n      \"[unused410]\": 415,\n      \"[unused411]\": 416,\n      \"[unused412]\": 417,\n      \"[unused413]\": 418,\n      \"[unused414]\": 419,\n      \"[unused415]\": 420,\n      \"[unused416]\": 421,\n      \"[unused417]\": 422,\n      \"[unused418]\": 423,\n      \"[unused419]\": 424,\n      \"[unused420]\": 425,\n      \"[unused421]\": 426,\n      \"[unused422]\": 427,\n      \"[unused423]\": 428,\n      \"[unused424]\": 429,\n      \"[unused425]\": 430,\n      \"[unused426]\": 431,\n      \"[unused427]\": 432,\n      \"[unused428]\": 433,\n      \"[unused429]\": 434,\n      \"[unused430]\": 435,\n      \"[unused431]\": 436,\n      \"[unused432]\": 437,\n      \"[unused433]\": 438,\n      \"[unused434]\": 439,\n      \"[unused435]\": 440,\n      \"[unused436]\": 441,\n      \"[unused437]\": 442,\n      \"[unused438]\": 443,\n      \"[unused439]\": 444,\n      \"[unused440]\": 445,\n      \"[unused441]\": 446,\n      \"[unused442]\": 447,\n      \"[unused443]\": 448,\n      \"[unused444]\": 449,\n      \"[unused445]\": 450,\n      \"[unused446]\": 451,\n      \"[unused447]\": 452,\n      \"[unused448]\": 453,\n      \"[unused449]\": 454,\n      \"[unused450]\": 455,\n      \"[unused451]\": 456,\n      \"[unused452]\": 457,\n      \"[unused453]\": 458,\n      \"[unused454]\": 459,\n      \"[unused455]\": 460,\n      \"[unused456]\": 461,\n      \"[unused457]\": 462,\n      \"[unused458]\": 463,\n      \"[unused459]\": 464,\n      \"[unused460]\": 465,\n      \"[unused461]\": 466,\n      \"[unused462]\": 467,\n      \"[unused463]\": 468,\n      \"[unused464]\": 469,\n      \"[unused465]\": 470,\n      \"[unused466]\": 471,\n      \"[unused467]\": 472,\n      \"[unused468]\": 473,\n      \"[unused469]\": 474,\n      \"[unused470]\": 475,\n      \"[unused471]\": 476,\n      \"[unused472]\": 477,\n      \"[unused473]\": 478,\n      \"[unused474]\": 479,\n      \"[unused475]\": 480,\n      \"[unused476]\": 481,\n      \"[unused477]\": 482,\n      \"[unused478]\": 483,\n      \"[unused479]\": 484,\n      \"[unused480]\": 485,\n      \"[unused481]\": 486,\n      \"[unused482]\": 487,\n      \"[unused483]\": 488,\n      \"[unused484]\": 489,\n      \"[unused485]\": 490,\n      \"[unused486]\": 491,\n      \"[unused487]\": 492,\n      \"[unused488]\": 493,\n      \"[unused489]\": 494,\n      \"[unused490]\": 495,\n      \"[unused491]\": 496,\n      \"[unused492]\": 497,\n      \"[unused493]\": 498,\n      \"[unused494]\": 499,\n      \"[unused495]\": 500,\n      \"[unused496]\": 501,\n      \"[unused497]\": 502,\n      \"[unused498]\": 503,\n      \"[unused499]\": 504,\n      \"[unused500]\": 505,\n      \"[unused501]\": 506,\n      \"[unused502]\": 507,\n      \"[unused503]\": 508,\n      \"[unused504]\": 509,\n      \"[unused505]\": 510,\n      \"[unused506]\": 511,\n      \"[unused507]\": 512,\n      \"[unused508]\": 513,\n      \"[unused509]\": 514,\n      \"[unused510]\": 515,\n      \"[unused511]\": 516,\n      \"[unused512]\": 517,\n      \"[unused513]\": 518,\n      \"[unused514]\": 519,\n      \"[unused515]\": 520,\n      \"[unused516]\": 521,\n      \"[unused517]\": 522,\n      \"[unused518]\": 523,\n      \"[unused519]\": 524,\n      \"[unused520]\": 525,\n      \"[unused521]\": 526,\n      \"[unused522]\": 527,\n      \"[unused523]\": 528,\n      \"[unused524]\": 529,\n      \"[unused525]\": 530,\n      \"[unused526]\": 531,\n      \"[unused527]\": 532,\n      \"[unused528]\": 533,\n      \"[unused529]\": 534,\n      \"[unused530]\": 535,\n      \"[unused531]\": 536,\n      \"[unused532]\": 537,\n      \"[unused533]\": 538,\n      \"[unused534]\": 539,\n      \"[unused535]\": 540,\n      \"[unused536]\": 541,\n      \"[unused537]\": 542,\n      \"[unused538]\": 543,\n      \"[unused539]\": 544,\n      \"[unused540]\": 545,\n      \"[unused541]\": 546,\n      \"[unused542]\": 547,\n      \"[unused543]\": 548,\n      \"[unused544]\": 549,\n      \"[unused545]\": 550,\n      \"[unused546]\": 551,\n      \"[unused547]\": 552,\n      \"[unused548]\": 553,\n      \"[unused549]\": 554,\n      \"[unused550]\": 555,\n      \"[unused551]\": 556,\n      \"[unused552]\": 557,\n      \"[unused553]\": 558,\n      \"[unused554]\": 559,\n      \"[unused555]\": 560,\n      \"[unused556]\": 561,\n      \"[unused557]\": 562,\n      \"[unused558]\": 563,\n      \"[unused559]\": 564,\n      \"[unused560]\": 565,\n      \"[unused561]\": 566,\n      \"[unused562]\": 567,\n      \"[unused563]\": 568,\n      \"[unused564]\": 569,\n      \"[unused565]\": 570,\n      \"[unused566]\": 571,\n      \"[unused567]\": 572,\n      \"[unused568]\": 573,\n      \"[unused569]\": 574,\n      \"[unused570]\": 575,\n      \"[unused571]\": 576,\n      \"[unused572]\": 577,\n      \"[unused573]\": 578,\n      \"[unused574]\": 579,\n      \"[unused575]\": 580,\n      \"[unused576]\": 581,\n      \"[unused577]\": 582,\n      \"[unused578]\": 583,\n      \"[unused579]\": 584,\n      \"[unused580]\": 585,\n      \"[unused581]\": 586,\n      \"[unused582]\": 587,\n      \"[unused583]\": 588,\n      \"[unused584]\": 589,\n      \"[unused585]\": 590,\n      \"[unused586]\": 591,\n      \"[unused587]\": 592,\n      \"[unused588]\": 593,\n      \"[unused589]\": 594,\n      \"[unused590]\": 595,\n      \"[unused591]\": 596,\n      \"[unused592]\": 597,\n      \"[unused593]\": 598,\n      \"[unused594]\": 599,\n      \"[unused595]\": 600,\n      \"[unused596]\": 601,\n      \"[unused597]\": 602,\n      \"[unused598]\": 603,\n      \"[unused599]\": 604,\n      \"[unused600]\": 605,\n      \"[unused601]\": 606,\n      \"[unused602]\": 607,\n      \"[unused603]\": 608,\n      \"[unused604]\": 609,\n      \"[unused605]\": 610,\n      \"[unused606]\": 611,\n      \"[unused607]\": 612,\n      \"[unused608]\": 613,\n      \"[unused609]\": 614,\n      \"[unused610]\": 615,\n      \"[unused611]\": 616,\n      \"[unused612]\": 617,\n      \"[unused613]\": 618,\n      \"[unused614]\": 619,\n      \"[unused615]\": 620,\n      \"[unused616]\": 621,\n      \"[unused617]\": 622,\n      \"[unused618]\": 623,\n      \"[unused619]\": 624,\n      \"[unused620]\": 625,\n      \"[unused621]\": 626,\n      \"[unused622]\": 627,\n      \"[unused623]\": 628,\n      \"[unused624]\": 629,\n      \"[unused625]\": 630,\n      \"[unused626]\": 631,\n      \"[unused627]\": 632,\n      \"[unused628]\": 633,\n      \"[unused629]\": 634,\n      \"[unused630]\": 635,\n      \"[unused631]\": 636,\n      \"[unused632]\": 637,\n      \"[unused633]\": 638,\n      \"[unused634]\": 639,\n      \"[unused635]\": 640,\n      \"[unused636]\": 641,\n      \"[unused637]\": 642,\n      \"[unused638]\": 643,\n      \"[unused639]\": 644,\n      \"[unused640]\": 645,\n      \"[unused641]\": 646,\n      \"[unused642]\": 647,\n      \"[unused643]\": 648,\n      \"[unused644]\": 649,\n      \"[unused645]\": 650,\n      \"[unused646]\": 651,\n      \"[unused647]\": 652,\n      \"[unused648]\": 653,\n      \"[unused649]\": 654,\n      \"[unused650]\": 655,\n      \"[unused651]\": 656,\n      \"[unused652]\": 657,\n      \"[unused653]\": 658,\n      \"[unused654]\": 659,\n      \"[unused655]\": 660,\n      \"[unused656]\": 661,\n      \"[unused657]\": 662,\n      \"[unused658]\": 663,\n      \"[unused659]\": 664,\n      \"[unused660]\": 665,\n      \"[unused661]\": 666,\n      \"[unused662]\": 667,\n      \"[unused663]\": 668,\n      \"[unused664]\": 669,\n      \"[unused665]\": 670,\n      \"[unused666]\": 671,\n      \"[unused667]\": 672,\n      \"[unused668]\": 673,\n      \"[unused669]\": 674,\n      \"[unused670]\": 675,\n      \"[unused671]\": 676,\n      \"[unused672]\": 677,\n      \"[unused673]\": 678,\n      \"[unused674]\": 679,\n      \"[unused675]\": 680,\n      \"[unused676]\": 681,\n      \"[unused677]\": 682,\n      \"[unused678]\": 683,\n      \"[unused679]\": 684,\n      \"[unused680]\": 685,\n      \"[unused681]\": 686,\n      \"[unused682]\": 687,\n      \"[unused683]\": 688,\n      \"[unused684]\": 689,\n      \"[unused685]\": 690,\n      \"[unused686]\": 691,\n      \"[unused687]\": 692,\n      \"[unused688]\": 693,\n      \"[unused689]\": 694,\n      \"[unused690]\": 695,\n      \"[unused691]\": 696,\n      \"[unused692]\": 697,\n      \"[unused693]\": 698,\n      \"[unused694]\": 699,\n      \"[unused695]\": 700,\n      \"[unused696]\": 701,\n      \"[unused697]\": 702,\n      \"[unused698]\": 703,\n      \"[unused699]\": 704,\n      \"[unused700]\": 705,\n      \"[unused701]\": 706,\n      \"[unused702]\": 707,\n      \"[unused703]\": 708,\n      \"[unused704]\": 709,\n      \"[unused705]\": 710,\n      \"[unused706]\": 711,\n      \"[unused707]\": 712,\n      \"[unused708]\": 713,\n      \"[unused709]\": 714,\n      \"[unused710]\": 715,\n      \"[unused711]\": 716,\n      \"[unused712]\": 717,\n      \"[unused713]\": 718,\n      \"[unused714]\": 719,\n      \"[unused715]\": 720,\n      \"[unused716]\": 721,\n      \"[unused717]\": 722,\n      \"[unused718]\": 723,\n      \"[unused719]\": 724,\n      \"[unused720]\": 725,\n      \"[unused721]\": 726,\n      \"[unused722]\": 727,\n      \"[unused723]\": 728,\n      \"[unused724]\": 729,\n      \"[unused725]\": 730,\n      \"[unused726]\": 731,\n      \"[unused727]\": 732,\n      \"[unused728]\": 733,\n      \"[unused729]\": 734,\n      \"[unused730]\": 735,\n      \"[unused731]\": 736,\n      \"[unused732]\": 737,\n      \"[unused733]\": 738,\n      \"[unused734]\": 739,\n      \"[unused735]\": 740,\n      \"[unused736]\": 741,\n      \"[unused737]\": 742,\n      \"[unused738]\": 743,\n      \"[unused739]\": 744,\n      \"[unused740]\": 745,\n      \"[unused741]\": 746,\n      \"[unused742]\": 747,\n      \"[unused743]\": 748,\n      \"[unused744]\": 749,\n      \"[unused745]\": 750,\n      \"[unused746]\": 751,\n      \"[unused747]\": 752,\n      \"[unused748]\": 753,\n      \"[unused749]\": 754,\n      \"[unused750]\": 755,\n      \"[unused751]\": 756,\n      \"[unused752]\": 757,\n      \"[unused753]\": 758,\n      \"[unused754]\": 759,\n      \"[unused755]\": 760,\n      \"[unused756]\": 761,\n      \"[unused757]\": 762,\n      \"[unused758]\": 763,\n      \"[unused759]\": 764,\n      \"[unused760]\": 765,\n      \"[unused761]\": 766,\n      \"[unused762]\": 767,\n      \"[unused763]\": 768,\n      \"[unused764]\": 769,\n      \"[unused765]\": 770,\n      \"[unused766]\": 771,\n      \"[unused767]\": 772,\n      \"[unused768]\": 773,\n      \"[unused769]\": 774,\n      \"[unused770]\": 775,\n      \"[unused771]\": 776,\n      \"[unused772]\": 777,\n      \"[unused773]\": 778,\n      \"[unused774]\": 779,\n      \"[unused775]\": 780,\n      \"[unused776]\": 781,\n      \"[unused777]\": 782,\n      \"[unused778]\": 783,\n      \"[unused779]\": 784,\n      \"[unused780]\": 785,\n      \"[unused781]\": 786,\n      \"[unused782]\": 787,\n      \"[unused783]\": 788,\n      \"[unused784]\": 789,\n      \"[unused785]\": 790,\n      \"[unused786]\": 791,\n      \"[unused787]\": 792,\n      \"[unused788]\": 793,\n      \"[unused789]\": 794,\n      \"[unused790]\": 795,\n      \"[unused791]\": 796,\n      \"[unused792]\": 797,\n      \"[unused793]\": 798,\n      \"[unused794]\": 799,\n      \"[unused795]\": 800,\n      \"[unused796]\": 801,\n      \"[unused797]\": 802,\n      \"[unused798]\": 803,\n      \"[unused799]\": 804,\n      \"[unused800]\": 805,\n      \"[unused801]\": 806,\n      \"[unused802]\": 807,\n      \"[unused803]\": 808,\n      \"[unused804]\": 809,\n      \"[unused805]\": 810,\n      \"[unused806]\": 811,\n      \"[unused807]\": 812,\n      \"[unused808]\": 813,\n      \"[unused809]\": 814,\n      \"[unused810]\": 815,\n      \"[unused811]\": 816,\n      \"[unused812]\": 817,\n      \"[unused813]\": 818,\n      \"[unused814]\": 819,\n      \"[unused815]\": 820,\n      \"[unused816]\": 821,\n      \"[unused817]\": 822,\n      \"[unused818]\": 823,\n      \"[unused819]\": 824,\n      \"[unused820]\": 825,\n      \"[unused821]\": 826,\n      \"[unused822]\": 827,\n      \"[unused823]\": 828,\n      \"[unused824]\": 829,\n      \"[unused825]\": 830,\n      \"[unused826]\": 831,\n      \"[unused827]\": 832,\n      \"[unused828]\": 833,\n      \"[unused829]\": 834,\n      \"[unused830]\": 835,\n      \"[unused831]\": 836,\n      \"[unused832]\": 837,\n      \"[unused833]\": 838,\n      \"[unused834]\": 839,\n      \"[unused835]\": 840,\n      \"[unused836]\": 841,\n      \"[unused837]\": 842,\n      \"[unused838]\": 843,\n      \"[unused839]\": 844,\n      \"[unused840]\": 845,\n      \"[unused841]\": 846,\n      \"[unused842]\": 847,\n      \"[unused843]\": 848,\n      \"[unused844]\": 849,\n      \"[unused845]\": 850,\n      \"[unused846]\": 851,\n      \"[unused847]\": 852,\n      \"[unused848]\": 853,\n      \"[unused849]\": 854,\n      \"[unused850]\": 855,\n      \"[unused851]\": 856,\n      \"[unused852]\": 857,\n      \"[unused853]\": 858,\n      \"[unused854]\": 859,\n      \"[unused855]\": 860,\n      \"[unused856]\": 861,\n      \"[unused857]\": 862,\n      \"[unused858]\": 863,\n      \"[unused859]\": 864,\n      \"[unused860]\": 865,\n      \"[unused861]\": 866,\n      \"[unused862]\": 867,\n      \"[unused863]\": 868,\n      \"[unused864]\": 869,\n      \"[unused865]\": 870,\n      \"[unused866]\": 871,\n      \"[unused867]\": 872,\n      \"[unused868]\": 873,\n      \"[unused869]\": 874,\n      \"[unused870]\": 875,\n      \"[unused871]\": 876,\n      \"[unused872]\": 877,\n      \"[unused873]\": 878,\n      \"[unused874]\": 879,\n      \"[unused875]\": 880,\n      \"[unused876]\": 881,\n      \"[unused877]\": 882,\n      \"[unused878]\": 883,\n      \"[unused879]\": 884,\n      \"[unused880]\": 885,\n      \"[unused881]\": 886,\n      \"[unused882]\": 887,\n      \"[unused883]\": 888,\n      \"[unused884]\": 889,\n      \"[unused885]\": 890,\n      \"[unused886]\": 891,\n      \"[unused887]\": 892,\n      \"[unused888]\": 893,\n      \"[unused889]\": 894,\n      \"[unused890]\": 895,\n      \"[unused891]\": 896,\n      \"[unused892]\": 897,\n      \"[unused893]\": 898,\n      \"[unused894]\": 899,\n      \"[unused895]\": 900,\n      \"[unused896]\": 901,\n      \"[unused897]\": 902,\n      \"[unused898]\": 903,\n      \"[unused899]\": 904,\n      \"[unused900]\": 905,\n      \"[unused901]\": 906,\n      \"[unused902]\": 907,\n      \"[unused903]\": 908,\n      \"[unused904]\": 909,\n      \"[unused905]\": 910,\n      \"[unused906]\": 911,\n      \"[unused907]\": 912,\n      \"[unused908]\": 913,\n      \"[unused909]\": 914,\n      \"[unused910]\": 915,\n      \"[unused911]\": 916,\n      \"[unused912]\": 917,\n      \"[unused913]\": 918,\n      \"[unused914]\": 919,\n      \"[unused915]\": 920,\n      \"[unused916]\": 921,\n      \"[unused917]\": 922,\n      \"[unused918]\": 923,\n      \"[unused919]\": 924,\n      \"[unused920]\": 925,\n      \"[unused921]\": 926,\n      \"[unused922]\": 927,\n      \"[unused923]\": 928,\n      \"[unused924]\": 929,\n      \"[unused925]\": 930,\n      \"[unused926]\": 931,\n      \"[unused927]\": 932,\n      \"[unused928]\": 933,\n      \"[unused929]\": 934,\n      \"[unused930]\": 935,\n      \"[unused931]\": 936,\n      \"[unused932]\": 937,\n      \"[unused933]\": 938,\n      \"[unused934]\": 939,\n      \"[unused935]\": 940,\n      \"[unused936]\": 941,\n      \"[unused937]\": 942,\n      \"[unused938]\": 943,\n      \"[unused939]\": 944,\n      \"[unused940]\": 945,\n      \"[unused941]\": 946,\n      \"[unused942]\": 947,\n      \"[unused943]\": 948,\n      \"[unused944]\": 949,\n      \"[unused945]\": 950,\n      \"[unused946]\": 951,\n      \"[unused947]\": 952,\n      \"[unused948]\": 953,\n      \"[unused949]\": 954,\n      \"[unused950]\": 955,\n      \"[unused951]\": 956,\n      \"[unused952]\": 957,\n      \"[unused953]\": 958,\n      \"[unused954]\": 959,\n      \"[unused955]\": 960,\n      \"[unused956]\": 961,\n      \"[unused957]\": 962,\n      \"[unused958]\": 963,\n      \"[unused959]\": 964,\n      \"[unused960]\": 965,\n      \"[unused961]\": 966,\n      \"[unused962]\": 967,\n      \"[unused963]\": 968,\n      \"[unused964]\": 969,\n      \"[unused965]\": 970,\n      \"[unused966]\": 971,\n      \"[unused967]\": 972,\n      \"[unused968]\": 973,\n      \"[unused969]\": 974,\n      \"[unused970]\": 975,\n      \"[unused971]\": 976,\n      \"[unused972]\": 977,\n      \"[unused973]\": 978,\n      \"[unused974]\": 979,\n      \"[unused975]\": 980,\n      \"[unused976]\": 981,\n      \"[unused977]\": 982,\n      \"[unused978]\": 983,\n      \"[unused979]\": 984,\n      \"[unused980]\": 985,\n      \"[unused981]\": 986,\n      \"[unused982]\": 987,\n      \"[unused983]\": 988,\n      \"[unused984]\": 989,\n      \"[unused985]\": 990,\n      \"[unused986]\": 991,\n      \"[unused987]\": 992,\n      \"[unused988]\": 993,\n      \"[unused989]\": 994,\n      \"[unused990]\": 995,\n      \"[unused991]\": 996,\n      \"[unused992]\": 997,\n      \"[unused993]\": 998,\n      \"!\": 999,\n      \"\\\"\": 1000,\n      \"#\": 1001,\n      \"$\": 1002,\n      \"%\": 1003,\n      \"&\": 1004,\n      \"'\": 1005,\n      \"(\": 1006,\n      \")\": 1007,\n      \"*\": 1008,\n      \"+\": 1009,\n      \",\": 1010,\n      \"-\": 1011,\n      \".\": 1012,\n      \"/\": 1013,\n      \"0\": 1014,\n      \"1\": 1015,\n      \"2\": 1016,\n      \"3\": 1017,\n      \"4\": 1018,\n      \"5\": 1019,\n      \"6\": 1020,\n      \"7\": 1021,\n      \"8\": 1022,\n      \"9\": 1023,\n      \":\": 1024,\n      \";\": 1025,\n      \"<\": 1026,\n      \"=\": 1027,\n      \">\": 1028,\n      \"?\": 1029,\n      \"@\": 1030,\n      \"[\": 1031,\n      \"\\\\\": 1032,\n      \"]\": 1033,\n      \"^\": 1034,\n      \"_\": 1035,\n      \"`\": 1036,\n      \"a\": 1037,\n      \"b\": 1038,\n      \"c\": 1039,\n      \"d\": 1040,\n      \"e\": 1041,\n      \"f\": 1042,\n      \"g\": 1043,\n      \"h\": 1044,\n      \"i\": 1045,\n      \"j\": 1046,\n      \"k\": 1047,\n      \"l\": 1048,\n      \"m\": 1049,\n      \"n\": 1050,\n      \"o\": 1051,\n      \"p\": 1052,\n      \"q\": 1053,\n      \"r\": 1054,\n      \"s\": 1055,\n      \"t\": 1056,\n      \"u\": 1057,\n      \"v\": 1058,\n      \"w\": 1059,\n      \"x\": 1060,\n      \"y\": 1061,\n      \"z\": 1062,\n      \"{\": 1063,\n      \"|\": 1064,\n      \"}\": 1065,\n      \"~\": 1066,\n      \"¡\": 1067,\n      \"¢\": 1068,\n      \"£\": 1069,\n      \"¤\": 1070,\n      \"¥\": 1071,\n      \"¦\": 1072,\n      \"§\": 1073,\n      \"¨\": 1074,\n      \"©\": 1075,\n      \"ª\": 1076,\n      \"«\": 1077,\n      \"¬\": 1078,\n      \"®\": 1079,\n      \"°\": 1080,\n      \"±\": 1081,\n      \"²\": 1082,\n      \"³\": 1083,\n      \"´\": 1084,\n      \"µ\": 1085,\n      \"¶\": 1086,\n      \"·\": 1087,\n      \"¹\": 1088,\n      \"º\": 1089,\n      \"»\": 1090,\n      \"¼\": 1091,\n      \"½\": 1092,\n      \"¾\": 1093,\n      \"¿\": 1094,\n      \"×\": 1095,\n      \"ß\": 1096,\n      \"æ\": 1097,\n      \"ð\": 1098,\n      \"÷\": 1099,\n      \"ø\": 1100,\n      \"þ\": 1101,\n      \"đ\": 1102,\n      \"ħ\": 1103,\n      \"ı\": 1104,\n      \"ł\": 1105,\n      \"ŋ\": 1106,\n      \"œ\": 1107,\n      \"ƒ\": 1108,\n      \"ɐ\": 1109,\n      \"ɑ\": 1110,\n      \"ɒ\": 1111,\n      \"ɔ\": 1112,\n      \"ɕ\": 1113,\n      \"ə\": 1114,\n      \"ɛ\": 1115,\n      \"ɡ\": 1116,\n      \"ɣ\": 1117,\n      \"ɨ\": 1118,\n      \"ɪ\": 1119,\n      \"ɫ\": 1120,\n      \"ɬ\": 1121,\n      \"ɯ\": 1122,\n      \"ɲ\": 1123,\n      \"ɴ\": 1124,\n      \"ɹ\": 1125,\n      \"ɾ\": 1126,\n      \"ʀ\": 1127,\n      \"ʁ\": 1128,\n      \"ʂ\": 1129,\n      \"ʃ\": 1130,\n      \"ʉ\": 1131,\n      \"ʊ\": 1132,\n      \"ʋ\": 1133,\n      \"ʌ\": 1134,\n      \"ʎ\": 1135,\n      \"ʐ\": 1136,\n      \"ʑ\": 1137,\n      \"ʒ\": 1138,\n      \"ʔ\": 1139,\n      \"ʰ\": 1140,\n      \"ʲ\": 1141,\n      \"ʳ\": 1142,\n      \"ʷ\": 1143,\n      \"ʸ\": 1144,\n      \"ʻ\": 1145,\n      \"ʼ\": 1146,\n      \"ʾ\": 1147,\n      \"ʿ\": 1148,\n      \"ˈ\": 1149,\n      \"ː\": 1150,\n      \"ˡ\": 1151,\n      \"ˢ\": 1152,\n      \"ˣ\": 1153,\n      \"ˤ\": 1154,\n      \"α\": 1155,\n      \"β\": 1156,\n      \"γ\": 1157,\n      \"δ\": 1158,\n      \"ε\": 1159,\n      \"ζ\": 1160,\n      \"η\": 1161,\n      \"θ\": 1162,\n      \"ι\": 1163,\n      \"κ\": 1164,\n      \"λ\": 1165,\n      \"μ\": 1166,\n      \"ν\": 1167,\n      \"ξ\": 1168,\n      \"ο\": 1169,\n      \"π\": 1170,\n      \"ρ\": 1171,\n      \"ς\": 1172,\n      \"σ\": 1173,\n      \"τ\": 1174,\n      \"υ\": 1175,\n      \"φ\": 1176,\n      \"χ\": 1177,\n      \"ψ\": 1178,\n      \"ω\": 1179,\n      \"а\": 1180,\n      \"б\": 1181,\n      \"в\": 1182,\n      \"г\": 1183,\n      \"д\": 1184,\n      \"е\": 1185,\n      \"ж\": 1186,\n      \"з\": 1187,\n      \"и\": 1188,\n      \"к\": 1189,\n      \"л\": 1190,\n      \"м\": 1191,\n      \"н\": 1192,\n      \"о\": 1193,\n      \"п\": 1194,\n      \"р\": 1195,\n      \"с\": 1196,\n      \"т\": 1197,\n      \"у\": 1198,\n      \"ф\": 1199,\n      \"х\": 1200,\n      \"ц\": 1201,\n      \"ч\": 1202,\n      \"ш\": 1203,\n      \"щ\": 1204,\n      \"ъ\": 1205,\n      \"ы\": 1206,\n      \"ь\": 1207,\n      \"э\": 1208,\n      \"ю\": 1209,\n      \"я\": 1210,\n      \"ђ\": 1211,\n      \"є\": 1212,\n      \"і\": 1213,\n      \"ј\": 1214,\n      \"љ\": 1215,\n      \"њ\": 1216,\n      \"ћ\": 1217,\n      \"ӏ\": 1218,\n      \"ա\": 1219,\n      \"բ\": 1220,\n      \"գ\": 1221,\n      \"դ\": 1222,\n      \"ե\": 1223,\n      \"թ\": 1224,\n      \"ի\": 1225,\n      \"լ\": 1226,\n      \"կ\": 1227,\n      \"հ\": 1228,\n      \"մ\": 1229,\n      \"յ\": 1230,\n      \"ն\": 1231,\n      \"ո\": 1232,\n      \"պ\": 1233,\n      \"ս\": 1234,\n      \"վ\": 1235,\n      \"տ\": 1236,\n      \"ր\": 1237,\n      \"ւ\": 1238,\n      \"ք\": 1239,\n      \"־\": 1240,\n      \"א\": 1241,\n      \"ב\": 1242,\n      \"ג\": 1243,\n      \"ד\": 1244,\n      \"ה\": 1245,\n      \"ו\": 1246,\n      \"ז\": 1247,\n      \"ח\": 1248,\n      \"ט\": 1249,\n      \"י\": 1250,\n      \"ך\": 1251,\n      \"כ\": 1252,\n      \"ל\": 1253,\n      \"ם\": 1254,\n      \"מ\": 1255,\n      \"ן\": 1256,\n      \"נ\": 1257,\n      \"ס\": 1258,\n      \"ע\": 1259,\n      \"ף\": 1260,\n      \"פ\": 1261,\n      \"ץ\": 1262,\n      \"צ\": 1263,\n      \"ק\": 1264,\n      \"ר\": 1265,\n      \"ש\": 1266,\n      \"ת\": 1267,\n      \"،\": 1268,\n      \"ء\": 1269,\n      \"ا\": 1270,\n      \"ب\": 1271,\n      \"ة\": 1272,\n      \"ت\": 1273,\n      \"ث\": 1274,\n      \"ج\": 1275,\n      \"ح\": 1276,\n      \"خ\": 1277,\n      \"د\": 1278,\n      \"ذ\": 1279,\n      \"ر\": 1280,\n      \"ز\": 1281,\n      \"س\": 1282,\n      \"ش\": 1283,\n      \"ص\": 1284,\n      \"ض\": 1285,\n      \"ط\": 1286,\n      \"ظ\": 1287,\n      \"ع\": 1288,\n      \"غ\": 1289,\n      \"ـ\": 1290,\n      \"ف\": 1291,\n      \"ق\": 1292,\n      \"ك\": 1293,\n      \"ل\": 1294,\n      \"م\": 1295,\n      \"ن\": 1296,\n      \"ه\": 1297,\n      \"و\": 1298,\n      \"ى\": 1299,\n      \"ي\": 1300,\n      \"ٹ\": 1301,\n      \"پ\": 1302,\n      \"چ\": 1303,\n      \"ک\": 1304,\n      \"گ\": 1305,\n      \"ں\": 1306,\n      \"ھ\": 1307,\n      \"ہ\": 1308,\n      \"ی\": 1309,\n      \"ے\": 1310,\n      \"अ\": 1311,\n      \"आ\": 1312,\n      \"उ\": 1313,\n      \"ए\": 1314,\n      \"क\": 1315,\n      \"ख\": 1316,\n      \"ग\": 1317,\n      \"च\": 1318,\n      \"ज\": 1319,\n      \"ट\": 1320,\n      \"ड\": 1321,\n      \"ण\": 1322,\n      \"त\": 1323,\n      \"थ\": 1324,\n      \"द\": 1325,\n      \"ध\": 1326,\n      \"न\": 1327,\n      \"प\": 1328,\n      \"ब\": 1329,\n      \"भ\": 1330,\n      \"म\": 1331,\n      \"य\": 1332,\n      \"र\": 1333,\n      \"ल\": 1334,\n      \"व\": 1335,\n      \"श\": 1336,\n      \"ष\": 1337,\n      \"स\": 1338,\n      \"ह\": 1339,\n      \"ा\": 1340,\n      \"ि\": 1341,\n      \"ी\": 1342,\n      \"ो\": 1343,\n      \"।\": 1344,\n      \"॥\": 1345,\n      \"ং\": 1346,\n      \"অ\": 1347,\n      \"আ\": 1348,\n      \"ই\": 1349,\n      \"উ\": 1350,\n      \"এ\": 1351,\n      \"ও\": 1352,\n      \"ক\": 1353,\n      \"খ\": 1354,\n      \"গ\": 1355,\n      \"চ\": 1356,\n      \"ছ\": 1357,\n      \"জ\": 1358,\n      \"ট\": 1359,\n      \"ড\": 1360,\n      \"ণ\": 1361,\n      \"ত\": 1362,\n      \"থ\": 1363,\n      \"দ\": 1364,\n      \"ধ\": 1365,\n      \"ন\": 1366,\n      \"প\": 1367,\n      \"ব\": 1368,\n      \"ভ\": 1369,\n      \"ম\": 1370,\n      \"য\": 1371,\n      \"র\": 1372,\n      \"ল\": 1373,\n      \"শ\": 1374,\n      \"ষ\": 1375,\n      \"স\": 1376,\n      \"হ\": 1377,\n      \"া\": 1378,\n      \"ি\": 1379,\n      \"ী\": 1380,\n      \"ে\": 1381,\n      \"க\": 1382,\n      \"ச\": 1383,\n      \"ட\": 1384,\n      \"த\": 1385,\n      \"ந\": 1386,\n      \"ன\": 1387,\n      \"ப\": 1388,\n      \"ம\": 1389,\n      \"ய\": 1390,\n      \"ர\": 1391,\n      \"ல\": 1392,\n      \"ள\": 1393,\n      \"வ\": 1394,\n      \"ா\": 1395,\n      \"ி\": 1396,\n      \"ு\": 1397,\n      \"ே\": 1398,\n      \"ை\": 1399,\n      \"ನ\": 1400,\n      \"ರ\": 1401,\n      \"ಾ\": 1402,\n      \"ක\": 1403,\n      \"ය\": 1404,\n      \"ර\": 1405,\n      \"ල\": 1406,\n      \"ව\": 1407,\n      \"ා\": 1408,\n      \"ก\": 1409,\n      \"ง\": 1410,\n      \"ต\": 1411,\n      \"ท\": 1412,\n      \"น\": 1413,\n      \"พ\": 1414,\n      \"ม\": 1415,\n      \"ย\": 1416,\n      \"ร\": 1417,\n      \"ล\": 1418,\n      \"ว\": 1419,\n      \"ส\": 1420,\n      \"อ\": 1421,\n      \"า\": 1422,\n      \"เ\": 1423,\n      \"་\": 1424,\n      \"།\": 1425,\n      \"ག\": 1426,\n      \"ང\": 1427,\n      \"ད\": 1428,\n      \"ན\": 1429,\n      \"པ\": 1430,\n      \"བ\": 1431,\n      \"མ\": 1432,\n      \"འ\": 1433,\n      \"ར\": 1434,\n      \"ལ\": 1435,\n      \"ས\": 1436,\n      \"မ\": 1437,\n      \"ა\": 1438,\n      \"ბ\": 1439,\n      \"გ\": 1440,\n      \"დ\": 1441,\n      \"ე\": 1442,\n      \"ვ\": 1443,\n      \"თ\": 1444,\n      \"ი\": 1445,\n      \"კ\": 1446,\n      \"ლ\": 1447,\n      \"მ\": 1448,\n      \"ნ\": 1449,\n      \"ო\": 1450,\n      \"რ\": 1451,\n      \"ს\": 1452,\n      \"ტ\": 1453,\n      \"უ\": 1454,\n      \"ᄀ\": 1455,\n      \"ᄂ\": 1456,\n      \"ᄃ\": 1457,\n      \"ᄅ\": 1458,\n      \"ᄆ\": 1459,\n      \"ᄇ\": 1460,\n      \"ᄉ\": 1461,\n      \"ᄊ\": 1462,\n      \"ᄋ\": 1463,\n      \"ᄌ\": 1464,\n      \"ᄎ\": 1465,\n      \"ᄏ\": 1466,\n      \"ᄐ\": 1467,\n      \"ᄑ\": 1468,\n      \"ᄒ\": 1469,\n      \"ᅡ\": 1470,\n      \"ᅢ\": 1471,\n      \"ᅥ\": 1472,\n      \"ᅦ\": 1473,\n      \"ᅧ\": 1474,\n      \"ᅩ\": 1475,\n      \"ᅪ\": 1476,\n      \"ᅭ\": 1477,\n      \"ᅮ\": 1478,\n      \"ᅯ\": 1479,\n      \"ᅲ\": 1480,\n      \"ᅳ\": 1481,\n      \"ᅴ\": 1482,\n      \"ᅵ\": 1483,\n      \"ᆨ\": 1484,\n      \"ᆫ\": 1485,\n      \"ᆯ\": 1486,\n      \"ᆷ\": 1487,\n      \"ᆸ\": 1488,\n      \"ᆼ\": 1489,\n      \"ᴬ\": 1490,\n      \"ᴮ\": 1491,\n      \"ᴰ\": 1492,\n      \"ᴵ\": 1493,\n      \"ᴺ\": 1494,\n      \"ᵀ\": 1495,\n      \"ᵃ\": 1496,\n      \"ᵇ\": 1497,\n      \"ᵈ\": 1498,\n      \"ᵉ\": 1499,\n      \"ᵍ\": 1500,\n      \"ᵏ\": 1501,\n      \"ᵐ\": 1502,\n      \"ᵒ\": 1503,\n      \"ᵖ\": 1504,\n      \"ᵗ\": 1505,\n      \"ᵘ\": 1506,\n      \"ᵢ\": 1507,\n      \"ᵣ\": 1508,\n      \"ᵤ\": 1509,\n      \"ᵥ\": 1510,\n      \"ᶜ\": 1511,\n      \"ᶠ\": 1512,\n      \"‐\": 1513,\n      \"‑\": 1514,\n      \"‒\": 1515,\n      \"–\": 1516,\n      \"—\": 1517,\n      \"―\": 1518,\n      \"‖\": 1519,\n      \"‘\": 1520,\n      \"’\": 1521,\n      \"‚\": 1522,\n      \"“\": 1523,\n      \"”\": 1524,\n      \"„\": 1525,\n      \"†\": 1526,\n      \"‡\": 1527,\n      \"•\": 1528,\n      \"…\": 1529,\n      \"‰\": 1530,\n      \"′\": 1531,\n      \"″\": 1532,\n      \"›\": 1533,\n      \"‿\": 1534,\n      \"⁄\": 1535,\n      \"⁰\": 1536,\n      \"ⁱ\": 1537,\n      \"⁴\": 1538,\n      \"⁵\": 1539,\n      \"⁶\": 1540,\n      \"⁷\": 1541,\n      \"⁸\": 1542,\n      \"⁹\": 1543,\n      \"⁺\": 1544,\n      \"⁻\": 1545,\n      \"ⁿ\": 1546,\n      \"₀\": 1547,\n      \"₁\": 1548,\n      \"₂\": 1549,\n      \"₃\": 1550,\n      \"₄\": 1551,\n      \"₅\": 1552,\n      \"₆\": 1553,\n      \"₇\": 1554,\n      \"₈\": 1555,\n      \"₉\": 1556,\n      \"₊\": 1557,\n      \"₍\": 1558,\n      \"₎\": 1559,\n      \"ₐ\": 1560,\n      \"ₑ\": 1561,\n      \"ₒ\": 1562,\n      \"ₓ\": 1563,\n      \"ₕ\": 1564,\n      \"ₖ\": 1565,\n      \"ₗ\": 1566,\n      \"ₘ\": 1567,\n      \"ₙ\": 1568,\n      \"ₚ\": 1569,\n      \"ₛ\": 1570,\n      \"ₜ\": 1571,\n      \"₤\": 1572,\n      \"₩\": 1573,\n      \"€\": 1574,\n      \"₱\": 1575,\n      \"₹\": 1576,\n      \"ℓ\": 1577,\n      \"№\": 1578,\n      \"ℝ\": 1579,\n      \"™\": 1580,\n      \"⅓\": 1581,\n      \"⅔\": 1582,\n      \"←\": 1583,\n      \"↑\": 1584,\n      \"→\": 1585,\n      \"↓\": 1586,\n      \"↔\": 1587,\n      \"↦\": 1588,\n      \"⇄\": 1589,\n      \"⇌\": 1590,\n      \"⇒\": 1591,\n      \"∂\": 1592,\n      \"∅\": 1593,\n      \"∆\": 1594,\n      \"∇\": 1595,\n      \"∈\": 1596,\n      \"−\": 1597,\n      \"∗\": 1598,\n      \"∘\": 1599,\n      \"√\": 1600,\n      \"∞\": 1601,\n      \"∧\": 1602,\n      \"∨\": 1603,\n      \"∩\": 1604,\n      \"∪\": 1605,\n      \"≈\": 1606,\n      \"≡\": 1607,\n      \"≤\": 1608,\n      \"≥\": 1609,\n      \"⊂\": 1610,\n      \"⊆\": 1611,\n      \"⊕\": 1612,\n      \"⊗\": 1613,\n      \"⋅\": 1614,\n      \"─\": 1615,\n      \"│\": 1616,\n      \"■\": 1617,\n      \"▪\": 1618,\n      \"●\": 1619,\n      \"★\": 1620,\n      \"☆\": 1621,\n      \"☉\": 1622,\n      \"♠\": 1623,\n      \"♣\": 1624,\n      \"♥\": 1625,\n      \"♦\": 1626,\n      \"♭\": 1627,\n      \"♯\": 1628,\n      \"⟨\": 1629,\n      \"⟩\": 1630,\n      \"ⱼ\": 1631,\n      \"⺩\": 1632,\n      \"⺼\": 1633,\n      \"⽥\": 1634,\n      \"、\": 1635,\n      \"。\": 1636,\n      \"〈\": 1637,\n      \"〉\": 1638,\n      \"《\": 1639,\n      \"》\": 1640,\n      \"「\": 1641,\n      \"」\": 1642,\n      \"『\": 1643,\n      \"』\": 1644,\n      \"〜\": 1645,\n      \"あ\": 1646,\n      \"い\": 1647,\n      \"う\": 1648,\n      \"え\": 1649,\n      \"お\": 1650,\n      \"か\": 1651,\n      \"き\": 1652,\n      \"く\": 1653,\n      \"け\": 1654,\n      \"こ\": 1655,\n      \"さ\": 1656,\n      \"し\": 1657,\n      \"す\": 1658,\n      \"せ\": 1659,\n      \"そ\": 1660,\n      \"た\": 1661,\n      \"ち\": 1662,\n      \"っ\": 1663,\n      \"つ\": 1664,\n      \"て\": 1665,\n      \"と\": 1666,\n      \"な\": 1667,\n      \"に\": 1668,\n      \"ぬ\": 1669,\n      \"ね\": 1670,\n      \"の\": 1671,\n      \"は\": 1672,\n      \"ひ\": 1673,\n      \"ふ\": 1674,\n      \"へ\": 1675,\n      \"ほ\": 1676,\n      \"ま\": 1677,\n      \"み\": 1678,\n      \"む\": 1679,\n      \"め\": 1680,\n      \"も\": 1681,\n      \"や\": 1682,\n      \"ゆ\": 1683,\n      \"よ\": 1684,\n      \"ら\": 1685,\n      \"り\": 1686,\n      \"る\": 1687,\n      \"れ\": 1688,\n      \"ろ\": 1689,\n      \"を\": 1690,\n      \"ん\": 1691,\n      \"ァ\": 1692,\n      \"ア\": 1693,\n      \"ィ\": 1694,\n      \"イ\": 1695,\n      \"ウ\": 1696,\n      \"ェ\": 1697,\n      \"エ\": 1698,\n      \"オ\": 1699,\n      \"カ\": 1700,\n      \"キ\": 1701,\n      \"ク\": 1702,\n      \"ケ\": 1703,\n      \"コ\": 1704,\n      \"サ\": 1705,\n      \"シ\": 1706,\n      \"ス\": 1707,\n      \"セ\": 1708,\n      \"タ\": 1709,\n      \"チ\": 1710,\n      \"ッ\": 1711,\n      \"ツ\": 1712,\n      \"テ\": 1713,\n      \"ト\": 1714,\n      \"ナ\": 1715,\n      \"ニ\": 1716,\n      \"ノ\": 1717,\n      \"ハ\": 1718,\n      \"ヒ\": 1719,\n      \"フ\": 1720,\n      \"ヘ\": 1721,\n      \"ホ\": 1722,\n      \"マ\": 1723,\n      \"ミ\": 1724,\n      \"ム\": 1725,\n      \"メ\": 1726,\n      \"モ\": 1727,\n      \"ャ\": 1728,\n      \"ュ\": 1729,\n      \"ョ\": 1730,\n      \"ラ\": 1731,\n      \"リ\": 1732,\n      \"ル\": 1733,\n      \"レ\": 1734,\n      \"ロ\": 1735,\n      \"ワ\": 1736,\n      \"ン\": 1737,\n      \"・\": 1738,\n      \"ー\": 1739,\n      \"一\": 1740,\n      \"三\": 1741,\n      \"上\": 1742,\n      \"下\": 1743,\n      \"不\": 1744,\n      \"世\": 1745,\n      \"中\": 1746,\n      \"主\": 1747,\n      \"久\": 1748,\n      \"之\": 1749,\n      \"也\": 1750,\n      \"事\": 1751,\n      \"二\": 1752,\n      \"五\": 1753,\n      \"井\": 1754,\n      \"京\": 1755,\n      \"人\": 1756,\n      \"亻\": 1757,\n      \"仁\": 1758,\n      \"介\": 1759,\n      \"代\": 1760,\n      \"仮\": 1761,\n      \"伊\": 1762,\n      \"会\": 1763,\n      \"佐\": 1764,\n      \"侍\": 1765,\n      \"保\": 1766,\n      \"信\": 1767,\n      \"健\": 1768,\n      \"元\": 1769,\n      \"光\": 1770,\n      \"八\": 1771,\n      \"公\": 1772,\n      \"内\": 1773,\n      \"出\": 1774,\n      \"分\": 1775,\n      \"前\": 1776,\n      \"劉\": 1777,\n      \"力\": 1778,\n      \"加\": 1779,\n      \"勝\": 1780,\n      \"北\": 1781,\n      \"区\": 1782,\n      \"十\": 1783,\n      \"千\": 1784,\n      \"南\": 1785,\n      \"博\": 1786,\n      \"原\": 1787,\n      \"口\": 1788,\n      \"古\": 1789,\n      \"史\": 1790,\n      \"司\": 1791,\n      \"合\": 1792,\n      \"吉\": 1793,\n      \"同\": 1794,\n      \"名\": 1795,\n      \"和\": 1796,\n      \"囗\": 1797,\n      \"四\": 1798,\n      \"国\": 1799,\n      \"國\": 1800,\n      \"土\": 1801,\n      \"地\": 1802,\n      \"坂\": 1803,\n      \"城\": 1804,\n      \"堂\": 1805,\n      \"場\": 1806,\n      \"士\": 1807,\n      \"夏\": 1808,\n      \"外\": 1809,\n      \"大\": 1810,\n      \"天\": 1811,\n      \"太\": 1812,\n      \"夫\": 1813,\n      \"奈\": 1814,\n      \"女\": 1815,\n      \"子\": 1816,\n      \"学\": 1817,\n      \"宀\": 1818,\n      \"宇\": 1819,\n      \"安\": 1820,\n      \"宗\": 1821,\n      \"定\": 1822,\n      \"宣\": 1823,\n      \"宮\": 1824,\n      \"家\": 1825,\n      \"宿\": 1826,\n      \"寺\": 1827,\n      \"將\": 1828,\n      \"小\": 1829,\n      \"尚\": 1830,\n      \"山\": 1831,\n      \"岡\": 1832,\n      \"島\": 1833,\n      \"崎\": 1834,\n      \"川\": 1835,\n      \"州\": 1836,\n      \"巿\": 1837,\n      \"帝\": 1838,\n      \"平\": 1839,\n      \"年\": 1840,\n      \"幸\": 1841,\n      \"广\": 1842,\n      \"弘\": 1843,\n      \"張\": 1844,\n      \"彳\": 1845,\n      \"後\": 1846,\n      \"御\": 1847,\n      \"德\": 1848,\n      \"心\": 1849,\n      \"忄\": 1850,\n      \"志\": 1851,\n      \"忠\": 1852,\n      \"愛\": 1853,\n      \"成\": 1854,\n      \"我\": 1855,\n      \"戦\": 1856,\n      \"戸\": 1857,\n      \"手\": 1858,\n      \"扌\": 1859,\n      \"政\": 1860,\n      \"文\": 1861,\n      \"新\": 1862,\n      \"方\": 1863,\n      \"日\": 1864,\n      \"明\": 1865,\n      \"星\": 1866,\n      \"春\": 1867,\n      \"昭\": 1868,\n      \"智\": 1869,\n      \"曲\": 1870,\n      \"書\": 1871,\n      \"月\": 1872,\n      \"有\": 1873,\n      \"朝\": 1874,\n      \"木\": 1875,\n      \"本\": 1876,\n      \"李\": 1877,\n      \"村\": 1878,\n      \"東\": 1879,\n      \"松\": 1880,\n      \"林\": 1881,\n      \"森\": 1882,\n      \"楊\": 1883,\n      \"樹\": 1884,\n      \"橋\": 1885,\n      \"歌\": 1886,\n      \"止\": 1887,\n      \"正\": 1888,\n      \"武\": 1889,\n      \"比\": 1890,\n      \"氏\": 1891,\n      \"民\": 1892,\n      \"水\": 1893,\n      \"氵\": 1894,\n      \"氷\": 1895,\n      \"永\": 1896,\n      \"江\": 1897,\n      \"沢\": 1898,\n      \"河\": 1899,\n      \"治\": 1900,\n      \"法\": 1901,\n      \"海\": 1902,\n      \"清\": 1903,\n      \"漢\": 1904,\n      \"瀬\": 1905,\n      \"火\": 1906,\n      \"版\": 1907,\n      \"犬\": 1908,\n      \"王\": 1909,\n      \"生\": 1910,\n      \"田\": 1911,\n      \"男\": 1912,\n      \"疒\": 1913,\n      \"発\": 1914,\n      \"白\": 1915,\n      \"的\": 1916,\n      \"皇\": 1917,\n      \"目\": 1918,\n      \"相\": 1919,\n      \"省\": 1920,\n      \"真\": 1921,\n      \"石\": 1922,\n      \"示\": 1923,\n      \"社\": 1924,\n      \"神\": 1925,\n      \"福\": 1926,\n      \"禾\": 1927,\n      \"秀\": 1928,\n      \"秋\": 1929,\n      \"空\": 1930,\n      \"立\": 1931,\n      \"章\": 1932,\n      \"竹\": 1933,\n      \"糹\": 1934,\n      \"美\": 1935,\n      \"義\": 1936,\n      \"耳\": 1937,\n      \"良\": 1938,\n      \"艹\": 1939,\n      \"花\": 1940,\n      \"英\": 1941,\n      \"華\": 1942,\n      \"葉\": 1943,\n      \"藤\": 1944,\n      \"行\": 1945,\n      \"街\": 1946,\n      \"西\": 1947,\n      \"見\": 1948,\n      \"訁\": 1949,\n      \"語\": 1950,\n      \"谷\": 1951,\n      \"貝\": 1952,\n      \"貴\": 1953,\n      \"車\": 1954,\n      \"軍\": 1955,\n      \"辶\": 1956,\n      \"道\": 1957,\n      \"郎\": 1958,\n      \"郡\": 1959,\n      \"部\": 1960,\n      \"都\": 1961,\n      \"里\": 1962,\n      \"野\": 1963,\n      \"金\": 1964,\n      \"鈴\": 1965,\n      \"镇\": 1966,\n      \"長\": 1967,\n      \"門\": 1968,\n      \"間\": 1969,\n      \"阝\": 1970,\n      \"阿\": 1971,\n      \"陳\": 1972,\n      \"陽\": 1973,\n      \"雄\": 1974,\n      \"青\": 1975,\n      \"面\": 1976,\n      \"風\": 1977,\n      \"食\": 1978,\n      \"香\": 1979,\n      \"馬\": 1980,\n      \"高\": 1981,\n      \"龍\": 1982,\n      \"龸\": 1983,\n      \"ﬁ\": 1984,\n      \"ﬂ\": 1985,\n      \"！\": 1986,\n      \"（\": 1987,\n      \"）\": 1988,\n      \"，\": 1989,\n      \"－\": 1990,\n      \"．\": 1991,\n      \"／\": 1992,\n      \"：\": 1993,\n      \"？\": 1994,\n      \"～\": 1995,\n      \"the\": 1996,\n      \"of\": 1997,\n      \"and\": 1998,\n      \"in\": 1999,\n      \"to\": 2000,\n      \"was\": 2001,\n      \"he\": 2002,\n      \"is\": 2003,\n      \"as\": 2004,\n      \"for\": 2005,\n      \"on\": 2006,\n      \"with\": 2007,\n      \"that\": 2008,\n      \"it\": 2009,\n      \"his\": 2010,\n      \"by\": 2011,\n      \"at\": 2012,\n      \"from\": 2013,\n      \"her\": 2014,\n      \"##s\": 2015,\n      \"she\": 2016,\n      \"you\": 2017,\n      \"had\": 2018,\n      \"an\": 2019,\n      \"were\": 2020,\n      \"but\": 2021,\n      \"be\": 2022,\n      \"this\": 2023,\n      \"are\": 2024,\n      \"not\": 2025,\n      \"my\": 2026,\n      \"they\": 2027,\n      \"one\": 2028,\n      \"which\": 2029,\n      \"or\": 2030,\n      \"have\": 2031,\n      \"him\": 2032,\n      \"me\": 2033,\n      \"first\": 2034,\n      \"all\": 2035,\n      \"also\": 2036,\n      \"their\": 2037,\n      \"has\": 2038,\n      \"up\": 2039,\n      \"who\": 2040,\n      \"out\": 2041,\n      \"been\": 2042,\n      \"when\": 2043,\n      \"after\": 2044,\n      \"there\": 2045,\n      \"into\": 2046,\n      \"new\": 2047,\n      \"two\": 2048,\n      \"its\": 2049,\n      \"##a\": 2050,\n      \"time\": 2051,\n      \"would\": 2052,\n      \"no\": 2053,\n      \"what\": 2054,\n      \"about\": 2055,\n      \"said\": 2056,\n      \"we\": 2057,\n      \"over\": 2058,\n      \"then\": 2059,\n      \"other\": 2060,\n      \"so\": 2061,\n      \"more\": 2062,\n      \"##e\": 2063,\n      \"can\": 2064,\n      \"if\": 2065,\n      \"like\": 2066,\n      \"back\": 2067,\n      \"them\": 2068,\n      \"only\": 2069,\n      \"some\": 2070,\n      \"could\": 2071,\n      \"##i\": 2072,\n      \"where\": 2073,\n      \"just\": 2074,\n      \"##ing\": 2075,\n      \"during\": 2076,\n      \"before\": 2077,\n      \"##n\": 2078,\n      \"do\": 2079,\n      \"##o\": 2080,\n      \"made\": 2081,\n      \"school\": 2082,\n      \"through\": 2083,\n      \"than\": 2084,\n      \"now\": 2085,\n      \"years\": 2086,\n      \"most\": 2087,\n      \"world\": 2088,\n      \"may\": 2089,\n      \"between\": 2090,\n      \"down\": 2091,\n      \"well\": 2092,\n      \"three\": 2093,\n      \"##d\": 2094,\n      \"year\": 2095,\n      \"while\": 2096,\n      \"will\": 2097,\n      \"##ed\": 2098,\n      \"##r\": 2099,\n      \"##y\": 2100,\n      \"later\": 2101,\n      \"##t\": 2102,\n      \"city\": 2103,\n      \"under\": 2104,\n      \"around\": 2105,\n      \"did\": 2106,\n      \"such\": 2107,\n      \"being\": 2108,\n      \"used\": 2109,\n      \"state\": 2110,\n      \"people\": 2111,\n      \"part\": 2112,\n      \"know\": 2113,\n      \"against\": 2114,\n      \"your\": 2115,\n      \"many\": 2116,\n      \"second\": 2117,\n      \"university\": 2118,\n      \"both\": 2119,\n      \"national\": 2120,\n      \"##er\": 2121,\n      \"these\": 2122,\n      \"don\": 2123,\n      \"known\": 2124,\n      \"off\": 2125,\n      \"way\": 2126,\n      \"until\": 2127,\n      \"re\": 2128,\n      \"how\": 2129,\n      \"even\": 2130,\n      \"get\": 2131,\n      \"head\": 2132,\n      \"...\": 2133,\n      \"didn\": 2134,\n      \"##ly\": 2135,\n      \"team\": 2136,\n      \"american\": 2137,\n      \"because\": 2138,\n      \"de\": 2139,\n      \"##l\": 2140,\n      \"born\": 2141,\n      \"united\": 2142,\n      \"film\": 2143,\n      \"since\": 2144,\n      \"still\": 2145,\n      \"long\": 2146,\n      \"work\": 2147,\n      \"south\": 2148,\n      \"us\": 2149,\n      \"became\": 2150,\n      \"any\": 2151,\n      \"high\": 2152,\n      \"again\": 2153,\n      \"day\": 2154,\n      \"family\": 2155,\n      \"see\": 2156,\n      \"right\": 2157,\n      \"man\": 2158,\n      \"eyes\": 2159,\n      \"house\": 2160,\n      \"season\": 2161,\n      \"war\": 2162,\n      \"states\": 2163,\n      \"including\": 2164,\n      \"took\": 2165,\n      \"life\": 2166,\n      \"north\": 2167,\n      \"same\": 2168,\n      \"each\": 2169,\n      \"called\": 2170,\n      \"name\": 2171,\n      \"much\": 2172,\n      \"place\": 2173,\n      \"however\": 2174,\n      \"go\": 2175,\n      \"four\": 2176,\n      \"group\": 2177,\n      \"another\": 2178,\n      \"found\": 2179,\n      \"won\": 2180,\n      \"area\": 2181,\n      \"here\": 2182,\n      \"going\": 2183,\n      \"10\": 2184,\n      \"away\": 2185,\n      \"series\": 2186,\n      \"left\": 2187,\n      \"home\": 2188,\n      \"music\": 2189,\n      \"best\": 2190,\n      \"make\": 2191,\n      \"hand\": 2192,\n      \"number\": 2193,\n      \"company\": 2194,\n      \"several\": 2195,\n      \"never\": 2196,\n      \"last\": 2197,\n      \"john\": 2198,\n      \"000\": 2199,\n      \"very\": 2200,\n      \"album\": 2201,\n      \"take\": 2202,\n      \"end\": 2203,\n      \"good\": 2204,\n      \"too\": 2205,\n      \"following\": 2206,\n      \"released\": 2207,\n      \"game\": 2208,\n      \"played\": 2209,\n      \"little\": 2210,\n      \"began\": 2211,\n      \"district\": 2212,\n      \"##m\": 2213,\n      \"old\": 2214,\n      \"want\": 2215,\n      \"those\": 2216,\n      \"side\": 2217,\n      \"held\": 2218,\n      \"own\": 2219,\n      \"early\": 2220,\n      \"county\": 2221,\n      \"ll\": 2222,\n      \"league\": 2223,\n      \"use\": 2224,\n      \"west\": 2225,\n      \"##u\": 2226,\n      \"face\": 2227,\n      \"think\": 2228,\n      \"##es\": 2229,\n      \"2010\": 2230,\n      \"government\": 2231,\n      \"##h\": 2232,\n      \"march\": 2233,\n      \"came\": 2234,\n      \"small\": 2235,\n      \"general\": 2236,\n      \"town\": 2237,\n      \"june\": 2238,\n      \"##on\": 2239,\n      \"line\": 2240,\n      \"based\": 2241,\n      \"something\": 2242,\n      \"##k\": 2243,\n      \"september\": 2244,\n      \"thought\": 2245,\n      \"looked\": 2246,\n      \"along\": 2247,\n      \"international\": 2248,\n      \"2011\": 2249,\n      \"air\": 2250,\n      \"july\": 2251,\n      \"club\": 2252,\n      \"went\": 2253,\n      \"january\": 2254,\n      \"october\": 2255,\n      \"our\": 2256,\n      \"august\": 2257,\n      \"april\": 2258,\n      \"york\": 2259,\n      \"12\": 2260,\n      \"few\": 2261,\n      \"2012\": 2262,\n      \"2008\": 2263,\n      \"east\": 2264,\n      \"show\": 2265,\n      \"member\": 2266,\n      \"college\": 2267,\n      \"2009\": 2268,\n      \"father\": 2269,\n      \"public\": 2270,\n      \"##us\": 2271,\n      \"come\": 2272,\n      \"men\": 2273,\n      \"five\": 2274,\n      \"set\": 2275,\n      \"station\": 2276,\n      \"church\": 2277,\n      \"##c\": 2278,\n      \"next\": 2279,\n      \"former\": 2280,\n      \"november\": 2281,\n      \"room\": 2282,\n      \"party\": 2283,\n      \"located\": 2284,\n      \"december\": 2285,\n      \"2013\": 2286,\n      \"age\": 2287,\n      \"got\": 2288,\n      \"2007\": 2289,\n      \"##g\": 2290,\n      \"system\": 2291,\n      \"let\": 2292,\n      \"love\": 2293,\n      \"2006\": 2294,\n      \"though\": 2295,\n      \"every\": 2296,\n      \"2014\": 2297,\n      \"look\": 2298,\n      \"song\": 2299,\n      \"water\": 2300,\n      \"century\": 2301,\n      \"without\": 2302,\n      \"body\": 2303,\n      \"black\": 2304,\n      \"night\": 2305,\n      \"within\": 2306,\n      \"great\": 2307,\n      \"women\": 2308,\n      \"single\": 2309,\n      \"ve\": 2310,\n      \"building\": 2311,\n      \"large\": 2312,\n      \"population\": 2313,\n      \"river\": 2314,\n      \"named\": 2315,\n      \"band\": 2316,\n      \"white\": 2317,\n      \"started\": 2318,\n      \"##an\": 2319,\n      \"once\": 2320,\n      \"15\": 2321,\n      \"20\": 2322,\n      \"should\": 2323,\n      \"18\": 2324,\n      \"2015\": 2325,\n      \"service\": 2326,\n      \"top\": 2327,\n      \"built\": 2328,\n      \"british\": 2329,\n      \"open\": 2330,\n      \"death\": 2331,\n      \"king\": 2332,\n      \"moved\": 2333,\n      \"local\": 2334,\n      \"times\": 2335,\n      \"children\": 2336,\n      \"february\": 2337,\n      \"book\": 2338,\n      \"why\": 2339,\n      \"11\": 2340,\n      \"door\": 2341,\n      \"need\": 2342,\n      \"president\": 2343,\n      \"order\": 2344,\n      \"final\": 2345,\n      \"road\": 2346,\n      \"wasn\": 2347,\n      \"although\": 2348,\n      \"due\": 2349,\n      \"major\": 2350,\n      \"died\": 2351,\n      \"village\": 2352,\n      \"third\": 2353,\n      \"knew\": 2354,\n      \"2016\": 2355,\n      \"asked\": 2356,\n      \"turned\": 2357,\n      \"st\": 2358,\n      \"wanted\": 2359,\n      \"say\": 2360,\n      \"##p\": 2361,\n      \"together\": 2362,\n      \"received\": 2363,\n      \"main\": 2364,\n      \"son\": 2365,\n      \"served\": 2366,\n      \"different\": 2367,\n      \"##en\": 2368,\n      \"behind\": 2369,\n      \"himself\": 2370,\n      \"felt\": 2371,\n      \"members\": 2372,\n      \"power\": 2373,\n      \"football\": 2374,\n      \"law\": 2375,\n      \"voice\": 2376,\n      \"play\": 2377,\n      \"##in\": 2378,\n      \"near\": 2379,\n      \"park\": 2380,\n      \"history\": 2381,\n      \"30\": 2382,\n      \"having\": 2383,\n      \"2005\": 2384,\n      \"16\": 2385,\n      \"##man\": 2386,\n      \"saw\": 2387,\n      \"mother\": 2388,\n      \"##al\": 2389,\n      \"army\": 2390,\n      \"point\": 2391,\n      \"front\": 2392,\n      \"help\": 2393,\n      \"english\": 2394,\n      \"street\": 2395,\n      \"art\": 2396,\n      \"late\": 2397,\n      \"hands\": 2398,\n      \"games\": 2399,\n      \"award\": 2400,\n      \"##ia\": 2401,\n      \"young\": 2402,\n      \"14\": 2403,\n      \"put\": 2404,\n      \"published\": 2405,\n      \"country\": 2406,\n      \"division\": 2407,\n      \"across\": 2408,\n      \"told\": 2409,\n      \"13\": 2410,\n      \"often\": 2411,\n      \"ever\": 2412,\n      \"french\": 2413,\n      \"london\": 2414,\n      \"center\": 2415,\n      \"six\": 2416,\n      \"red\": 2417,\n      \"2017\": 2418,\n      \"led\": 2419,\n      \"days\": 2420,\n      \"include\": 2421,\n      \"light\": 2422,\n      \"25\": 2423,\n      \"find\": 2424,\n      \"tell\": 2425,\n      \"among\": 2426,\n      \"species\": 2427,\n      \"really\": 2428,\n      \"according\": 2429,\n      \"central\": 2430,\n      \"half\": 2431,\n      \"2004\": 2432,\n      \"form\": 2433,\n      \"original\": 2434,\n      \"gave\": 2435,\n      \"office\": 2436,\n      \"making\": 2437,\n      \"enough\": 2438,\n      \"lost\": 2439,\n      \"full\": 2440,\n      \"opened\": 2441,\n      \"must\": 2442,\n      \"included\": 2443,\n      \"live\": 2444,\n      \"given\": 2445,\n      \"german\": 2446,\n      \"player\": 2447,\n      \"run\": 2448,\n      \"business\": 2449,\n      \"woman\": 2450,\n      \"community\": 2451,\n      \"cup\": 2452,\n      \"might\": 2453,\n      \"million\": 2454,\n      \"land\": 2455,\n      \"2000\": 2456,\n      \"court\": 2457,\n      \"development\": 2458,\n      \"17\": 2459,\n      \"short\": 2460,\n      \"round\": 2461,\n      \"ii\": 2462,\n      \"km\": 2463,\n      \"seen\": 2464,\n      \"class\": 2465,\n      \"story\": 2466,\n      \"always\": 2467,\n      \"become\": 2468,\n      \"sure\": 2469,\n      \"research\": 2470,\n      \"almost\": 2471,\n      \"director\": 2472,\n      \"council\": 2473,\n      \"la\": 2474,\n      \"##2\": 2475,\n      \"career\": 2476,\n      \"things\": 2477,\n      \"using\": 2478,\n      \"island\": 2479,\n      \"##z\": 2480,\n      \"couldn\": 2481,\n      \"car\": 2482,\n      \"##is\": 2483,\n      \"24\": 2484,\n      \"close\": 2485,\n      \"force\": 2486,\n      \"##1\": 2487,\n      \"better\": 2488,\n      \"free\": 2489,\n      \"support\": 2490,\n      \"control\": 2491,\n      \"field\": 2492,\n      \"students\": 2493,\n      \"2003\": 2494,\n      \"education\": 2495,\n      \"married\": 2496,\n      \"##b\": 2497,\n      \"nothing\": 2498,\n      \"worked\": 2499,\n      \"others\": 2500,\n      \"record\": 2501,\n      \"big\": 2502,\n      \"inside\": 2503,\n      \"level\": 2504,\n      \"anything\": 2505,\n      \"continued\": 2506,\n      \"give\": 2507,\n      \"james\": 2508,\n      \"##3\": 2509,\n      \"military\": 2510,\n      \"established\": 2511,\n      \"non\": 2512,\n      \"returned\": 2513,\n      \"feel\": 2514,\n      \"does\": 2515,\n      \"title\": 2516,\n      \"written\": 2517,\n      \"thing\": 2518,\n      \"feet\": 2519,\n      \"william\": 2520,\n      \"far\": 2521,\n      \"co\": 2522,\n      \"association\": 2523,\n      \"hard\": 2524,\n      \"already\": 2525,\n      \"2002\": 2526,\n      \"##ra\": 2527,\n      \"championship\": 2528,\n      \"human\": 2529,\n      \"western\": 2530,\n      \"100\": 2531,\n      \"##na\": 2532,\n      \"department\": 2533,\n      \"hall\": 2534,\n      \"role\": 2535,\n      \"various\": 2536,\n      \"production\": 2537,\n      \"21\": 2538,\n      \"19\": 2539,\n      \"heart\": 2540,\n      \"2001\": 2541,\n      \"living\": 2542,\n      \"fire\": 2543,\n      \"version\": 2544,\n      \"##ers\": 2545,\n      \"##f\": 2546,\n      \"television\": 2547,\n      \"royal\": 2548,\n      \"##4\": 2549,\n      \"produced\": 2550,\n      \"working\": 2551,\n      \"act\": 2552,\n      \"case\": 2553,\n      \"society\": 2554,\n      \"region\": 2555,\n      \"present\": 2556,\n      \"radio\": 2557,\n      \"period\": 2558,\n      \"looking\": 2559,\n      \"least\": 2560,\n      \"total\": 2561,\n      \"keep\": 2562,\n      \"england\": 2563,\n      \"wife\": 2564,\n      \"program\": 2565,\n      \"per\": 2566,\n      \"brother\": 2567,\n      \"mind\": 2568,\n      \"special\": 2569,\n      \"22\": 2570,\n      \"##le\": 2571,\n      \"am\": 2572,\n      \"works\": 2573,\n      \"soon\": 2574,\n      \"##6\": 2575,\n      \"political\": 2576,\n      \"george\": 2577,\n      \"services\": 2578,\n      \"taken\": 2579,\n      \"created\": 2580,\n      \"##7\": 2581,\n      \"further\": 2582,\n      \"able\": 2583,\n      \"reached\": 2584,\n      \"david\": 2585,\n      \"union\": 2586,\n      \"joined\": 2587,\n      \"upon\": 2588,\n      \"done\": 2589,\n      \"important\": 2590,\n      \"social\": 2591,\n      \"information\": 2592,\n      \"either\": 2593,\n      \"##ic\": 2594,\n      \"##x\": 2595,\n      \"appeared\": 2596,\n      \"position\": 2597,\n      \"ground\": 2598,\n      \"lead\": 2599,\n      \"rock\": 2600,\n      \"dark\": 2601,\n      \"election\": 2602,\n      \"23\": 2603,\n      \"board\": 2604,\n      \"france\": 2605,\n      \"hair\": 2606,\n      \"course\": 2607,\n      \"arms\": 2608,\n      \"site\": 2609,\n      \"police\": 2610,\n      \"girl\": 2611,\n      \"instead\": 2612,\n      \"real\": 2613,\n      \"sound\": 2614,\n      \"##v\": 2615,\n      \"words\": 2616,\n      \"moment\": 2617,\n      \"##te\": 2618,\n      \"someone\": 2619,\n      \"##8\": 2620,\n      \"summer\": 2621,\n      \"project\": 2622,\n      \"announced\": 2623,\n      \"san\": 2624,\n      \"less\": 2625,\n      \"wrote\": 2626,\n      \"past\": 2627,\n      \"followed\": 2628,\n      \"##5\": 2629,\n      \"blue\": 2630,\n      \"founded\": 2631,\n      \"al\": 2632,\n      \"finally\": 2633,\n      \"india\": 2634,\n      \"taking\": 2635,\n      \"records\": 2636,\n      \"america\": 2637,\n      \"##ne\": 2638,\n      \"1999\": 2639,\n      \"design\": 2640,\n      \"considered\": 2641,\n      \"northern\": 2642,\n      \"god\": 2643,\n      \"stop\": 2644,\n      \"battle\": 2645,\n      \"toward\": 2646,\n      \"european\": 2647,\n      \"outside\": 2648,\n      \"described\": 2649,\n      \"track\": 2650,\n      \"today\": 2651,\n      \"playing\": 2652,\n      \"language\": 2653,\n      \"28\": 2654,\n      \"call\": 2655,\n      \"26\": 2656,\n      \"heard\": 2657,\n      \"professional\": 2658,\n      \"low\": 2659,\n      \"australia\": 2660,\n      \"miles\": 2661,\n      \"california\": 2662,\n      \"win\": 2663,\n      \"yet\": 2664,\n      \"green\": 2665,\n      \"##ie\": 2666,\n      \"trying\": 2667,\n      \"blood\": 2668,\n      \"##ton\": 2669,\n      \"southern\": 2670,\n      \"science\": 2671,\n      \"maybe\": 2672,\n      \"everything\": 2673,\n      \"match\": 2674,\n      \"square\": 2675,\n      \"27\": 2676,\n      \"mouth\": 2677,\n      \"video\": 2678,\n      \"race\": 2679,\n      \"recorded\": 2680,\n      \"leave\": 2681,\n      \"above\": 2682,\n      \"##9\": 2683,\n      \"daughter\": 2684,\n      \"points\": 2685,\n      \"space\": 2686,\n      \"1998\": 2687,\n      \"museum\": 2688,\n      \"change\": 2689,\n      \"middle\": 2690,\n      \"common\": 2691,\n      \"##0\": 2692,\n      \"move\": 2693,\n      \"tv\": 2694,\n      \"post\": 2695,\n      \"##ta\": 2696,\n      \"lake\": 2697,\n      \"seven\": 2698,\n      \"tried\": 2699,\n      \"elected\": 2700,\n      \"closed\": 2701,\n      \"ten\": 2702,\n      \"paul\": 2703,\n      \"minister\": 2704,\n      \"##th\": 2705,\n      \"months\": 2706,\n      \"start\": 2707,\n      \"chief\": 2708,\n      \"return\": 2709,\n      \"canada\": 2710,\n      \"person\": 2711,\n      \"sea\": 2712,\n      \"release\": 2713,\n      \"similar\": 2714,\n      \"modern\": 2715,\n      \"brought\": 2716,\n      \"rest\": 2717,\n      \"hit\": 2718,\n      \"formed\": 2719,\n      \"mr\": 2720,\n      \"##la\": 2721,\n      \"1997\": 2722,\n      \"floor\": 2723,\n      \"event\": 2724,\n      \"doing\": 2725,\n      \"thomas\": 2726,\n      \"1996\": 2727,\n      \"robert\": 2728,\n      \"care\": 2729,\n      \"killed\": 2730,\n      \"training\": 2731,\n      \"star\": 2732,\n      \"week\": 2733,\n      \"needed\": 2734,\n      \"turn\": 2735,\n      \"finished\": 2736,\n      \"railway\": 2737,\n      \"rather\": 2738,\n      \"news\": 2739,\n      \"health\": 2740,\n      \"sent\": 2741,\n      \"example\": 2742,\n      \"ran\": 2743,\n      \"term\": 2744,\n      \"michael\": 2745,\n      \"coming\": 2746,\n      \"currently\": 2747,\n      \"yes\": 2748,\n      \"forces\": 2749,\n      \"despite\": 2750,\n      \"gold\": 2751,\n      \"areas\": 2752,\n      \"50\": 2753,\n      \"stage\": 2754,\n      \"fact\": 2755,\n      \"29\": 2756,\n      \"dead\": 2757,\n      \"says\": 2758,\n      \"popular\": 2759,\n      \"2018\": 2760,\n      \"originally\": 2761,\n      \"germany\": 2762,\n      \"probably\": 2763,\n      \"developed\": 2764,\n      \"result\": 2765,\n      \"pulled\": 2766,\n      \"friend\": 2767,\n      \"stood\": 2768,\n      \"money\": 2769,\n      \"running\": 2770,\n      \"mi\": 2771,\n      \"signed\": 2772,\n      \"word\": 2773,\n      \"songs\": 2774,\n      \"child\": 2775,\n      \"eventually\": 2776,\n      \"met\": 2777,\n      \"tour\": 2778,\n      \"average\": 2779,\n      \"teams\": 2780,\n      \"minutes\": 2781,\n      \"festival\": 2782,\n      \"current\": 2783,\n      \"deep\": 2784,\n      \"kind\": 2785,\n      \"1995\": 2786,\n      \"decided\": 2787,\n      \"usually\": 2788,\n      \"eastern\": 2789,\n      \"seemed\": 2790,\n      \"##ness\": 2791,\n      \"episode\": 2792,\n      \"bed\": 2793,\n      \"added\": 2794,\n      \"table\": 2795,\n      \"indian\": 2796,\n      \"private\": 2797,\n      \"charles\": 2798,\n      \"route\": 2799,\n      \"available\": 2800,\n      \"idea\": 2801,\n      \"throughout\": 2802,\n      \"centre\": 2803,\n      \"addition\": 2804,\n      \"appointed\": 2805,\n      \"style\": 2806,\n      \"1994\": 2807,\n      \"books\": 2808,\n      \"eight\": 2809,\n      \"construction\": 2810,\n      \"press\": 2811,\n      \"mean\": 2812,\n      \"wall\": 2813,\n      \"friends\": 2814,\n      \"remained\": 2815,\n      \"schools\": 2816,\n      \"study\": 2817,\n      \"##ch\": 2818,\n      \"##um\": 2819,\n      \"institute\": 2820,\n      \"oh\": 2821,\n      \"chinese\": 2822,\n      \"sometimes\": 2823,\n      \"events\": 2824,\n      \"possible\": 2825,\n      \"1992\": 2826,\n      \"australian\": 2827,\n      \"type\": 2828,\n      \"brown\": 2829,\n      \"forward\": 2830,\n      \"talk\": 2831,\n      \"process\": 2832,\n      \"food\": 2833,\n      \"debut\": 2834,\n      \"seat\": 2835,\n      \"performance\": 2836,\n      \"committee\": 2837,\n      \"features\": 2838,\n      \"character\": 2839,\n      \"arts\": 2840,\n      \"herself\": 2841,\n      \"else\": 2842,\n      \"lot\": 2843,\n      \"strong\": 2844,\n      \"russian\": 2845,\n      \"range\": 2846,\n      \"hours\": 2847,\n      \"peter\": 2848,\n      \"arm\": 2849,\n      \"##da\": 2850,\n      \"morning\": 2851,\n      \"dr\": 2852,\n      \"sold\": 2853,\n      \"##ry\": 2854,\n      \"quickly\": 2855,\n      \"directed\": 2856,\n      \"1993\": 2857,\n      \"guitar\": 2858,\n      \"china\": 2859,\n      \"##w\": 2860,\n      \"31\": 2861,\n      \"list\": 2862,\n      \"##ma\": 2863,\n      \"performed\": 2864,\n      \"media\": 2865,\n      \"uk\": 2866,\n      \"players\": 2867,\n      \"smile\": 2868,\n      \"##rs\": 2869,\n      \"myself\": 2870,\n      \"40\": 2871,\n      \"placed\": 2872,\n      \"coach\": 2873,\n      \"province\": 2874,\n      \"towards\": 2875,\n      \"wouldn\": 2876,\n      \"leading\": 2877,\n      \"whole\": 2878,\n      \"boy\": 2879,\n      \"official\": 2880,\n      \"designed\": 2881,\n      \"grand\": 2882,\n      \"census\": 2883,\n      \"##el\": 2884,\n      \"europe\": 2885,\n      \"attack\": 2886,\n      \"japanese\": 2887,\n      \"henry\": 2888,\n      \"1991\": 2889,\n      \"##re\": 2890,\n      \"##os\": 2891,\n      \"cross\": 2892,\n      \"getting\": 2893,\n      \"alone\": 2894,\n      \"action\": 2895,\n      \"lower\": 2896,\n      \"network\": 2897,\n      \"wide\": 2898,\n      \"washington\": 2899,\n      \"japan\": 2900,\n      \"1990\": 2901,\n      \"hospital\": 2902,\n      \"believe\": 2903,\n      \"changed\": 2904,\n      \"sister\": 2905,\n      \"##ar\": 2906,\n      \"hold\": 2907,\n      \"gone\": 2908,\n      \"sir\": 2909,\n      \"hadn\": 2910,\n      \"ship\": 2911,\n      \"##ka\": 2912,\n      \"studies\": 2913,\n      \"academy\": 2914,\n      \"shot\": 2915,\n      \"rights\": 2916,\n      \"below\": 2917,\n      \"base\": 2918,\n      \"bad\": 2919,\n      \"involved\": 2920,\n      \"kept\": 2921,\n      \"largest\": 2922,\n      \"##ist\": 2923,\n      \"bank\": 2924,\n      \"future\": 2925,\n      \"especially\": 2926,\n      \"beginning\": 2927,\n      \"mark\": 2928,\n      \"movement\": 2929,\n      \"section\": 2930,\n      \"female\": 2931,\n      \"magazine\": 2932,\n      \"plan\": 2933,\n      \"professor\": 2934,\n      \"lord\": 2935,\n      \"longer\": 2936,\n      \"##ian\": 2937,\n      \"sat\": 2938,\n      \"walked\": 2939,\n      \"hill\": 2940,\n      \"actually\": 2941,\n      \"civil\": 2942,\n      \"energy\": 2943,\n      \"model\": 2944,\n      \"families\": 2945,\n      \"size\": 2946,\n      \"thus\": 2947,\n      \"aircraft\": 2948,\n      \"completed\": 2949,\n      \"includes\": 2950,\n      \"data\": 2951,\n      \"captain\": 2952,\n      \"##or\": 2953,\n      \"fight\": 2954,\n      \"vocals\": 2955,\n      \"featured\": 2956,\n      \"richard\": 2957,\n      \"bridge\": 2958,\n      \"fourth\": 2959,\n      \"1989\": 2960,\n      \"officer\": 2961,\n      \"stone\": 2962,\n      \"hear\": 2963,\n      \"##ism\": 2964,\n      \"means\": 2965,\n      \"medical\": 2966,\n      \"groups\": 2967,\n      \"management\": 2968,\n      \"self\": 2969,\n      \"lips\": 2970,\n      \"competition\": 2971,\n      \"entire\": 2972,\n      \"lived\": 2973,\n      \"technology\": 2974,\n      \"leaving\": 2975,\n      \"federal\": 2976,\n      \"tournament\": 2977,\n      \"bit\": 2978,\n      \"passed\": 2979,\n      \"hot\": 2980,\n      \"independent\": 2981,\n      \"awards\": 2982,\n      \"kingdom\": 2983,\n      \"mary\": 2984,\n      \"spent\": 2985,\n      \"fine\": 2986,\n      \"doesn\": 2987,\n      \"reported\": 2988,\n      \"##ling\": 2989,\n      \"jack\": 2990,\n      \"fall\": 2991,\n      \"raised\": 2992,\n      \"itself\": 2993,\n      \"stay\": 2994,\n      \"true\": 2995,\n      \"studio\": 2996,\n      \"1988\": 2997,\n      \"sports\": 2998,\n      \"replaced\": 2999,\n      \"paris\": 3000,\n      \"systems\": 3001,\n      \"saint\": 3002,\n      \"leader\": 3003,\n      \"theatre\": 3004,\n      \"whose\": 3005,\n      \"market\": 3006,\n      \"capital\": 3007,\n      \"parents\": 3008,\n      \"spanish\": 3009,\n      \"canadian\": 3010,\n      \"earth\": 3011,\n      \"##ity\": 3012,\n      \"cut\": 3013,\n      \"degree\": 3014,\n      \"writing\": 3015,\n      \"bay\": 3016,\n      \"christian\": 3017,\n      \"awarded\": 3018,\n      \"natural\": 3019,\n      \"higher\": 3020,\n      \"bill\": 3021,\n      \"##as\": 3022,\n      \"coast\": 3023,\n      \"provided\": 3024,\n      \"previous\": 3025,\n      \"senior\": 3026,\n      \"ft\": 3027,\n      \"valley\": 3028,\n      \"organization\": 3029,\n      \"stopped\": 3030,\n      \"onto\": 3031,\n      \"countries\": 3032,\n      \"parts\": 3033,\n      \"conference\": 3034,\n      \"queen\": 3035,\n      \"security\": 3036,\n      \"interest\": 3037,\n      \"saying\": 3038,\n      \"allowed\": 3039,\n      \"master\": 3040,\n      \"earlier\": 3041,\n      \"phone\": 3042,\n      \"matter\": 3043,\n      \"smith\": 3044,\n      \"winning\": 3045,\n      \"try\": 3046,\n      \"happened\": 3047,\n      \"moving\": 3048,\n      \"campaign\": 3049,\n      \"los\": 3050,\n      \"##ley\": 3051,\n      \"breath\": 3052,\n      \"nearly\": 3053,\n      \"mid\": 3054,\n      \"1987\": 3055,\n      \"certain\": 3056,\n      \"girls\": 3057,\n      \"date\": 3058,\n      \"italian\": 3059,\n      \"african\": 3060,\n      \"standing\": 3061,\n      \"fell\": 3062,\n      \"artist\": 3063,\n      \"##ted\": 3064,\n      \"shows\": 3065,\n      \"deal\": 3066,\n      \"mine\": 3067,\n      \"industry\": 3068,\n      \"1986\": 3069,\n      \"##ng\": 3070,\n      \"everyone\": 3071,\n      \"republic\": 3072,\n      \"provide\": 3073,\n      \"collection\": 3074,\n      \"library\": 3075,\n      \"student\": 3076,\n      \"##ville\": 3077,\n      \"primary\": 3078,\n      \"owned\": 3079,\n      \"older\": 3080,\n      \"via\": 3081,\n      \"heavy\": 3082,\n      \"1st\": 3083,\n      \"makes\": 3084,\n      \"##able\": 3085,\n      \"attention\": 3086,\n      \"anyone\": 3087,\n      \"africa\": 3088,\n      \"##ri\": 3089,\n      \"stated\": 3090,\n      \"length\": 3091,\n      \"ended\": 3092,\n      \"fingers\": 3093,\n      \"command\": 3094,\n      \"staff\": 3095,\n      \"skin\": 3096,\n      \"foreign\": 3097,\n      \"opening\": 3098,\n      \"governor\": 3099,\n      \"okay\": 3100,\n      \"medal\": 3101,\n      \"kill\": 3102,\n      \"sun\": 3103,\n      \"cover\": 3104,\n      \"job\": 3105,\n      \"1985\": 3106,\n      \"introduced\": 3107,\n      \"chest\": 3108,\n      \"hell\": 3109,\n      \"feeling\": 3110,\n      \"##ies\": 3111,\n      \"success\": 3112,\n      \"meet\": 3113,\n      \"reason\": 3114,\n      \"standard\": 3115,\n      \"meeting\": 3116,\n      \"novel\": 3117,\n      \"1984\": 3118,\n      \"trade\": 3119,\n      \"source\": 3120,\n      \"buildings\": 3121,\n      \"##land\": 3122,\n      \"rose\": 3123,\n      \"guy\": 3124,\n      \"goal\": 3125,\n      \"##ur\": 3126,\n      \"chapter\": 3127,\n      \"native\": 3128,\n      \"husband\": 3129,\n      \"previously\": 3130,\n      \"unit\": 3131,\n      \"limited\": 3132,\n      \"entered\": 3133,\n      \"weeks\": 3134,\n      \"producer\": 3135,\n      \"operations\": 3136,\n      \"mountain\": 3137,\n      \"takes\": 3138,\n      \"covered\": 3139,\n      \"forced\": 3140,\n      \"related\": 3141,\n      \"roman\": 3142,\n      \"complete\": 3143,\n      \"successful\": 3144,\n      \"key\": 3145,\n      \"texas\": 3146,\n      \"cold\": 3147,\n      \"##ya\": 3148,\n      \"channel\": 3149,\n      \"1980\": 3150,\n      \"traditional\": 3151,\n      \"films\": 3152,\n      \"dance\": 3153,\n      \"clear\": 3154,\n      \"approximately\": 3155,\n      \"500\": 3156,\n      \"nine\": 3157,\n      \"van\": 3158,\n      \"prince\": 3159,\n      \"question\": 3160,\n      \"active\": 3161,\n      \"tracks\": 3162,\n      \"ireland\": 3163,\n      \"regional\": 3164,\n      \"silver\": 3165,\n      \"author\": 3166,\n      \"personal\": 3167,\n      \"sense\": 3168,\n      \"operation\": 3169,\n      \"##ine\": 3170,\n      \"economic\": 3171,\n      \"1983\": 3172,\n      \"holding\": 3173,\n      \"twenty\": 3174,\n      \"isbn\": 3175,\n      \"additional\": 3176,\n      \"speed\": 3177,\n      \"hour\": 3178,\n      \"edition\": 3179,\n      \"regular\": 3180,\n      \"historic\": 3181,\n      \"places\": 3182,\n      \"whom\": 3183,\n      \"shook\": 3184,\n      \"movie\": 3185,\n      \"km²\": 3186,\n      \"secretary\": 3187,\n      \"prior\": 3188,\n      \"report\": 3189,\n      \"chicago\": 3190,\n      \"read\": 3191,\n      \"foundation\": 3192,\n      \"view\": 3193,\n      \"engine\": 3194,\n      \"scored\": 3195,\n      \"1982\": 3196,\n      \"units\": 3197,\n      \"ask\": 3198,\n      \"airport\": 3199,\n      \"property\": 3200,\n      \"ready\": 3201,\n      \"immediately\": 3202,\n      \"lady\": 3203,\n      \"month\": 3204,\n      \"listed\": 3205,\n      \"contract\": 3206,\n      \"##de\": 3207,\n      \"manager\": 3208,\n      \"themselves\": 3209,\n      \"lines\": 3210,\n      \"##ki\": 3211,\n      \"navy\": 3212,\n      \"writer\": 3213,\n      \"meant\": 3214,\n      \"##ts\": 3215,\n      \"runs\": 3216,\n      \"##ro\": 3217,\n      \"practice\": 3218,\n      \"championships\": 3219,\n      \"singer\": 3220,\n      \"glass\": 3221,\n      \"commission\": 3222,\n      \"required\": 3223,\n      \"forest\": 3224,\n      \"starting\": 3225,\n      \"culture\": 3226,\n      \"generally\": 3227,\n      \"giving\": 3228,\n      \"access\": 3229,\n      \"attended\": 3230,\n      \"test\": 3231,\n      \"couple\": 3232,\n      \"stand\": 3233,\n      \"catholic\": 3234,\n      \"martin\": 3235,\n      \"caught\": 3236,\n      \"executive\": 3237,\n      \"##less\": 3238,\n      \"eye\": 3239,\n      \"##ey\": 3240,\n      \"thinking\": 3241,\n      \"chair\": 3242,\n      \"quite\": 3243,\n      \"shoulder\": 3244,\n      \"1979\": 3245,\n      \"hope\": 3246,\n      \"decision\": 3247,\n      \"plays\": 3248,\n      \"defeated\": 3249,\n      \"municipality\": 3250,\n      \"whether\": 3251,\n      \"structure\": 3252,\n      \"offered\": 3253,\n      \"slowly\": 3254,\n      \"pain\": 3255,\n      \"ice\": 3256,\n      \"direction\": 3257,\n      \"##ion\": 3258,\n      \"paper\": 3259,\n      \"mission\": 3260,\n      \"1981\": 3261,\n      \"mostly\": 3262,\n      \"200\": 3263,\n      \"noted\": 3264,\n      \"individual\": 3265,\n      \"managed\": 3266,\n      \"nature\": 3267,\n      \"lives\": 3268,\n      \"plant\": 3269,\n      \"##ha\": 3270,\n      \"helped\": 3271,\n      \"except\": 3272,\n      \"studied\": 3273,\n      \"computer\": 3274,\n      \"figure\": 3275,\n      \"relationship\": 3276,\n      \"issue\": 3277,\n      \"significant\": 3278,\n      \"loss\": 3279,\n      \"die\": 3280,\n      \"smiled\": 3281,\n      \"gun\": 3282,\n      \"ago\": 3283,\n      \"highest\": 3284,\n      \"1972\": 3285,\n      \"##am\": 3286,\n      \"male\": 3287,\n      \"bring\": 3288,\n      \"goals\": 3289,\n      \"mexico\": 3290,\n      \"problem\": 3291,\n      \"distance\": 3292,\n      \"commercial\": 3293,\n      \"completely\": 3294,\n      \"location\": 3295,\n      \"annual\": 3296,\n      \"famous\": 3297,\n      \"drive\": 3298,\n      \"1976\": 3299,\n      \"neck\": 3300,\n      \"1978\": 3301,\n      \"surface\": 3302,\n      \"caused\": 3303,\n      \"italy\": 3304,\n      \"understand\": 3305,\n      \"greek\": 3306,\n      \"highway\": 3307,\n      \"wrong\": 3308,\n      \"hotel\": 3309,\n      \"comes\": 3310,\n      \"appearance\": 3311,\n      \"joseph\": 3312,\n      \"double\": 3313,\n      \"issues\": 3314,\n      \"musical\": 3315,\n      \"companies\": 3316,\n      \"castle\": 3317,\n      \"income\": 3318,\n      \"review\": 3319,\n      \"assembly\": 3320,\n      \"bass\": 3321,\n      \"initially\": 3322,\n      \"parliament\": 3323,\n      \"artists\": 3324,\n      \"experience\": 3325,\n      \"1974\": 3326,\n      \"particular\": 3327,\n      \"walk\": 3328,\n      \"foot\": 3329,\n      \"engineering\": 3330,\n      \"talking\": 3331,\n      \"window\": 3332,\n      \"dropped\": 3333,\n      \"##ter\": 3334,\n      \"miss\": 3335,\n      \"baby\": 3336,\n      \"boys\": 3337,\n      \"break\": 3338,\n      \"1975\": 3339,\n      \"stars\": 3340,\n      \"edge\": 3341,\n      \"remember\": 3342,\n      \"policy\": 3343,\n      \"carried\": 3344,\n      \"train\": 3345,\n      \"stadium\": 3346,\n      \"bar\": 3347,\n      \"sex\": 3348,\n      \"angeles\": 3349,\n      \"evidence\": 3350,\n      \"##ge\": 3351,\n      \"becoming\": 3352,\n      \"assistant\": 3353,\n      \"soviet\": 3354,\n      \"1977\": 3355,\n      \"upper\": 3356,\n      \"step\": 3357,\n      \"wing\": 3358,\n      \"1970\": 3359,\n      \"youth\": 3360,\n      \"financial\": 3361,\n      \"reach\": 3362,\n      \"##ll\": 3363,\n      \"actor\": 3364,\n      \"numerous\": 3365,\n      \"##se\": 3366,\n      \"##st\": 3367,\n      \"nodded\": 3368,\n      \"arrived\": 3369,\n      \"##ation\": 3370,\n      \"minute\": 3371,\n      \"##nt\": 3372,\n      \"believed\": 3373,\n      \"sorry\": 3374,\n      \"complex\": 3375,\n      \"beautiful\": 3376,\n      \"victory\": 3377,\n      \"associated\": 3378,\n      \"temple\": 3379,\n      \"1968\": 3380,\n      \"1973\": 3381,\n      \"chance\": 3382,\n      \"perhaps\": 3383,\n      \"metal\": 3384,\n      \"##son\": 3385,\n      \"1945\": 3386,\n      \"bishop\": 3387,\n      \"##et\": 3388,\n      \"lee\": 3389,\n      \"launched\": 3390,\n      \"particularly\": 3391,\n      \"tree\": 3392,\n      \"le\": 3393,\n      \"retired\": 3394,\n      \"subject\": 3395,\n      \"prize\": 3396,\n      \"contains\": 3397,\n      \"yeah\": 3398,\n      \"theory\": 3399,\n      \"empire\": 3400,\n      \"##ce\": 3401,\n      \"suddenly\": 3402,\n      \"waiting\": 3403,\n      \"trust\": 3404,\n      \"recording\": 3405,\n      \"##to\": 3406,\n      \"happy\": 3407,\n      \"terms\": 3408,\n      \"camp\": 3409,\n      \"champion\": 3410,\n      \"1971\": 3411,\n      \"religious\": 3412,\n      \"pass\": 3413,\n      \"zealand\": 3414,\n      \"names\": 3415,\n      \"2nd\": 3416,\n      \"port\": 3417,\n      \"ancient\": 3418,\n      \"tom\": 3419,\n      \"corner\": 3420,\n      \"represented\": 3421,\n      \"watch\": 3422,\n      \"legal\": 3423,\n      \"anti\": 3424,\n      \"justice\": 3425,\n      \"cause\": 3426,\n      \"watched\": 3427,\n      \"brothers\": 3428,\n      \"45\": 3429,\n      \"material\": 3430,\n      \"changes\": 3431,\n      \"simply\": 3432,\n      \"response\": 3433,\n      \"louis\": 3434,\n      \"fast\": 3435,\n      \"##ting\": 3436,\n      \"answer\": 3437,\n      \"60\": 3438,\n      \"historical\": 3439,\n      \"1969\": 3440,\n      \"stories\": 3441,\n      \"straight\": 3442,\n      \"create\": 3443,\n      \"feature\": 3444,\n      \"increased\": 3445,\n      \"rate\": 3446,\n      \"administration\": 3447,\n      \"virginia\": 3448,\n      \"el\": 3449,\n      \"activities\": 3450,\n      \"cultural\": 3451,\n      \"overall\": 3452,\n      \"winner\": 3453,\n      \"programs\": 3454,\n      \"basketball\": 3455,\n      \"legs\": 3456,\n      \"guard\": 3457,\n      \"beyond\": 3458,\n      \"cast\": 3459,\n      \"doctor\": 3460,\n      \"mm\": 3461,\n      \"flight\": 3462,\n      \"results\": 3463,\n      \"remains\": 3464,\n      \"cost\": 3465,\n      \"effect\": 3466,\n      \"winter\": 3467,\n      \"##ble\": 3468,\n      \"larger\": 3469,\n      \"islands\": 3470,\n      \"problems\": 3471,\n      \"chairman\": 3472,\n      \"grew\": 3473,\n      \"commander\": 3474,\n      \"isn\": 3475,\n      \"1967\": 3476,\n      \"pay\": 3477,\n      \"failed\": 3478,\n      \"selected\": 3479,\n      \"hurt\": 3480,\n      \"fort\": 3481,\n      \"box\": 3482,\n      \"regiment\": 3483,\n      \"majority\": 3484,\n      \"journal\": 3485,\n      \"35\": 3486,\n      \"edward\": 3487,\n      \"plans\": 3488,\n      \"##ke\": 3489,\n      \"##ni\": 3490,\n      \"shown\": 3491,\n      \"pretty\": 3492,\n      \"irish\": 3493,\n      \"characters\": 3494,\n      \"directly\": 3495,\n      \"scene\": 3496,\n      \"likely\": 3497,\n      \"operated\": 3498,\n      \"allow\": 3499,\n      \"spring\": 3500,\n      \"##j\": 3501,\n      \"junior\": 3502,\n      \"matches\": 3503,\n      \"looks\": 3504,\n      \"mike\": 3505,\n      \"houses\": 3506,\n      \"fellow\": 3507,\n      \"##tion\": 3508,\n      \"beach\": 3509,\n      \"marriage\": 3510,\n      \"##ham\": 3511,\n      \"##ive\": 3512,\n      \"rules\": 3513,\n      \"oil\": 3514,\n      \"65\": 3515,\n      \"florida\": 3516,\n      \"expected\": 3517,\n      \"nearby\": 3518,\n      \"congress\": 3519,\n      \"sam\": 3520,\n      \"peace\": 3521,\n      \"recent\": 3522,\n      \"iii\": 3523,\n      \"wait\": 3524,\n      \"subsequently\": 3525,\n      \"cell\": 3526,\n      \"##do\": 3527,\n      \"variety\": 3528,\n      \"serving\": 3529,\n      \"agreed\": 3530,\n      \"please\": 3531,\n      \"poor\": 3532,\n      \"joe\": 3533,\n      \"pacific\": 3534,\n      \"attempt\": 3535,\n      \"wood\": 3536,\n      \"democratic\": 3537,\n      \"piece\": 3538,\n      \"prime\": 3539,\n      \"##ca\": 3540,\n      \"rural\": 3541,\n      \"mile\": 3542,\n      \"touch\": 3543,\n      \"appears\": 3544,\n      \"township\": 3545,\n      \"1964\": 3546,\n      \"1966\": 3547,\n      \"soldiers\": 3548,\n      \"##men\": 3549,\n      \"##ized\": 3550,\n      \"1965\": 3551,\n      \"pennsylvania\": 3552,\n      \"closer\": 3553,\n      \"fighting\": 3554,\n      \"claimed\": 3555,\n      \"score\": 3556,\n      \"jones\": 3557,\n      \"physical\": 3558,\n      \"editor\": 3559,\n      \"##ous\": 3560,\n      \"filled\": 3561,\n      \"genus\": 3562,\n      \"specific\": 3563,\n      \"sitting\": 3564,\n      \"super\": 3565,\n      \"mom\": 3566,\n      \"##va\": 3567,\n      \"therefore\": 3568,\n      \"supported\": 3569,\n      \"status\": 3570,\n      \"fear\": 3571,\n      \"cases\": 3572,\n      \"store\": 3573,\n      \"meaning\": 3574,\n      \"wales\": 3575,\n      \"minor\": 3576,\n      \"spain\": 3577,\n      \"tower\": 3578,\n      \"focus\": 3579,\n      \"vice\": 3580,\n      \"frank\": 3581,\n      \"follow\": 3582,\n      \"parish\": 3583,\n      \"separate\": 3584,\n      \"golden\": 3585,\n      \"horse\": 3586,\n      \"fifth\": 3587,\n      \"remaining\": 3588,\n      \"branch\": 3589,\n      \"32\": 3590,\n      \"presented\": 3591,\n      \"stared\": 3592,\n      \"##id\": 3593,\n      \"uses\": 3594,\n      \"secret\": 3595,\n      \"forms\": 3596,\n      \"##co\": 3597,\n      \"baseball\": 3598,\n      \"exactly\": 3599,\n      \"##ck\": 3600,\n      \"choice\": 3601,\n      \"note\": 3602,\n      \"discovered\": 3603,\n      \"travel\": 3604,\n      \"composed\": 3605,\n      \"truth\": 3606,\n      \"russia\": 3607,\n      \"ball\": 3608,\n      \"color\": 3609,\n      \"kiss\": 3610,\n      \"dad\": 3611,\n      \"wind\": 3612,\n      \"continue\": 3613,\n      \"ring\": 3614,\n      \"referred\": 3615,\n      \"numbers\": 3616,\n      \"digital\": 3617,\n      \"greater\": 3618,\n      \"##ns\": 3619,\n      \"metres\": 3620,\n      \"slightly\": 3621,\n      \"direct\": 3622,\n      \"increase\": 3623,\n      \"1960\": 3624,\n      \"responsible\": 3625,\n      \"crew\": 3626,\n      \"rule\": 3627,\n      \"trees\": 3628,\n      \"troops\": 3629,\n      \"##no\": 3630,\n      \"broke\": 3631,\n      \"goes\": 3632,\n      \"individuals\": 3633,\n      \"hundred\": 3634,\n      \"weight\": 3635,\n      \"creek\": 3636,\n      \"sleep\": 3637,\n      \"memory\": 3638,\n      \"defense\": 3639,\n      \"provides\": 3640,\n      \"ordered\": 3641,\n      \"code\": 3642,\n      \"value\": 3643,\n      \"jewish\": 3644,\n      \"windows\": 3645,\n      \"1944\": 3646,\n      \"safe\": 3647,\n      \"judge\": 3648,\n      \"whatever\": 3649,\n      \"corps\": 3650,\n      \"realized\": 3651,\n      \"growing\": 3652,\n      \"pre\": 3653,\n      \"##ga\": 3654,\n      \"cities\": 3655,\n      \"alexander\": 3656,\n      \"gaze\": 3657,\n      \"lies\": 3658,\n      \"spread\": 3659,\n      \"scott\": 3660,\n      \"letter\": 3661,\n      \"showed\": 3662,\n      \"situation\": 3663,\n      \"mayor\": 3664,\n      \"transport\": 3665,\n      \"watching\": 3666,\n      \"workers\": 3667,\n      \"extended\": 3668,\n      \"##li\": 3669,\n      \"expression\": 3670,\n      \"normal\": 3671,\n      \"##ment\": 3672,\n      \"chart\": 3673,\n      \"multiple\": 3674,\n      \"border\": 3675,\n      \"##ba\": 3676,\n      \"host\": 3677,\n      \"##ner\": 3678,\n      \"daily\": 3679,\n      \"mrs\": 3680,\n      \"walls\": 3681,\n      \"piano\": 3682,\n      \"##ko\": 3683,\n      \"heat\": 3684,\n      \"cannot\": 3685,\n      \"##ate\": 3686,\n      \"earned\": 3687,\n      \"products\": 3688,\n      \"drama\": 3689,\n      \"era\": 3690,\n      \"authority\": 3691,\n      \"seasons\": 3692,\n      \"join\": 3693,\n      \"grade\": 3694,\n      \"##io\": 3695,\n      \"sign\": 3696,\n      \"difficult\": 3697,\n      \"machine\": 3698,\n      \"1963\": 3699,\n      \"territory\": 3700,\n      \"mainly\": 3701,\n      \"##wood\": 3702,\n      \"stations\": 3703,\n      \"squadron\": 3704,\n      \"1962\": 3705,\n      \"stepped\": 3706,\n      \"iron\": 3707,\n      \"19th\": 3708,\n      \"##led\": 3709,\n      \"serve\": 3710,\n      \"appear\": 3711,\n      \"sky\": 3712,\n      \"speak\": 3713,\n      \"broken\": 3714,\n      \"charge\": 3715,\n      \"knowledge\": 3716,\n      \"kilometres\": 3717,\n      \"removed\": 3718,\n      \"ships\": 3719,\n      \"article\": 3720,\n      \"campus\": 3721,\n      \"simple\": 3722,\n      \"##ty\": 3723,\n      \"pushed\": 3724,\n      \"britain\": 3725,\n      \"##ve\": 3726,\n      \"leaves\": 3727,\n      \"recently\": 3728,\n      \"cd\": 3729,\n      \"soft\": 3730,\n      \"boston\": 3731,\n      \"latter\": 3732,\n      \"easy\": 3733,\n      \"acquired\": 3734,\n      \"poland\": 3735,\n      \"##sa\": 3736,\n      \"quality\": 3737,\n      \"officers\": 3738,\n      \"presence\": 3739,\n      \"planned\": 3740,\n      \"nations\": 3741,\n      \"mass\": 3742,\n      \"broadcast\": 3743,\n      \"jean\": 3744,\n      \"share\": 3745,\n      \"image\": 3746,\n      \"influence\": 3747,\n      \"wild\": 3748,\n      \"offer\": 3749,\n      \"emperor\": 3750,\n      \"electric\": 3751,\n      \"reading\": 3752,\n      \"headed\": 3753,\n      \"ability\": 3754,\n      \"promoted\": 3755,\n      \"yellow\": 3756,\n      \"ministry\": 3757,\n      \"1942\": 3758,\n      \"throat\": 3759,\n      \"smaller\": 3760,\n      \"politician\": 3761,\n      \"##by\": 3762,\n      \"latin\": 3763,\n      \"spoke\": 3764,\n      \"cars\": 3765,\n      \"williams\": 3766,\n      \"males\": 3767,\n      \"lack\": 3768,\n      \"pop\": 3769,\n      \"80\": 3770,\n      \"##ier\": 3771,\n      \"acting\": 3772,\n      \"seeing\": 3773,\n      \"consists\": 3774,\n      \"##ti\": 3775,\n      \"estate\": 3776,\n      \"1961\": 3777,\n      \"pressure\": 3778,\n      \"johnson\": 3779,\n      \"newspaper\": 3780,\n      \"jr\": 3781,\n      \"chris\": 3782,\n      \"olympics\": 3783,\n      \"online\": 3784,\n      \"conditions\": 3785,\n      \"beat\": 3786,\n      \"elements\": 3787,\n      \"walking\": 3788,\n      \"vote\": 3789,\n      \"##field\": 3790,\n      \"needs\": 3791,\n      \"carolina\": 3792,\n      \"text\": 3793,\n      \"featuring\": 3794,\n      \"global\": 3795,\n      \"block\": 3796,\n      \"shirt\": 3797,\n      \"levels\": 3798,\n      \"francisco\": 3799,\n      \"purpose\": 3800,\n      \"females\": 3801,\n      \"et\": 3802,\n      \"dutch\": 3803,\n      \"duke\": 3804,\n      \"ahead\": 3805,\n      \"gas\": 3806,\n      \"twice\": 3807,\n      \"safety\": 3808,\n      \"serious\": 3809,\n      \"turning\": 3810,\n      \"highly\": 3811,\n      \"lieutenant\": 3812,\n      \"firm\": 3813,\n      \"maria\": 3814,\n      \"amount\": 3815,\n      \"mixed\": 3816,\n      \"daniel\": 3817,\n      \"proposed\": 3818,\n      \"perfect\": 3819,\n      \"agreement\": 3820,\n      \"affairs\": 3821,\n      \"3rd\": 3822,\n      \"seconds\": 3823,\n      \"contemporary\": 3824,\n      \"paid\": 3825,\n      \"1943\": 3826,\n      \"prison\": 3827,\n      \"save\": 3828,\n      \"kitchen\": 3829,\n      \"label\": 3830,\n      \"administrative\": 3831,\n      \"intended\": 3832,\n      \"constructed\": 3833,\n      \"academic\": 3834,\n      \"nice\": 3835,\n      \"teacher\": 3836,\n      \"races\": 3837,\n      \"1956\": 3838,\n      \"formerly\": 3839,\n      \"corporation\": 3840,\n      \"ben\": 3841,\n      \"nation\": 3842,\n      \"issued\": 3843,\n      \"shut\": 3844,\n      \"1958\": 3845,\n      \"drums\": 3846,\n      \"housing\": 3847,\n      \"victoria\": 3848,\n      \"seems\": 3849,\n      \"opera\": 3850,\n      \"1959\": 3851,\n      \"graduated\": 3852,\n      \"function\": 3853,\n      \"von\": 3854,\n      \"mentioned\": 3855,\n      \"picked\": 3856,\n      \"build\": 3857,\n      \"recognized\": 3858,\n      \"shortly\": 3859,\n      \"protection\": 3860,\n      \"picture\": 3861,\n      \"notable\": 3862,\n      \"exchange\": 3863,\n      \"elections\": 3864,\n      \"1980s\": 3865,\n      \"loved\": 3866,\n      \"percent\": 3867,\n      \"racing\": 3868,\n      \"fish\": 3869,\n      \"elizabeth\": 3870,\n      \"garden\": 3871,\n      \"volume\": 3872,\n      \"hockey\": 3873,\n      \"1941\": 3874,\n      \"beside\": 3875,\n      \"settled\": 3876,\n      \"##ford\": 3877,\n      \"1940\": 3878,\n      \"competed\": 3879,\n      \"replied\": 3880,\n      \"drew\": 3881,\n      \"1948\": 3882,\n      \"actress\": 3883,\n      \"marine\": 3884,\n      \"scotland\": 3885,\n      \"steel\": 3886,\n      \"glanced\": 3887,\n      \"farm\": 3888,\n      \"steve\": 3889,\n      \"1957\": 3890,\n      \"risk\": 3891,\n      \"tonight\": 3892,\n      \"positive\": 3893,\n      \"magic\": 3894,\n      \"singles\": 3895,\n      \"effects\": 3896,\n      \"gray\": 3897,\n      \"screen\": 3898,\n      \"dog\": 3899,\n      \"##ja\": 3900,\n      \"residents\": 3901,\n      \"bus\": 3902,\n      \"sides\": 3903,\n      \"none\": 3904,\n      \"secondary\": 3905,\n      \"literature\": 3906,\n      \"polish\": 3907,\n      \"destroyed\": 3908,\n      \"flying\": 3909,\n      \"founder\": 3910,\n      \"households\": 3911,\n      \"1939\": 3912,\n      \"lay\": 3913,\n      \"reserve\": 3914,\n      \"usa\": 3915,\n      \"gallery\": 3916,\n      \"##ler\": 3917,\n      \"1946\": 3918,\n      \"industrial\": 3919,\n      \"younger\": 3920,\n      \"approach\": 3921,\n      \"appearances\": 3922,\n      \"urban\": 3923,\n      \"ones\": 3924,\n      \"1950\": 3925,\n      \"finish\": 3926,\n      \"avenue\": 3927,\n      \"powerful\": 3928,\n      \"fully\": 3929,\n      \"growth\": 3930,\n      \"page\": 3931,\n      \"honor\": 3932,\n      \"jersey\": 3933,\n      \"projects\": 3934,\n      \"advanced\": 3935,\n      \"revealed\": 3936,\n      \"basic\": 3937,\n      \"90\": 3938,\n      \"infantry\": 3939,\n      \"pair\": 3940,\n      \"equipment\": 3941,\n      \"visit\": 3942,\n      \"33\": 3943,\n      \"evening\": 3944,\n      \"search\": 3945,\n      \"grant\": 3946,\n      \"effort\": 3947,\n      \"solo\": 3948,\n      \"treatment\": 3949,\n      \"buried\": 3950,\n      \"republican\": 3951,\n      \"primarily\": 3952,\n      \"bottom\": 3953,\n      \"owner\": 3954,\n      \"1970s\": 3955,\n      \"israel\": 3956,\n      \"gives\": 3957,\n      \"jim\": 3958,\n      \"dream\": 3959,\n      \"bob\": 3960,\n      \"remain\": 3961,\n      \"spot\": 3962,\n      \"70\": 3963,\n      \"notes\": 3964,\n      \"produce\": 3965,\n      \"champions\": 3966,\n      \"contact\": 3967,\n      \"ed\": 3968,\n      \"soul\": 3969,\n      \"accepted\": 3970,\n      \"ways\": 3971,\n      \"del\": 3972,\n      \"##ally\": 3973,\n      \"losing\": 3974,\n      \"split\": 3975,\n      \"price\": 3976,\n      \"capacity\": 3977,\n      \"basis\": 3978,\n      \"trial\": 3979,\n      \"questions\": 3980,\n      \"##ina\": 3981,\n      \"1955\": 3982,\n      \"20th\": 3983,\n      \"guess\": 3984,\n      \"officially\": 3985,\n      \"memorial\": 3986,\n      \"naval\": 3987,\n      \"initial\": 3988,\n      \"##ization\": 3989,\n      \"whispered\": 3990,\n      \"median\": 3991,\n      \"engineer\": 3992,\n      \"##ful\": 3993,\n      \"sydney\": 3994,\n      \"##go\": 3995,\n      \"columbia\": 3996,\n      \"strength\": 3997,\n      \"300\": 3998,\n      \"1952\": 3999,\n      \"tears\": 4000,\n      \"senate\": 4001,\n      \"00\": 4002,\n      \"card\": 4003,\n      \"asian\": 4004,\n      \"agent\": 4005,\n      \"1947\": 4006,\n      \"software\": 4007,\n      \"44\": 4008,\n      \"draw\": 4009,\n      \"warm\": 4010,\n      \"supposed\": 4011,\n      \"com\": 4012,\n      \"pro\": 4013,\n      \"##il\": 4014,\n      \"transferred\": 4015,\n      \"leaned\": 4016,\n      \"##at\": 4017,\n      \"candidate\": 4018,\n      \"escape\": 4019,\n      \"mountains\": 4020,\n      \"asia\": 4021,\n      \"potential\": 4022,\n      \"activity\": 4023,\n      \"entertainment\": 4024,\n      \"seem\": 4025,\n      \"traffic\": 4026,\n      \"jackson\": 4027,\n      \"murder\": 4028,\n      \"36\": 4029,\n      \"slow\": 4030,\n      \"product\": 4031,\n      \"orchestra\": 4032,\n      \"haven\": 4033,\n      \"agency\": 4034,\n      \"bbc\": 4035,\n      \"taught\": 4036,\n      \"website\": 4037,\n      \"comedy\": 4038,\n      \"unable\": 4039,\n      \"storm\": 4040,\n      \"planning\": 4041,\n      \"albums\": 4042,\n      \"rugby\": 4043,\n      \"environment\": 4044,\n      \"scientific\": 4045,\n      \"grabbed\": 4046,\n      \"protect\": 4047,\n      \"##hi\": 4048,\n      \"boat\": 4049,\n      \"typically\": 4050,\n      \"1954\": 4051,\n      \"1953\": 4052,\n      \"damage\": 4053,\n      \"principal\": 4054,\n      \"divided\": 4055,\n      \"dedicated\": 4056,\n      \"mount\": 4057,\n      \"ohio\": 4058,\n      \"##berg\": 4059,\n      \"pick\": 4060,\n      \"fought\": 4061,\n      \"driver\": 4062,\n      \"##der\": 4063,\n      \"empty\": 4064,\n      \"shoulders\": 4065,\n      \"sort\": 4066,\n      \"thank\": 4067,\n      \"berlin\": 4068,\n      \"prominent\": 4069,\n      \"account\": 4070,\n      \"freedom\": 4071,\n      \"necessary\": 4072,\n      \"efforts\": 4073,\n      \"alex\": 4074,\n      \"headquarters\": 4075,\n      \"follows\": 4076,\n      \"alongside\": 4077,\n      \"des\": 4078,\n      \"simon\": 4079,\n      \"andrew\": 4080,\n      \"suggested\": 4081,\n      \"operating\": 4082,\n      \"learning\": 4083,\n      \"steps\": 4084,\n      \"1949\": 4085,\n      \"sweet\": 4086,\n      \"technical\": 4087,\n      \"begin\": 4088,\n      \"easily\": 4089,\n      \"34\": 4090,\n      \"teeth\": 4091,\n      \"speaking\": 4092,\n      \"settlement\": 4093,\n      \"scale\": 4094,\n      \"##sh\": 4095,\n      \"renamed\": 4096,\n      \"ray\": 4097,\n      \"max\": 4098,\n      \"enemy\": 4099,\n      \"semi\": 4100,\n      \"joint\": 4101,\n      \"compared\": 4102,\n      \"##rd\": 4103,\n      \"scottish\": 4104,\n      \"leadership\": 4105,\n      \"analysis\": 4106,\n      \"offers\": 4107,\n      \"georgia\": 4108,\n      \"pieces\": 4109,\n      \"captured\": 4110,\n      \"animal\": 4111,\n      \"deputy\": 4112,\n      \"guest\": 4113,\n      \"organized\": 4114,\n      \"##lin\": 4115,\n      \"tony\": 4116,\n      \"combined\": 4117,\n      \"method\": 4118,\n      \"challenge\": 4119,\n      \"1960s\": 4120,\n      \"huge\": 4121,\n      \"wants\": 4122,\n      \"battalion\": 4123,\n      \"sons\": 4124,\n      \"rise\": 4125,\n      \"crime\": 4126,\n      \"types\": 4127,\n      \"facilities\": 4128,\n      \"telling\": 4129,\n      \"path\": 4130,\n      \"1951\": 4131,\n      \"platform\": 4132,\n      \"sit\": 4133,\n      \"1990s\": 4134,\n      \"##lo\": 4135,\n      \"tells\": 4136,\n      \"assigned\": 4137,\n      \"rich\": 4138,\n      \"pull\": 4139,\n      \"##ot\": 4140,\n      \"commonly\": 4141,\n      \"alive\": 4142,\n      \"##za\": 4143,\n      \"letters\": 4144,\n      \"concept\": 4145,\n      \"conducted\": 4146,\n      \"wearing\": 4147,\n      \"happen\": 4148,\n      \"bought\": 4149,\n      \"becomes\": 4150,\n      \"holy\": 4151,\n      \"gets\": 4152,\n      \"ocean\": 4153,\n      \"defeat\": 4154,\n      \"languages\": 4155,\n      \"purchased\": 4156,\n      \"coffee\": 4157,\n      \"occurred\": 4158,\n      \"titled\": 4159,\n      \"##q\": 4160,\n      \"declared\": 4161,\n      \"applied\": 4162,\n      \"sciences\": 4163,\n      \"concert\": 4164,\n      \"sounds\": 4165,\n      \"jazz\": 4166,\n      \"brain\": 4167,\n      \"##me\": 4168,\n      \"painting\": 4169,\n      \"fleet\": 4170,\n      \"tax\": 4171,\n      \"nick\": 4172,\n      \"##ius\": 4173,\n      \"michigan\": 4174,\n      \"count\": 4175,\n      \"animals\": 4176,\n      \"leaders\": 4177,\n      \"episodes\": 4178,\n      \"##line\": 4179,\n      \"content\": 4180,\n      \"##den\": 4181,\n      \"birth\": 4182,\n      \"##it\": 4183,\n      \"clubs\": 4184,\n      \"64\": 4185,\n      \"palace\": 4186,\n      \"critical\": 4187,\n      \"refused\": 4188,\n      \"fair\": 4189,\n      \"leg\": 4190,\n      \"laughed\": 4191,\n      \"returning\": 4192,\n      \"surrounding\": 4193,\n      \"participated\": 4194,\n      \"formation\": 4195,\n      \"lifted\": 4196,\n      \"pointed\": 4197,\n      \"connected\": 4198,\n      \"rome\": 4199,\n      \"medicine\": 4200,\n      \"laid\": 4201,\n      \"taylor\": 4202,\n      \"santa\": 4203,\n      \"powers\": 4204,\n      \"adam\": 4205,\n      \"tall\": 4206,\n      \"shared\": 4207,\n      \"focused\": 4208,\n      \"knowing\": 4209,\n      \"yards\": 4210,\n      \"entrance\": 4211,\n      \"falls\": 4212,\n      \"##wa\": 4213,\n      \"calling\": 4214,\n      \"##ad\": 4215,\n      \"sources\": 4216,\n      \"chosen\": 4217,\n      \"beneath\": 4218,\n      \"resources\": 4219,\n      \"yard\": 4220,\n      \"##ite\": 4221,\n      \"nominated\": 4222,\n      \"silence\": 4223,\n      \"zone\": 4224,\n      \"defined\": 4225,\n      \"##que\": 4226,\n      \"gained\": 4227,\n      \"thirty\": 4228,\n      \"38\": 4229,\n      \"bodies\": 4230,\n      \"moon\": 4231,\n      \"##ard\": 4232,\n      \"adopted\": 4233,\n      \"christmas\": 4234,\n      \"widely\": 4235,\n      \"register\": 4236,\n      \"apart\": 4237,\n      \"iran\": 4238,\n      \"premier\": 4239,\n      \"serves\": 4240,\n      \"du\": 4241,\n      \"unknown\": 4242,\n      \"parties\": 4243,\n      \"##les\": 4244,\n      \"generation\": 4245,\n      \"##ff\": 4246,\n      \"continues\": 4247,\n      \"quick\": 4248,\n      \"fields\": 4249,\n      \"brigade\": 4250,\n      \"quiet\": 4251,\n      \"teaching\": 4252,\n      \"clothes\": 4253,\n      \"impact\": 4254,\n      \"weapons\": 4255,\n      \"partner\": 4256,\n      \"flat\": 4257,\n      \"theater\": 4258,\n      \"supreme\": 4259,\n      \"1938\": 4260,\n      \"37\": 4261,\n      \"relations\": 4262,\n      \"##tor\": 4263,\n      \"plants\": 4264,\n      \"suffered\": 4265,\n      \"1936\": 4266,\n      \"wilson\": 4267,\n      \"kids\": 4268,\n      \"begins\": 4269,\n      \"##age\": 4270,\n      \"1918\": 4271,\n      \"seats\": 4272,\n      \"armed\": 4273,\n      \"internet\": 4274,\n      \"models\": 4275,\n      \"worth\": 4276,\n      \"laws\": 4277,\n      \"400\": 4278,\n      \"communities\": 4279,\n      \"classes\": 4280,\n      \"background\": 4281,\n      \"knows\": 4282,\n      \"thanks\": 4283,\n      \"quarter\": 4284,\n      \"reaching\": 4285,\n      \"humans\": 4286,\n      \"carry\": 4287,\n      \"killing\": 4288,\n      \"format\": 4289,\n      \"kong\": 4290,\n      \"hong\": 4291,\n      \"setting\": 4292,\n      \"75\": 4293,\n      \"architecture\": 4294,\n      \"disease\": 4295,\n      \"railroad\": 4296,\n      \"inc\": 4297,\n      \"possibly\": 4298,\n      \"wish\": 4299,\n      \"arthur\": 4300,\n      \"thoughts\": 4301,\n      \"harry\": 4302,\n      \"doors\": 4303,\n      \"density\": 4304,\n      \"##di\": 4305,\n      \"crowd\": 4306,\n      \"illinois\": 4307,\n      \"stomach\": 4308,\n      \"tone\": 4309,\n      \"unique\": 4310,\n      \"reports\": 4311,\n      \"anyway\": 4312,\n      \"##ir\": 4313,\n      \"liberal\": 4314,\n      \"der\": 4315,\n      \"vehicle\": 4316,\n      \"thick\": 4317,\n      \"dry\": 4318,\n      \"drug\": 4319,\n      \"faced\": 4320,\n      \"largely\": 4321,\n      \"facility\": 4322,\n      \"theme\": 4323,\n      \"holds\": 4324,\n      \"creation\": 4325,\n      \"strange\": 4326,\n      \"colonel\": 4327,\n      \"##mi\": 4328,\n      \"revolution\": 4329,\n      \"bell\": 4330,\n      \"politics\": 4331,\n      \"turns\": 4332,\n      \"silent\": 4333,\n      \"rail\": 4334,\n      \"relief\": 4335,\n      \"independence\": 4336,\n      \"combat\": 4337,\n      \"shape\": 4338,\n      \"write\": 4339,\n      \"determined\": 4340,\n      \"sales\": 4341,\n      \"learned\": 4342,\n      \"4th\": 4343,\n      \"finger\": 4344,\n      \"oxford\": 4345,\n      \"providing\": 4346,\n      \"1937\": 4347,\n      \"heritage\": 4348,\n      \"fiction\": 4349,\n      \"situated\": 4350,\n      \"designated\": 4351,\n      \"allowing\": 4352,\n      \"distribution\": 4353,\n      \"hosted\": 4354,\n      \"##est\": 4355,\n      \"sight\": 4356,\n      \"interview\": 4357,\n      \"estimated\": 4358,\n      \"reduced\": 4359,\n      \"##ria\": 4360,\n      \"toronto\": 4361,\n      \"footballer\": 4362,\n      \"keeping\": 4363,\n      \"guys\": 4364,\n      \"damn\": 4365,\n      \"claim\": 4366,\n      \"motion\": 4367,\n      \"sport\": 4368,\n      \"sixth\": 4369,\n      \"stayed\": 4370,\n      \"##ze\": 4371,\n      \"en\": 4372,\n      \"rear\": 4373,\n      \"receive\": 4374,\n      \"handed\": 4375,\n      \"twelve\": 4376,\n      \"dress\": 4377,\n      \"audience\": 4378,\n      \"granted\": 4379,\n      \"brazil\": 4380,\n      \"##well\": 4381,\n      \"spirit\": 4382,\n      \"##ated\": 4383,\n      \"noticed\": 4384,\n      \"etc\": 4385,\n      \"olympic\": 4386,\n      \"representative\": 4387,\n      \"eric\": 4388,\n      \"tight\": 4389,\n      \"trouble\": 4390,\n      \"reviews\": 4391,\n      \"drink\": 4392,\n      \"vampire\": 4393,\n      \"missing\": 4394,\n      \"roles\": 4395,\n      \"ranked\": 4396,\n      \"newly\": 4397,\n      \"household\": 4398,\n      \"finals\": 4399,\n      \"wave\": 4400,\n      \"critics\": 4401,\n      \"##ee\": 4402,\n      \"phase\": 4403,\n      \"massachusetts\": 4404,\n      \"pilot\": 4405,\n      \"unlike\": 4406,\n      \"philadelphia\": 4407,\n      \"bright\": 4408,\n      \"guns\": 4409,\n      \"crown\": 4410,\n      \"organizations\": 4411,\n      \"roof\": 4412,\n      \"42\": 4413,\n      \"respectively\": 4414,\n      \"clearly\": 4415,\n      \"tongue\": 4416,\n      \"marked\": 4417,\n      \"circle\": 4418,\n      \"fox\": 4419,\n      \"korea\": 4420,\n      \"bronze\": 4421,\n      \"brian\": 4422,\n      \"expanded\": 4423,\n      \"sexual\": 4424,\n      \"supply\": 4425,\n      \"yourself\": 4426,\n      \"inspired\": 4427,\n      \"labour\": 4428,\n      \"fc\": 4429,\n      \"##ah\": 4430,\n      \"reference\": 4431,\n      \"vision\": 4432,\n      \"draft\": 4433,\n      \"connection\": 4434,\n      \"brand\": 4435,\n      \"reasons\": 4436,\n      \"1935\": 4437,\n      \"classic\": 4438,\n      \"driving\": 4439,\n      \"trip\": 4440,\n      \"jesus\": 4441,\n      \"cells\": 4442,\n      \"entry\": 4443,\n      \"1920\": 4444,\n      \"neither\": 4445,\n      \"trail\": 4446,\n      \"claims\": 4447,\n      \"atlantic\": 4448,\n      \"orders\": 4449,\n      \"labor\": 4450,\n      \"nose\": 4451,\n      \"afraid\": 4452,\n      \"identified\": 4453,\n      \"intelligence\": 4454,\n      \"calls\": 4455,\n      \"cancer\": 4456,\n      \"attacked\": 4457,\n      \"passing\": 4458,\n      \"stephen\": 4459,\n      \"positions\": 4460,\n      \"imperial\": 4461,\n      \"grey\": 4462,\n      \"jason\": 4463,\n      \"39\": 4464,\n      \"sunday\": 4465,\n      \"48\": 4466,\n      \"swedish\": 4467,\n      \"avoid\": 4468,\n      \"extra\": 4469,\n      \"uncle\": 4470,\n      \"message\": 4471,\n      \"covers\": 4472,\n      \"allows\": 4473,\n      \"surprise\": 4474,\n      \"materials\": 4475,\n      \"fame\": 4476,\n      \"hunter\": 4477,\n      \"##ji\": 4478,\n      \"1930\": 4479,\n      \"citizens\": 4480,\n      \"figures\": 4481,\n      \"davis\": 4482,\n      \"environmental\": 4483,\n      \"confirmed\": 4484,\n      \"shit\": 4485,\n      \"titles\": 4486,\n      \"di\": 4487,\n      \"performing\": 4488,\n      \"difference\": 4489,\n      \"acts\": 4490,\n      \"attacks\": 4491,\n      \"##ov\": 4492,\n      \"existing\": 4493,\n      \"votes\": 4494,\n      \"opportunity\": 4495,\n      \"nor\": 4496,\n      \"shop\": 4497,\n      \"entirely\": 4498,\n      \"trains\": 4499,\n      \"opposite\": 4500,\n      \"pakistan\": 4501,\n      \"##pa\": 4502,\n      \"develop\": 4503,\n      \"resulted\": 4504,\n      \"representatives\": 4505,\n      \"actions\": 4506,\n      \"reality\": 4507,\n      \"pressed\": 4508,\n      \"##ish\": 4509,\n      \"barely\": 4510,\n      \"wine\": 4511,\n      \"conversation\": 4512,\n      \"faculty\": 4513,\n      \"northwest\": 4514,\n      \"ends\": 4515,\n      \"documentary\": 4516,\n      \"nuclear\": 4517,\n      \"stock\": 4518,\n      \"grace\": 4519,\n      \"sets\": 4520,\n      \"eat\": 4521,\n      \"alternative\": 4522,\n      \"##ps\": 4523,\n      \"bag\": 4524,\n      \"resulting\": 4525,\n      \"creating\": 4526,\n      \"surprised\": 4527,\n      \"cemetery\": 4528,\n      \"1919\": 4529,\n      \"drop\": 4530,\n      \"finding\": 4531,\n      \"sarah\": 4532,\n      \"cricket\": 4533,\n      \"streets\": 4534,\n      \"tradition\": 4535,\n      \"ride\": 4536,\n      \"1933\": 4537,\n      \"exhibition\": 4538,\n      \"target\": 4539,\n      \"ear\": 4540,\n      \"explained\": 4541,\n      \"rain\": 4542,\n      \"composer\": 4543,\n      \"injury\": 4544,\n      \"apartment\": 4545,\n      \"municipal\": 4546,\n      \"educational\": 4547,\n      \"occupied\": 4548,\n      \"netherlands\": 4549,\n      \"clean\": 4550,\n      \"billion\": 4551,\n      \"constitution\": 4552,\n      \"learn\": 4553,\n      \"1914\": 4554,\n      \"maximum\": 4555,\n      \"classical\": 4556,\n      \"francis\": 4557,\n      \"lose\": 4558,\n      \"opposition\": 4559,\n      \"jose\": 4560,\n      \"ontario\": 4561,\n      \"bear\": 4562,\n      \"core\": 4563,\n      \"hills\": 4564,\n      \"rolled\": 4565,\n      \"ending\": 4566,\n      \"drawn\": 4567,\n      \"permanent\": 4568,\n      \"fun\": 4569,\n      \"##tes\": 4570,\n      \"##lla\": 4571,\n      \"lewis\": 4572,\n      \"sites\": 4573,\n      \"chamber\": 4574,\n      \"ryan\": 4575,\n      \"##way\": 4576,\n      \"scoring\": 4577,\n      \"height\": 4578,\n      \"1934\": 4579,\n      \"##house\": 4580,\n      \"lyrics\": 4581,\n      \"staring\": 4582,\n      \"55\": 4583,\n      \"officials\": 4584,\n      \"1917\": 4585,\n      \"snow\": 4586,\n      \"oldest\": 4587,\n      \"##tic\": 4588,\n      \"orange\": 4589,\n      \"##ger\": 4590,\n      \"qualified\": 4591,\n      \"interior\": 4592,\n      \"apparently\": 4593,\n      \"succeeded\": 4594,\n      \"thousand\": 4595,\n      \"dinner\": 4596,\n      \"lights\": 4597,\n      \"existence\": 4598,\n      \"fans\": 4599,\n      \"heavily\": 4600,\n      \"41\": 4601,\n      \"greatest\": 4602,\n      \"conservative\": 4603,\n      \"send\": 4604,\n      \"bowl\": 4605,\n      \"plus\": 4606,\n      \"enter\": 4607,\n      \"catch\": 4608,\n      \"##un\": 4609,\n      \"economy\": 4610,\n      \"duty\": 4611,\n      \"1929\": 4612,\n      \"speech\": 4613,\n      \"authorities\": 4614,\n      \"princess\": 4615,\n      \"performances\": 4616,\n      \"versions\": 4617,\n      \"shall\": 4618,\n      \"graduate\": 4619,\n      \"pictures\": 4620,\n      \"effective\": 4621,\n      \"remembered\": 4622,\n      \"poetry\": 4623,\n      \"desk\": 4624,\n      \"crossed\": 4625,\n      \"starring\": 4626,\n      \"starts\": 4627,\n      \"passenger\": 4628,\n      \"sharp\": 4629,\n      \"##ant\": 4630,\n      \"acres\": 4631,\n      \"ass\": 4632,\n      \"weather\": 4633,\n      \"falling\": 4634,\n      \"rank\": 4635,\n      \"fund\": 4636,\n      \"supporting\": 4637,\n      \"check\": 4638,\n      \"adult\": 4639,\n      \"publishing\": 4640,\n      \"heads\": 4641,\n      \"cm\": 4642,\n      \"southeast\": 4643,\n      \"lane\": 4644,\n      \"##burg\": 4645,\n      \"application\": 4646,\n      \"bc\": 4647,\n      \"##ura\": 4648,\n      \"les\": 4649,\n      \"condition\": 4650,\n      \"transfer\": 4651,\n      \"prevent\": 4652,\n      \"display\": 4653,\n      \"ex\": 4654,\n      \"regions\": 4655,\n      \"earl\": 4656,\n      \"federation\": 4657,\n      \"cool\": 4658,\n      \"relatively\": 4659,\n      \"answered\": 4660,\n      \"besides\": 4661,\n      \"1928\": 4662,\n      \"obtained\": 4663,\n      \"portion\": 4664,\n      \"##town\": 4665,\n      \"mix\": 4666,\n      \"##ding\": 4667,\n      \"reaction\": 4668,\n      \"liked\": 4669,\n      \"dean\": 4670,\n      \"express\": 4671,\n      \"peak\": 4672,\n      \"1932\": 4673,\n      \"##tte\": 4674,\n      \"counter\": 4675,\n      \"religion\": 4676,\n      \"chain\": 4677,\n      \"rare\": 4678,\n      \"miller\": 4679,\n      \"convention\": 4680,\n      \"aid\": 4681,\n      \"lie\": 4682,\n      \"vehicles\": 4683,\n      \"mobile\": 4684,\n      \"perform\": 4685,\n      \"squad\": 4686,\n      \"wonder\": 4687,\n      \"lying\": 4688,\n      \"crazy\": 4689,\n      \"sword\": 4690,\n      \"##ping\": 4691,\n      \"attempted\": 4692,\n      \"centuries\": 4693,\n      \"weren\": 4694,\n      \"philosophy\": 4695,\n      \"category\": 4696,\n      \"##ize\": 4697,\n      \"anna\": 4698,\n      \"interested\": 4699,\n      \"47\": 4700,\n      \"sweden\": 4701,\n      \"wolf\": 4702,\n      \"frequently\": 4703,\n      \"abandoned\": 4704,\n      \"kg\": 4705,\n      \"literary\": 4706,\n      \"alliance\": 4707,\n      \"task\": 4708,\n      \"entitled\": 4709,\n      \"##ay\": 4710,\n      \"threw\": 4711,\n      \"promotion\": 4712,\n      \"factory\": 4713,\n      \"tiny\": 4714,\n      \"soccer\": 4715,\n      \"visited\": 4716,\n      \"matt\": 4717,\n      \"fm\": 4718,\n      \"achieved\": 4719,\n      \"52\": 4720,\n      \"defence\": 4721,\n      \"internal\": 4722,\n      \"persian\": 4723,\n      \"43\": 4724,\n      \"methods\": 4725,\n      \"##ging\": 4726,\n      \"arrested\": 4727,\n      \"otherwise\": 4728,\n      \"cambridge\": 4729,\n      \"programming\": 4730,\n      \"villages\": 4731,\n      \"elementary\": 4732,\n      \"districts\": 4733,\n      \"rooms\": 4734,\n      \"criminal\": 4735,\n      \"conflict\": 4736,\n      \"worry\": 4737,\n      \"trained\": 4738,\n      \"1931\": 4739,\n      \"attempts\": 4740,\n      \"waited\": 4741,\n      \"signal\": 4742,\n      \"bird\": 4743,\n      \"truck\": 4744,\n      \"subsequent\": 4745,\n      \"programme\": 4746,\n      \"##ol\": 4747,\n      \"ad\": 4748,\n      \"49\": 4749,\n      \"communist\": 4750,\n      \"details\": 4751,\n      \"faith\": 4752,\n      \"sector\": 4753,\n      \"patrick\": 4754,\n      \"carrying\": 4755,\n      \"laugh\": 4756,\n      \"##ss\": 4757,\n      \"controlled\": 4758,\n      \"korean\": 4759,\n      \"showing\": 4760,\n      \"origin\": 4761,\n      \"fuel\": 4762,\n      \"evil\": 4763,\n      \"1927\": 4764,\n      \"##ent\": 4765,\n      \"brief\": 4766,\n      \"identity\": 4767,\n      \"darkness\": 4768,\n      \"address\": 4769,\n      \"pool\": 4770,\n      \"missed\": 4771,\n      \"publication\": 4772,\n      \"web\": 4773,\n      \"planet\": 4774,\n      \"ian\": 4775,\n      \"anne\": 4776,\n      \"wings\": 4777,\n      \"invited\": 4778,\n      \"##tt\": 4779,\n      \"briefly\": 4780,\n      \"standards\": 4781,\n      \"kissed\": 4782,\n      \"##be\": 4783,\n      \"ideas\": 4784,\n      \"climate\": 4785,\n      \"causing\": 4786,\n      \"walter\": 4787,\n      \"worse\": 4788,\n      \"albert\": 4789,\n      \"articles\": 4790,\n      \"winners\": 4791,\n      \"desire\": 4792,\n      \"aged\": 4793,\n      \"northeast\": 4794,\n      \"dangerous\": 4795,\n      \"gate\": 4796,\n      \"doubt\": 4797,\n      \"1922\": 4798,\n      \"wooden\": 4799,\n      \"multi\": 4800,\n      \"##ky\": 4801,\n      \"poet\": 4802,\n      \"rising\": 4803,\n      \"funding\": 4804,\n      \"46\": 4805,\n      \"communications\": 4806,\n      \"communication\": 4807,\n      \"violence\": 4808,\n      \"copies\": 4809,\n      \"prepared\": 4810,\n      \"ford\": 4811,\n      \"investigation\": 4812,\n      \"skills\": 4813,\n      \"1924\": 4814,\n      \"pulling\": 4815,\n      \"electronic\": 4816,\n      \"##ak\": 4817,\n      \"##ial\": 4818,\n      \"##han\": 4819,\n      \"containing\": 4820,\n      \"ultimately\": 4821,\n      \"offices\": 4822,\n      \"singing\": 4823,\n      \"understanding\": 4824,\n      \"restaurant\": 4825,\n      \"tomorrow\": 4826,\n      \"fashion\": 4827,\n      \"christ\": 4828,\n      \"ward\": 4829,\n      \"da\": 4830,\n      \"pope\": 4831,\n      \"stands\": 4832,\n      \"5th\": 4833,\n      \"flow\": 4834,\n      \"studios\": 4835,\n      \"aired\": 4836,\n      \"commissioned\": 4837,\n      \"contained\": 4838,\n      \"exist\": 4839,\n      \"fresh\": 4840,\n      \"americans\": 4841,\n      \"##per\": 4842,\n      \"wrestling\": 4843,\n      \"approved\": 4844,\n      \"kid\": 4845,\n      \"employed\": 4846,\n      \"respect\": 4847,\n      \"suit\": 4848,\n      \"1925\": 4849,\n      \"angel\": 4850,\n      \"asking\": 4851,\n      \"increasing\": 4852,\n      \"frame\": 4853,\n      \"angry\": 4854,\n      \"selling\": 4855,\n      \"1950s\": 4856,\n      \"thin\": 4857,\n      \"finds\": 4858,\n      \"##nd\": 4859,\n      \"temperature\": 4860,\n      \"statement\": 4861,\n      \"ali\": 4862,\n      \"explain\": 4863,\n      \"inhabitants\": 4864,\n      \"towns\": 4865,\n      \"extensive\": 4866,\n      \"narrow\": 4867,\n      \"51\": 4868,\n      \"jane\": 4869,\n      \"flowers\": 4870,\n      \"images\": 4871,\n      \"promise\": 4872,\n      \"somewhere\": 4873,\n      \"object\": 4874,\n      \"fly\": 4875,\n      \"closely\": 4876,\n      \"##ls\": 4877,\n      \"1912\": 4878,\n      \"bureau\": 4879,\n      \"cape\": 4880,\n      \"1926\": 4881,\n      \"weekly\": 4882,\n      \"presidential\": 4883,\n      \"legislative\": 4884,\n      \"1921\": 4885,\n      \"##ai\": 4886,\n      \"##au\": 4887,\n      \"launch\": 4888,\n      \"founding\": 4889,\n      \"##ny\": 4890,\n      \"978\": 4891,\n      \"##ring\": 4892,\n      \"artillery\": 4893,\n      \"strike\": 4894,\n      \"un\": 4895,\n      \"institutions\": 4896,\n      \"roll\": 4897,\n      \"writers\": 4898,\n      \"landing\": 4899,\n      \"chose\": 4900,\n      \"kevin\": 4901,\n      \"anymore\": 4902,\n      \"pp\": 4903,\n      \"##ut\": 4904,\n      \"attorney\": 4905,\n      \"fit\": 4906,\n      \"dan\": 4907,\n      \"billboard\": 4908,\n      \"receiving\": 4909,\n      \"agricultural\": 4910,\n      \"breaking\": 4911,\n      \"sought\": 4912,\n      \"dave\": 4913,\n      \"admitted\": 4914,\n      \"lands\": 4915,\n      \"mexican\": 4916,\n      \"##bury\": 4917,\n      \"charlie\": 4918,\n      \"specifically\": 4919,\n      \"hole\": 4920,\n      \"iv\": 4921,\n      \"howard\": 4922,\n      \"credit\": 4923,\n      \"moscow\": 4924,\n      \"roads\": 4925,\n      \"accident\": 4926,\n      \"1923\": 4927,\n      \"proved\": 4928,\n      \"wear\": 4929,\n      \"struck\": 4930,\n      \"hey\": 4931,\n      \"guards\": 4932,\n      \"stuff\": 4933,\n      \"slid\": 4934,\n      \"expansion\": 4935,\n      \"1915\": 4936,\n      \"cat\": 4937,\n      \"anthony\": 4938,\n      \"##kin\": 4939,\n      \"melbourne\": 4940,\n      \"opposed\": 4941,\n      \"sub\": 4942,\n      \"southwest\": 4943,\n      \"architect\": 4944,\n      \"failure\": 4945,\n      \"plane\": 4946,\n      \"1916\": 4947,\n      \"##ron\": 4948,\n      \"map\": 4949,\n      \"camera\": 4950,\n      \"tank\": 4951,\n      \"listen\": 4952,\n      \"regarding\": 4953,\n      \"wet\": 4954,\n      \"introduction\": 4955,\n      \"metropolitan\": 4956,\n      \"link\": 4957,\n      \"ep\": 4958,\n      \"fighter\": 4959,\n      \"inch\": 4960,\n      \"grown\": 4961,\n      \"gene\": 4962,\n      \"anger\": 4963,\n      \"fixed\": 4964,\n      \"buy\": 4965,\n      \"dvd\": 4966,\n      \"khan\": 4967,\n      \"domestic\": 4968,\n      \"worldwide\": 4969,\n      \"chapel\": 4970,\n      \"mill\": 4971,\n      \"functions\": 4972,\n      \"examples\": 4973,\n      \"##head\": 4974,\n      \"developing\": 4975,\n      \"1910\": 4976,\n      \"turkey\": 4977,\n      \"hits\": 4978,\n      \"pocket\": 4979,\n      \"antonio\": 4980,\n      \"papers\": 4981,\n      \"grow\": 4982,\n      \"unless\": 4983,\n      \"circuit\": 4984,\n      \"18th\": 4985,\n      \"concerned\": 4986,\n      \"attached\": 4987,\n      \"journalist\": 4988,\n      \"selection\": 4989,\n      \"journey\": 4990,\n      \"converted\": 4991,\n      \"provincial\": 4992,\n      \"painted\": 4993,\n      \"hearing\": 4994,\n      \"aren\": 4995,\n      \"bands\": 4996,\n      \"negative\": 4997,\n      \"aside\": 4998,\n      \"wondered\": 4999,\n      \"knight\": 5000,\n      \"lap\": 5001,\n      \"survey\": 5002,\n      \"ma\": 5003,\n      \"##ow\": 5004,\n      \"noise\": 5005,\n      \"billy\": 5006,\n      \"##ium\": 5007,\n      \"shooting\": 5008,\n      \"guide\": 5009,\n      \"bedroom\": 5010,\n      \"priest\": 5011,\n      \"resistance\": 5012,\n      \"motor\": 5013,\n      \"homes\": 5014,\n      \"sounded\": 5015,\n      \"giant\": 5016,\n      \"##mer\": 5017,\n      \"150\": 5018,\n      \"scenes\": 5019,\n      \"equal\": 5020,\n      \"comic\": 5021,\n      \"patients\": 5022,\n      \"hidden\": 5023,\n      \"solid\": 5024,\n      \"actual\": 5025,\n      \"bringing\": 5026,\n      \"afternoon\": 5027,\n      \"touched\": 5028,\n      \"funds\": 5029,\n      \"wedding\": 5030,\n      \"consisted\": 5031,\n      \"marie\": 5032,\n      \"canal\": 5033,\n      \"sr\": 5034,\n      \"kim\": 5035,\n      \"treaty\": 5036,\n      \"turkish\": 5037,\n      \"recognition\": 5038,\n      \"residence\": 5039,\n      \"cathedral\": 5040,\n      \"broad\": 5041,\n      \"knees\": 5042,\n      \"incident\": 5043,\n      \"shaped\": 5044,\n      \"fired\": 5045,\n      \"norwegian\": 5046,\n      \"handle\": 5047,\n      \"cheek\": 5048,\n      \"contest\": 5049,\n      \"represent\": 5050,\n      \"##pe\": 5051,\n      \"representing\": 5052,\n      \"beauty\": 5053,\n      \"##sen\": 5054,\n      \"birds\": 5055,\n      \"advantage\": 5056,\n      \"emergency\": 5057,\n      \"wrapped\": 5058,\n      \"drawing\": 5059,\n      \"notice\": 5060,\n      \"pink\": 5061,\n      \"broadcasting\": 5062,\n      \"##ong\": 5063,\n      \"somehow\": 5064,\n      \"bachelor\": 5065,\n      \"seventh\": 5066,\n      \"collected\": 5067,\n      \"registered\": 5068,\n      \"establishment\": 5069,\n      \"alan\": 5070,\n      \"assumed\": 5071,\n      \"chemical\": 5072,\n      \"personnel\": 5073,\n      \"roger\": 5074,\n      \"retirement\": 5075,\n      \"jeff\": 5076,\n      \"portuguese\": 5077,\n      \"wore\": 5078,\n      \"tied\": 5079,\n      \"device\": 5080,\n      \"threat\": 5081,\n      \"progress\": 5082,\n      \"advance\": 5083,\n      \"##ised\": 5084,\n      \"banks\": 5085,\n      \"hired\": 5086,\n      \"manchester\": 5087,\n      \"nfl\": 5088,\n      \"teachers\": 5089,\n      \"structures\": 5090,\n      \"forever\": 5091,\n      \"##bo\": 5092,\n      \"tennis\": 5093,\n      \"helping\": 5094,\n      \"saturday\": 5095,\n      \"sale\": 5096,\n      \"applications\": 5097,\n      \"junction\": 5098,\n      \"hip\": 5099,\n      \"incorporated\": 5100,\n      \"neighborhood\": 5101,\n      \"dressed\": 5102,\n      \"ceremony\": 5103,\n      \"##ds\": 5104,\n      \"influenced\": 5105,\n      \"hers\": 5106,\n      \"visual\": 5107,\n      \"stairs\": 5108,\n      \"decades\": 5109,\n      \"inner\": 5110,\n      \"kansas\": 5111,\n      \"hung\": 5112,\n      \"hoped\": 5113,\n      \"gain\": 5114,\n      \"scheduled\": 5115,\n      \"downtown\": 5116,\n      \"engaged\": 5117,\n      \"austria\": 5118,\n      \"clock\": 5119,\n      \"norway\": 5120,\n      \"certainly\": 5121,\n      \"pale\": 5122,\n      \"protected\": 5123,\n      \"1913\": 5124,\n      \"victor\": 5125,\n      \"employees\": 5126,\n      \"plate\": 5127,\n      \"putting\": 5128,\n      \"surrounded\": 5129,\n      \"##ists\": 5130,\n      \"finishing\": 5131,\n      \"blues\": 5132,\n      \"tropical\": 5133,\n      \"##ries\": 5134,\n      \"minnesota\": 5135,\n      \"consider\": 5136,\n      \"philippines\": 5137,\n      \"accept\": 5138,\n      \"54\": 5139,\n      \"retrieved\": 5140,\n      \"1900\": 5141,\n      \"concern\": 5142,\n      \"anderson\": 5143,\n      \"properties\": 5144,\n      \"institution\": 5145,\n      \"gordon\": 5146,\n      \"successfully\": 5147,\n      \"vietnam\": 5148,\n      \"##dy\": 5149,\n      \"backing\": 5150,\n      \"outstanding\": 5151,\n      \"muslim\": 5152,\n      \"crossing\": 5153,\n      \"folk\": 5154,\n      \"producing\": 5155,\n      \"usual\": 5156,\n      \"demand\": 5157,\n      \"occurs\": 5158,\n      \"observed\": 5159,\n      \"lawyer\": 5160,\n      \"educated\": 5161,\n      \"##ana\": 5162,\n      \"kelly\": 5163,\n      \"string\": 5164,\n      \"pleasure\": 5165,\n      \"budget\": 5166,\n      \"items\": 5167,\n      \"quietly\": 5168,\n      \"colorado\": 5169,\n      \"philip\": 5170,\n      \"typical\": 5171,\n      \"##worth\": 5172,\n      \"derived\": 5173,\n      \"600\": 5174,\n      \"survived\": 5175,\n      \"asks\": 5176,\n      \"mental\": 5177,\n      \"##ide\": 5178,\n      \"56\": 5179,\n      \"jake\": 5180,\n      \"jews\": 5181,\n      \"distinguished\": 5182,\n      \"ltd\": 5183,\n      \"1911\": 5184,\n      \"sri\": 5185,\n      \"extremely\": 5186,\n      \"53\": 5187,\n      \"athletic\": 5188,\n      \"loud\": 5189,\n      \"thousands\": 5190,\n      \"worried\": 5191,\n      \"shadow\": 5192,\n      \"transportation\": 5193,\n      \"horses\": 5194,\n      \"weapon\": 5195,\n      \"arena\": 5196,\n      \"importance\": 5197,\n      \"users\": 5198,\n      \"tim\": 5199,\n      \"objects\": 5200,\n      \"contributed\": 5201,\n      \"dragon\": 5202,\n      \"douglas\": 5203,\n      \"aware\": 5204,\n      \"senator\": 5205,\n      \"johnny\": 5206,\n      \"jordan\": 5207,\n      \"sisters\": 5208,\n      \"engines\": 5209,\n      \"flag\": 5210,\n      \"investment\": 5211,\n      \"samuel\": 5212,\n      \"shock\": 5213,\n      \"capable\": 5214,\n      \"clark\": 5215,\n      \"row\": 5216,\n      \"wheel\": 5217,\n      \"refers\": 5218,\n      \"session\": 5219,\n      \"familiar\": 5220,\n      \"biggest\": 5221,\n      \"wins\": 5222,\n      \"hate\": 5223,\n      \"maintained\": 5224,\n      \"drove\": 5225,\n      \"hamilton\": 5226,\n      \"request\": 5227,\n      \"expressed\": 5228,\n      \"injured\": 5229,\n      \"underground\": 5230,\n      \"churches\": 5231,\n      \"walker\": 5232,\n      \"wars\": 5233,\n      \"tunnel\": 5234,\n      \"passes\": 5235,\n      \"stupid\": 5236,\n      \"agriculture\": 5237,\n      \"softly\": 5238,\n      \"cabinet\": 5239,\n      \"regarded\": 5240,\n      \"joining\": 5241,\n      \"indiana\": 5242,\n      \"##ea\": 5243,\n      \"##ms\": 5244,\n      \"push\": 5245,\n      \"dates\": 5246,\n      \"spend\": 5247,\n      \"behavior\": 5248,\n      \"woods\": 5249,\n      \"protein\": 5250,\n      \"gently\": 5251,\n      \"chase\": 5252,\n      \"morgan\": 5253,\n      \"mention\": 5254,\n      \"burning\": 5255,\n      \"wake\": 5256,\n      \"combination\": 5257,\n      \"occur\": 5258,\n      \"mirror\": 5259,\n      \"leads\": 5260,\n      \"jimmy\": 5261,\n      \"indeed\": 5262,\n      \"impossible\": 5263,\n      \"singapore\": 5264,\n      \"paintings\": 5265,\n      \"covering\": 5266,\n      \"##nes\": 5267,\n      \"soldier\": 5268,\n      \"locations\": 5269,\n      \"attendance\": 5270,\n      \"sell\": 5271,\n      \"historian\": 5272,\n      \"wisconsin\": 5273,\n      \"invasion\": 5274,\n      \"argued\": 5275,\n      \"painter\": 5276,\n      \"diego\": 5277,\n      \"changing\": 5278,\n      \"egypt\": 5279,\n      \"##don\": 5280,\n      \"experienced\": 5281,\n      \"inches\": 5282,\n      \"##ku\": 5283,\n      \"missouri\": 5284,\n      \"vol\": 5285,\n      \"grounds\": 5286,\n      \"spoken\": 5287,\n      \"switzerland\": 5288,\n      \"##gan\": 5289,\n      \"reform\": 5290,\n      \"rolling\": 5291,\n      \"ha\": 5292,\n      \"forget\": 5293,\n      \"massive\": 5294,\n      \"resigned\": 5295,\n      \"burned\": 5296,\n      \"allen\": 5297,\n      \"tennessee\": 5298,\n      \"locked\": 5299,\n      \"values\": 5300,\n      \"improved\": 5301,\n      \"##mo\": 5302,\n      \"wounded\": 5303,\n      \"universe\": 5304,\n      \"sick\": 5305,\n      \"dating\": 5306,\n      \"facing\": 5307,\n      \"pack\": 5308,\n      \"purchase\": 5309,\n      \"user\": 5310,\n      \"##pur\": 5311,\n      \"moments\": 5312,\n      \"##ul\": 5313,\n      \"merged\": 5314,\n      \"anniversary\": 5315,\n      \"1908\": 5316,\n      \"coal\": 5317,\n      \"brick\": 5318,\n      \"understood\": 5319,\n      \"causes\": 5320,\n      \"dynasty\": 5321,\n      \"queensland\": 5322,\n      \"establish\": 5323,\n      \"stores\": 5324,\n      \"crisis\": 5325,\n      \"promote\": 5326,\n      \"hoping\": 5327,\n      \"views\": 5328,\n      \"cards\": 5329,\n      \"referee\": 5330,\n      \"extension\": 5331,\n      \"##si\": 5332,\n      \"raise\": 5333,\n      \"arizona\": 5334,\n      \"improve\": 5335,\n      \"colonial\": 5336,\n      \"formal\": 5337,\n      \"charged\": 5338,\n      \"##rt\": 5339,\n      \"palm\": 5340,\n      \"lucky\": 5341,\n      \"hide\": 5342,\n      \"rescue\": 5343,\n      \"faces\": 5344,\n      \"95\": 5345,\n      \"feelings\": 5346,\n      \"candidates\": 5347,\n      \"juan\": 5348,\n      \"##ell\": 5349,\n      \"goods\": 5350,\n      \"6th\": 5351,\n      \"courses\": 5352,\n      \"weekend\": 5353,\n      \"59\": 5354,\n      \"luke\": 5355,\n      \"cash\": 5356,\n      \"fallen\": 5357,\n      \"##om\": 5358,\n      \"delivered\": 5359,\n      \"affected\": 5360,\n      \"installed\": 5361,\n      \"carefully\": 5362,\n      \"tries\": 5363,\n      \"swiss\": 5364,\n      \"hollywood\": 5365,\n      \"costs\": 5366,\n      \"lincoln\": 5367,\n      \"responsibility\": 5368,\n      \"##he\": 5369,\n      \"shore\": 5370,\n      \"file\": 5371,\n      \"proper\": 5372,\n      \"normally\": 5373,\n      \"maryland\": 5374,\n      \"assistance\": 5375,\n      \"jump\": 5376,\n      \"constant\": 5377,\n      \"offering\": 5378,\n      \"friendly\": 5379,\n      \"waters\": 5380,\n      \"persons\": 5381,\n      \"realize\": 5382,\n      \"contain\": 5383,\n      \"trophy\": 5384,\n      \"800\": 5385,\n      \"partnership\": 5386,\n      \"factor\": 5387,\n      \"58\": 5388,\n      \"musicians\": 5389,\n      \"cry\": 5390,\n      \"bound\": 5391,\n      \"oregon\": 5392,\n      \"indicated\": 5393,\n      \"hero\": 5394,\n      \"houston\": 5395,\n      \"medium\": 5396,\n      \"##ure\": 5397,\n      \"consisting\": 5398,\n      \"somewhat\": 5399,\n      \"##ara\": 5400,\n      \"57\": 5401,\n      \"cycle\": 5402,\n      \"##che\": 5403,\n      \"beer\": 5404,\n      \"moore\": 5405,\n      \"frederick\": 5406,\n      \"gotten\": 5407,\n      \"eleven\": 5408,\n      \"worst\": 5409,\n      \"weak\": 5410,\n      \"approached\": 5411,\n      \"arranged\": 5412,\n      \"chin\": 5413,\n      \"loan\": 5414,\n      \"universal\": 5415,\n      \"bond\": 5416,\n      \"fifteen\": 5417,\n      \"pattern\": 5418,\n      \"disappeared\": 5419,\n      \"##ney\": 5420,\n      \"translated\": 5421,\n      \"##zed\": 5422,\n      \"lip\": 5423,\n      \"arab\": 5424,\n      \"capture\": 5425,\n      \"interests\": 5426,\n      \"insurance\": 5427,\n      \"##chi\": 5428,\n      \"shifted\": 5429,\n      \"cave\": 5430,\n      \"prix\": 5431,\n      \"warning\": 5432,\n      \"sections\": 5433,\n      \"courts\": 5434,\n      \"coat\": 5435,\n      \"plot\": 5436,\n      \"smell\": 5437,\n      \"feed\": 5438,\n      \"golf\": 5439,\n      \"favorite\": 5440,\n      \"maintain\": 5441,\n      \"knife\": 5442,\n      \"vs\": 5443,\n      \"voted\": 5444,\n      \"degrees\": 5445,\n      \"finance\": 5446,\n      \"quebec\": 5447,\n      \"opinion\": 5448,\n      \"translation\": 5449,\n      \"manner\": 5450,\n      \"ruled\": 5451,\n      \"operate\": 5452,\n      \"productions\": 5453,\n      \"choose\": 5454,\n      \"musician\": 5455,\n      \"discovery\": 5456,\n      \"confused\": 5457,\n      \"tired\": 5458,\n      \"separated\": 5459,\n      \"stream\": 5460,\n      \"techniques\": 5461,\n      \"committed\": 5462,\n      \"attend\": 5463,\n      \"ranking\": 5464,\n      \"kings\": 5465,\n      \"throw\": 5466,\n      \"passengers\": 5467,\n      \"measure\": 5468,\n      \"horror\": 5469,\n      \"fan\": 5470,\n      \"mining\": 5471,\n      \"sand\": 5472,\n      \"danger\": 5473,\n      \"salt\": 5474,\n      \"calm\": 5475,\n      \"decade\": 5476,\n      \"dam\": 5477,\n      \"require\": 5478,\n      \"runner\": 5479,\n      \"##ik\": 5480,\n      \"rush\": 5481,\n      \"associate\": 5482,\n      \"greece\": 5483,\n      \"##ker\": 5484,\n      \"rivers\": 5485,\n      \"consecutive\": 5486,\n      \"matthew\": 5487,\n      \"##ski\": 5488,\n      \"sighed\": 5489,\n      \"sq\": 5490,\n      \"documents\": 5491,\n      \"steam\": 5492,\n      \"edited\": 5493,\n      \"closing\": 5494,\n      \"tie\": 5495,\n      \"accused\": 5496,\n      \"1905\": 5497,\n      \"##ini\": 5498,\n      \"islamic\": 5499,\n      \"distributed\": 5500,\n      \"directors\": 5501,\n      \"organisation\": 5502,\n      \"bruce\": 5503,\n      \"7th\": 5504,\n      \"breathing\": 5505,\n      \"mad\": 5506,\n      \"lit\": 5507,\n      \"arrival\": 5508,\n      \"concrete\": 5509,\n      \"taste\": 5510,\n      \"08\": 5511,\n      \"composition\": 5512,\n      \"shaking\": 5513,\n      \"faster\": 5514,\n      \"amateur\": 5515,\n      \"adjacent\": 5516,\n      \"stating\": 5517,\n      \"1906\": 5518,\n      \"twin\": 5519,\n      \"flew\": 5520,\n      \"##ran\": 5521,\n      \"tokyo\": 5522,\n      \"publications\": 5523,\n      \"##tone\": 5524,\n      \"obviously\": 5525,\n      \"ridge\": 5526,\n      \"storage\": 5527,\n      \"1907\": 5528,\n      \"carl\": 5529,\n      \"pages\": 5530,\n      \"concluded\": 5531,\n      \"desert\": 5532,\n      \"driven\": 5533,\n      \"universities\": 5534,\n      \"ages\": 5535,\n      \"terminal\": 5536,\n      \"sequence\": 5537,\n      \"borough\": 5538,\n      \"250\": 5539,\n      \"constituency\": 5540,\n      \"creative\": 5541,\n      \"cousin\": 5542,\n      \"economics\": 5543,\n      \"dreams\": 5544,\n      \"margaret\": 5545,\n      \"notably\": 5546,\n      \"reduce\": 5547,\n      \"montreal\": 5548,\n      \"mode\": 5549,\n      \"17th\": 5550,\n      \"ears\": 5551,\n      \"saved\": 5552,\n      \"jan\": 5553,\n      \"vocal\": 5554,\n      \"##ica\": 5555,\n      \"1909\": 5556,\n      \"andy\": 5557,\n      \"##jo\": 5558,\n      \"riding\": 5559,\n      \"roughly\": 5560,\n      \"threatened\": 5561,\n      \"##ise\": 5562,\n      \"meters\": 5563,\n      \"meanwhile\": 5564,\n      \"landed\": 5565,\n      \"compete\": 5566,\n      \"repeated\": 5567,\n      \"grass\": 5568,\n      \"czech\": 5569,\n      \"regularly\": 5570,\n      \"charges\": 5571,\n      \"tea\": 5572,\n      \"sudden\": 5573,\n      \"appeal\": 5574,\n      \"##ung\": 5575,\n      \"solution\": 5576,\n      \"describes\": 5577,\n      \"pierre\": 5578,\n      \"classification\": 5579,\n      \"glad\": 5580,\n      \"parking\": 5581,\n      \"##ning\": 5582,\n      \"belt\": 5583,\n      \"physics\": 5584,\n      \"99\": 5585,\n      \"rachel\": 5586,\n      \"add\": 5587,\n      \"hungarian\": 5588,\n      \"participate\": 5589,\n      \"expedition\": 5590,\n      \"damaged\": 5591,\n      \"gift\": 5592,\n      \"childhood\": 5593,\n      \"85\": 5594,\n      \"fifty\": 5595,\n      \"##red\": 5596,\n      \"mathematics\": 5597,\n      \"jumped\": 5598,\n      \"letting\": 5599,\n      \"defensive\": 5600,\n      \"mph\": 5601,\n      \"##ux\": 5602,\n      \"##gh\": 5603,\n      \"testing\": 5604,\n      \"##hip\": 5605,\n      \"hundreds\": 5606,\n      \"shoot\": 5607,\n      \"owners\": 5608,\n      \"matters\": 5609,\n      \"smoke\": 5610,\n      \"israeli\": 5611,\n      \"kentucky\": 5612,\n      \"dancing\": 5613,\n      \"mounted\": 5614,\n      \"grandfather\": 5615,\n      \"emma\": 5616,\n      \"designs\": 5617,\n      \"profit\": 5618,\n      \"argentina\": 5619,\n      \"##gs\": 5620,\n      \"truly\": 5621,\n      \"li\": 5622,\n      \"lawrence\": 5623,\n      \"cole\": 5624,\n      \"begun\": 5625,\n      \"detroit\": 5626,\n      \"willing\": 5627,\n      \"branches\": 5628,\n      \"smiling\": 5629,\n      \"decide\": 5630,\n      \"miami\": 5631,\n      \"enjoyed\": 5632,\n      \"recordings\": 5633,\n      \"##dale\": 5634,\n      \"poverty\": 5635,\n      \"ethnic\": 5636,\n      \"gay\": 5637,\n      \"##bi\": 5638,\n      \"gary\": 5639,\n      \"arabic\": 5640,\n      \"09\": 5641,\n      \"accompanied\": 5642,\n      \"##one\": 5643,\n      \"##ons\": 5644,\n      \"fishing\": 5645,\n      \"determine\": 5646,\n      \"residential\": 5647,\n      \"acid\": 5648,\n      \"##ary\": 5649,\n      \"alice\": 5650,\n      \"returns\": 5651,\n      \"starred\": 5652,\n      \"mail\": 5653,\n      \"##ang\": 5654,\n      \"jonathan\": 5655,\n      \"strategy\": 5656,\n      \"##ue\": 5657,\n      \"net\": 5658,\n      \"forty\": 5659,\n      \"cook\": 5660,\n      \"businesses\": 5661,\n      \"equivalent\": 5662,\n      \"commonwealth\": 5663,\n      \"distinct\": 5664,\n      \"ill\": 5665,\n      \"##cy\": 5666,\n      \"seriously\": 5667,\n      \"##ors\": 5668,\n      \"##ped\": 5669,\n      \"shift\": 5670,\n      \"harris\": 5671,\n      \"replace\": 5672,\n      \"rio\": 5673,\n      \"imagine\": 5674,\n      \"formula\": 5675,\n      \"ensure\": 5676,\n      \"##ber\": 5677,\n      \"additionally\": 5678,\n      \"scheme\": 5679,\n      \"conservation\": 5680,\n      \"occasionally\": 5681,\n      \"purposes\": 5682,\n      \"feels\": 5683,\n      \"favor\": 5684,\n      \"##and\": 5685,\n      \"##ore\": 5686,\n      \"1930s\": 5687,\n      \"contrast\": 5688,\n      \"hanging\": 5689,\n      \"hunt\": 5690,\n      \"movies\": 5691,\n      \"1904\": 5692,\n      \"instruments\": 5693,\n      \"victims\": 5694,\n      \"danish\": 5695,\n      \"christopher\": 5696,\n      \"busy\": 5697,\n      \"demon\": 5698,\n      \"sugar\": 5699,\n      \"earliest\": 5700,\n      \"colony\": 5701,\n      \"studying\": 5702,\n      \"balance\": 5703,\n      \"duties\": 5704,\n      \"##ks\": 5705,\n      \"belgium\": 5706,\n      \"slipped\": 5707,\n      \"carter\": 5708,\n      \"05\": 5709,\n      \"visible\": 5710,\n      \"stages\": 5711,\n      \"iraq\": 5712,\n      \"fifa\": 5713,\n      \"##im\": 5714,\n      \"commune\": 5715,\n      \"forming\": 5716,\n      \"zero\": 5717,\n      \"07\": 5718,\n      \"continuing\": 5719,\n      \"talked\": 5720,\n      \"counties\": 5721,\n      \"legend\": 5722,\n      \"bathroom\": 5723,\n      \"option\": 5724,\n      \"tail\": 5725,\n      \"clay\": 5726,\n      \"daughters\": 5727,\n      \"afterwards\": 5728,\n      \"severe\": 5729,\n      \"jaw\": 5730,\n      \"visitors\": 5731,\n      \"##ded\": 5732,\n      \"devices\": 5733,\n      \"aviation\": 5734,\n      \"russell\": 5735,\n      \"kate\": 5736,\n      \"##vi\": 5737,\n      \"entering\": 5738,\n      \"subjects\": 5739,\n      \"##ino\": 5740,\n      \"temporary\": 5741,\n      \"swimming\": 5742,\n      \"forth\": 5743,\n      \"smooth\": 5744,\n      \"ghost\": 5745,\n      \"audio\": 5746,\n      \"bush\": 5747,\n      \"operates\": 5748,\n      \"rocks\": 5749,\n      \"movements\": 5750,\n      \"signs\": 5751,\n      \"eddie\": 5752,\n      \"##tz\": 5753,\n      \"ann\": 5754,\n      \"voices\": 5755,\n      \"honorary\": 5756,\n      \"06\": 5757,\n      \"memories\": 5758,\n      \"dallas\": 5759,\n      \"pure\": 5760,\n      \"measures\": 5761,\n      \"racial\": 5762,\n      \"promised\": 5763,\n      \"66\": 5764,\n      \"harvard\": 5765,\n      \"ceo\": 5766,\n      \"16th\": 5767,\n      \"parliamentary\": 5768,\n      \"indicate\": 5769,\n      \"benefit\": 5770,\n      \"flesh\": 5771,\n      \"dublin\": 5772,\n      \"louisiana\": 5773,\n      \"1902\": 5774,\n      \"1901\": 5775,\n      \"patient\": 5776,\n      \"sleeping\": 5777,\n      \"1903\": 5778,\n      \"membership\": 5779,\n      \"coastal\": 5780,\n      \"medieval\": 5781,\n      \"wanting\": 5782,\n      \"element\": 5783,\n      \"scholars\": 5784,\n      \"rice\": 5785,\n      \"62\": 5786,\n      \"limit\": 5787,\n      \"survive\": 5788,\n      \"makeup\": 5789,\n      \"rating\": 5790,\n      \"definitely\": 5791,\n      \"collaboration\": 5792,\n      \"obvious\": 5793,\n      \"##tan\": 5794,\n      \"boss\": 5795,\n      \"ms\": 5796,\n      \"baron\": 5797,\n      \"birthday\": 5798,\n      \"linked\": 5799,\n      \"soil\": 5800,\n      \"diocese\": 5801,\n      \"##lan\": 5802,\n      \"ncaa\": 5803,\n      \"##mann\": 5804,\n      \"offensive\": 5805,\n      \"shell\": 5806,\n      \"shouldn\": 5807,\n      \"waist\": 5808,\n      \"##tus\": 5809,\n      \"plain\": 5810,\n      \"ross\": 5811,\n      \"organ\": 5812,\n      \"resolution\": 5813,\n      \"manufacturing\": 5814,\n      \"adding\": 5815,\n      \"relative\": 5816,\n      \"kennedy\": 5817,\n      \"98\": 5818,\n      \"whilst\": 5819,\n      \"moth\": 5820,\n      \"marketing\": 5821,\n      \"gardens\": 5822,\n      \"crash\": 5823,\n      \"72\": 5824,\n      \"heading\": 5825,\n      \"partners\": 5826,\n      \"credited\": 5827,\n      \"carlos\": 5828,\n      \"moves\": 5829,\n      \"cable\": 5830,\n      \"##zi\": 5831,\n      \"marshall\": 5832,\n      \"##out\": 5833,\n      \"depending\": 5834,\n      \"bottle\": 5835,\n      \"represents\": 5836,\n      \"rejected\": 5837,\n      \"responded\": 5838,\n      \"existed\": 5839,\n      \"04\": 5840,\n      \"jobs\": 5841,\n      \"denmark\": 5842,\n      \"lock\": 5843,\n      \"##ating\": 5844,\n      \"treated\": 5845,\n      \"graham\": 5846,\n      \"routes\": 5847,\n      \"talent\": 5848,\n      \"commissioner\": 5849,\n      \"drugs\": 5850,\n      \"secure\": 5851,\n      \"tests\": 5852,\n      \"reign\": 5853,\n      \"restored\": 5854,\n      \"photography\": 5855,\n      \"##gi\": 5856,\n      \"contributions\": 5857,\n      \"oklahoma\": 5858,\n      \"designer\": 5859,\n      \"disc\": 5860,\n      \"grin\": 5861,\n      \"seattle\": 5862,\n      \"robin\": 5863,\n      \"paused\": 5864,\n      \"atlanta\": 5865,\n      \"unusual\": 5866,\n      \"##gate\": 5867,\n      \"praised\": 5868,\n      \"las\": 5869,\n      \"laughing\": 5870,\n      \"satellite\": 5871,\n      \"hungary\": 5872,\n      \"visiting\": 5873,\n      \"##sky\": 5874,\n      \"interesting\": 5875,\n      \"factors\": 5876,\n      \"deck\": 5877,\n      \"poems\": 5878,\n      \"norman\": 5879,\n      \"##water\": 5880,\n      \"stuck\": 5881,\n      \"speaker\": 5882,\n      \"rifle\": 5883,\n      \"domain\": 5884,\n      \"premiered\": 5885,\n      \"##her\": 5886,\n      \"dc\": 5887,\n      \"comics\": 5888,\n      \"actors\": 5889,\n      \"01\": 5890,\n      \"reputation\": 5891,\n      \"eliminated\": 5892,\n      \"8th\": 5893,\n      \"ceiling\": 5894,\n      \"prisoners\": 5895,\n      \"script\": 5896,\n      \"##nce\": 5897,\n      \"leather\": 5898,\n      \"austin\": 5899,\n      \"mississippi\": 5900,\n      \"rapidly\": 5901,\n      \"admiral\": 5902,\n      \"parallel\": 5903,\n      \"charlotte\": 5904,\n      \"guilty\": 5905,\n      \"tools\": 5906,\n      \"gender\": 5907,\n      \"divisions\": 5908,\n      \"fruit\": 5909,\n      \"##bs\": 5910,\n      \"laboratory\": 5911,\n      \"nelson\": 5912,\n      \"fantasy\": 5913,\n      \"marry\": 5914,\n      \"rapid\": 5915,\n      \"aunt\": 5916,\n      \"tribe\": 5917,\n      \"requirements\": 5918,\n      \"aspects\": 5919,\n      \"suicide\": 5920,\n      \"amongst\": 5921,\n      \"adams\": 5922,\n      \"bone\": 5923,\n      \"ukraine\": 5924,\n      \"abc\": 5925,\n      \"kick\": 5926,\n      \"sees\": 5927,\n      \"edinburgh\": 5928,\n      \"clothing\": 5929,\n      \"column\": 5930,\n      \"rough\": 5931,\n      \"gods\": 5932,\n      \"hunting\": 5933,\n      \"broadway\": 5934,\n      \"gathered\": 5935,\n      \"concerns\": 5936,\n      \"##ek\": 5937,\n      \"spending\": 5938,\n      \"ty\": 5939,\n      \"12th\": 5940,\n      \"snapped\": 5941,\n      \"requires\": 5942,\n      \"solar\": 5943,\n      \"bones\": 5944,\n      \"cavalry\": 5945,\n      \"##tta\": 5946,\n      \"iowa\": 5947,\n      \"drinking\": 5948,\n      \"waste\": 5949,\n      \"index\": 5950,\n      \"franklin\": 5951,\n      \"charity\": 5952,\n      \"thompson\": 5953,\n      \"stewart\": 5954,\n      \"tip\": 5955,\n      \"flash\": 5956,\n      \"landscape\": 5957,\n      \"friday\": 5958,\n      \"enjoy\": 5959,\n      \"singh\": 5960,\n      \"poem\": 5961,\n      \"listening\": 5962,\n      \"##back\": 5963,\n      \"eighth\": 5964,\n      \"fred\": 5965,\n      \"differences\": 5966,\n      \"adapted\": 5967,\n      \"bomb\": 5968,\n      \"ukrainian\": 5969,\n      \"surgery\": 5970,\n      \"corporate\": 5971,\n      \"masters\": 5972,\n      \"anywhere\": 5973,\n      \"##more\": 5974,\n      \"waves\": 5975,\n      \"odd\": 5976,\n      \"sean\": 5977,\n      \"portugal\": 5978,\n      \"orleans\": 5979,\n      \"dick\": 5980,\n      \"debate\": 5981,\n      \"kent\": 5982,\n      \"eating\": 5983,\n      \"puerto\": 5984,\n      \"cleared\": 5985,\n      \"96\": 5986,\n      \"expect\": 5987,\n      \"cinema\": 5988,\n      \"97\": 5989,\n      \"guitarist\": 5990,\n      \"blocks\": 5991,\n      \"electrical\": 5992,\n      \"agree\": 5993,\n      \"involving\": 5994,\n      \"depth\": 5995,\n      \"dying\": 5996,\n      \"panel\": 5997,\n      \"struggle\": 5998,\n      \"##ged\": 5999,\n      \"peninsula\": 6000,\n      \"adults\": 6001,\n      \"novels\": 6002,\n      \"emerged\": 6003,\n      \"vienna\": 6004,\n      \"metro\": 6005,\n      \"debuted\": 6006,\n      \"shoes\": 6007,\n      \"tamil\": 6008,\n      \"songwriter\": 6009,\n      \"meets\": 6010,\n      \"prove\": 6011,\n      \"beating\": 6012,\n      \"instance\": 6013,\n      \"heaven\": 6014,\n      \"scared\": 6015,\n      \"sending\": 6016,\n      \"marks\": 6017,\n      \"artistic\": 6018,\n      \"passage\": 6019,\n      \"superior\": 6020,\n      \"03\": 6021,\n      \"significantly\": 6022,\n      \"shopping\": 6023,\n      \"##tive\": 6024,\n      \"retained\": 6025,\n      \"##izing\": 6026,\n      \"malaysia\": 6027,\n      \"technique\": 6028,\n      \"cheeks\": 6029,\n      \"##ola\": 6030,\n      \"warren\": 6031,\n      \"maintenance\": 6032,\n      \"destroy\": 6033,\n      \"extreme\": 6034,\n      \"allied\": 6035,\n      \"120\": 6036,\n      \"appearing\": 6037,\n      \"##yn\": 6038,\n      \"fill\": 6039,\n      \"advice\": 6040,\n      \"alabama\": 6041,\n      \"qualifying\": 6042,\n      \"policies\": 6043,\n      \"cleveland\": 6044,\n      \"hat\": 6045,\n      \"battery\": 6046,\n      \"smart\": 6047,\n      \"authors\": 6048,\n      \"10th\": 6049,\n      \"soundtrack\": 6050,\n      \"acted\": 6051,\n      \"dated\": 6052,\n      \"lb\": 6053,\n      \"glance\": 6054,\n      \"equipped\": 6055,\n      \"coalition\": 6056,\n      \"funny\": 6057,\n      \"outer\": 6058,\n      \"ambassador\": 6059,\n      \"roy\": 6060,\n      \"possibility\": 6061,\n      \"couples\": 6062,\n      \"campbell\": 6063,\n      \"dna\": 6064,\n      \"loose\": 6065,\n      \"ethan\": 6066,\n      \"supplies\": 6067,\n      \"1898\": 6068,\n      \"gonna\": 6069,\n      \"88\": 6070,\n      \"monster\": 6071,\n      \"##res\": 6072,\n      \"shake\": 6073,\n      \"agents\": 6074,\n      \"frequency\": 6075,\n      \"springs\": 6076,\n      \"dogs\": 6077,\n      \"practices\": 6078,\n      \"61\": 6079,\n      \"gang\": 6080,\n      \"plastic\": 6081,\n      \"easier\": 6082,\n      \"suggests\": 6083,\n      \"gulf\": 6084,\n      \"blade\": 6085,\n      \"exposed\": 6086,\n      \"colors\": 6087,\n      \"industries\": 6088,\n      \"markets\": 6089,\n      \"pan\": 6090,\n      \"nervous\": 6091,\n      \"electoral\": 6092,\n      \"charts\": 6093,\n      \"legislation\": 6094,\n      \"ownership\": 6095,\n      \"##idae\": 6096,\n      \"mac\": 6097,\n      \"appointment\": 6098,\n      \"shield\": 6099,\n      \"copy\": 6100,\n      \"assault\": 6101,\n      \"socialist\": 6102,\n      \"abbey\": 6103,\n      \"monument\": 6104,\n      \"license\": 6105,\n      \"throne\": 6106,\n      \"employment\": 6107,\n      \"jay\": 6108,\n      \"93\": 6109,\n      \"replacement\": 6110,\n      \"charter\": 6111,\n      \"cloud\": 6112,\n      \"powered\": 6113,\n      \"suffering\": 6114,\n      \"accounts\": 6115,\n      \"oak\": 6116,\n      \"connecticut\": 6117,\n      \"strongly\": 6118,\n      \"wright\": 6119,\n      \"colour\": 6120,\n      \"crystal\": 6121,\n      \"13th\": 6122,\n      \"context\": 6123,\n      \"welsh\": 6124,\n      \"networks\": 6125,\n      \"voiced\": 6126,\n      \"gabriel\": 6127,\n      \"jerry\": 6128,\n      \"##cing\": 6129,\n      \"forehead\": 6130,\n      \"mp\": 6131,\n      \"##ens\": 6132,\n      \"manage\": 6133,\n      \"schedule\": 6134,\n      \"totally\": 6135,\n      \"remix\": 6136,\n      \"##ii\": 6137,\n      \"forests\": 6138,\n      \"occupation\": 6139,\n      \"print\": 6140,\n      \"nicholas\": 6141,\n      \"brazilian\": 6142,\n      \"strategic\": 6143,\n      \"vampires\": 6144,\n      \"engineers\": 6145,\n      \"76\": 6146,\n      \"roots\": 6147,\n      \"seek\": 6148,\n      \"correct\": 6149,\n      \"instrumental\": 6150,\n      \"und\": 6151,\n      \"alfred\": 6152,\n      \"backed\": 6153,\n      \"hop\": 6154,\n      \"##des\": 6155,\n      \"stanley\": 6156,\n      \"robinson\": 6157,\n      \"traveled\": 6158,\n      \"wayne\": 6159,\n      \"welcome\": 6160,\n      \"austrian\": 6161,\n      \"achieve\": 6162,\n      \"67\": 6163,\n      \"exit\": 6164,\n      \"rates\": 6165,\n      \"1899\": 6166,\n      \"strip\": 6167,\n      \"whereas\": 6168,\n      \"##cs\": 6169,\n      \"sing\": 6170,\n      \"deeply\": 6171,\n      \"adventure\": 6172,\n      \"bobby\": 6173,\n      \"rick\": 6174,\n      \"jamie\": 6175,\n      \"careful\": 6176,\n      \"components\": 6177,\n      \"cap\": 6178,\n      \"useful\": 6179,\n      \"personality\": 6180,\n      \"knee\": 6181,\n      \"##shi\": 6182,\n      \"pushing\": 6183,\n      \"hosts\": 6184,\n      \"02\": 6185,\n      \"protest\": 6186,\n      \"ca\": 6187,\n      \"ottoman\": 6188,\n      \"symphony\": 6189,\n      \"##sis\": 6190,\n      \"63\": 6191,\n      \"boundary\": 6192,\n      \"1890\": 6193,\n      \"processes\": 6194,\n      \"considering\": 6195,\n      \"considerable\": 6196,\n      \"tons\": 6197,\n      \"##work\": 6198,\n      \"##ft\": 6199,\n      \"##nia\": 6200,\n      \"cooper\": 6201,\n      \"trading\": 6202,\n      \"dear\": 6203,\n      \"conduct\": 6204,\n      \"91\": 6205,\n      \"illegal\": 6206,\n      \"apple\": 6207,\n      \"revolutionary\": 6208,\n      \"holiday\": 6209,\n      \"definition\": 6210,\n      \"harder\": 6211,\n      \"##van\": 6212,\n      \"jacob\": 6213,\n      \"circumstances\": 6214,\n      \"destruction\": 6215,\n      \"##lle\": 6216,\n      \"popularity\": 6217,\n      \"grip\": 6218,\n      \"classified\": 6219,\n      \"liverpool\": 6220,\n      \"donald\": 6221,\n      \"baltimore\": 6222,\n      \"flows\": 6223,\n      \"seeking\": 6224,\n      \"honour\": 6225,\n      \"approval\": 6226,\n      \"92\": 6227,\n      \"mechanical\": 6228,\n      \"till\": 6229,\n      \"happening\": 6230,\n      \"statue\": 6231,\n      \"critic\": 6232,\n      \"increasingly\": 6233,\n      \"immediate\": 6234,\n      \"describe\": 6235,\n      \"commerce\": 6236,\n      \"stare\": 6237,\n      \"##ster\": 6238,\n      \"indonesia\": 6239,\n      \"meat\": 6240,\n      \"rounds\": 6241,\n      \"boats\": 6242,\n      \"baker\": 6243,\n      \"orthodox\": 6244,\n      \"depression\": 6245,\n      \"formally\": 6246,\n      \"worn\": 6247,\n      \"naked\": 6248,\n      \"claire\": 6249,\n      \"muttered\": 6250,\n      \"sentence\": 6251,\n      \"11th\": 6252,\n      \"emily\": 6253,\n      \"document\": 6254,\n      \"77\": 6255,\n      \"criticism\": 6256,\n      \"wished\": 6257,\n      \"vessel\": 6258,\n      \"spiritual\": 6259,\n      \"bent\": 6260,\n      \"virgin\": 6261,\n      \"parker\": 6262,\n      \"minimum\": 6263,\n      \"murray\": 6264,\n      \"lunch\": 6265,\n      \"danny\": 6266,\n      \"printed\": 6267,\n      \"compilation\": 6268,\n      \"keyboards\": 6269,\n      \"false\": 6270,\n      \"blow\": 6271,\n      \"belonged\": 6272,\n      \"68\": 6273,\n      \"raising\": 6274,\n      \"78\": 6275,\n      \"cutting\": 6276,\n      \"##board\": 6277,\n      \"pittsburgh\": 6278,\n      \"##up\": 6279,\n      \"9th\": 6280,\n      \"shadows\": 6281,\n      \"81\": 6282,\n      \"hated\": 6283,\n      \"indigenous\": 6284,\n      \"jon\": 6285,\n      \"15th\": 6286,\n      \"barry\": 6287,\n      \"scholar\": 6288,\n      \"ah\": 6289,\n      \"##zer\": 6290,\n      \"oliver\": 6291,\n      \"##gy\": 6292,\n      \"stick\": 6293,\n      \"susan\": 6294,\n      \"meetings\": 6295,\n      \"attracted\": 6296,\n      \"spell\": 6297,\n      \"romantic\": 6298,\n      \"##ver\": 6299,\n      \"ye\": 6300,\n      \"1895\": 6301,\n      \"photo\": 6302,\n      \"demanded\": 6303,\n      \"customers\": 6304,\n      \"##ac\": 6305,\n      \"1896\": 6306,\n      \"logan\": 6307,\n      \"revival\": 6308,\n      \"keys\": 6309,\n      \"modified\": 6310,\n      \"commanded\": 6311,\n      \"jeans\": 6312,\n      \"##ious\": 6313,\n      \"upset\": 6314,\n      \"raw\": 6315,\n      \"phil\": 6316,\n      \"detective\": 6317,\n      \"hiding\": 6318,\n      \"resident\": 6319,\n      \"vincent\": 6320,\n      \"##bly\": 6321,\n      \"experiences\": 6322,\n      \"diamond\": 6323,\n      \"defeating\": 6324,\n      \"coverage\": 6325,\n      \"lucas\": 6326,\n      \"external\": 6327,\n      \"parks\": 6328,\n      \"franchise\": 6329,\n      \"helen\": 6330,\n      \"bible\": 6331,\n      \"successor\": 6332,\n      \"percussion\": 6333,\n      \"celebrated\": 6334,\n      \"il\": 6335,\n      \"lift\": 6336,\n      \"profile\": 6337,\n      \"clan\": 6338,\n      \"romania\": 6339,\n      \"##ied\": 6340,\n      \"mills\": 6341,\n      \"##su\": 6342,\n      \"nobody\": 6343,\n      \"achievement\": 6344,\n      \"shrugged\": 6345,\n      \"fault\": 6346,\n      \"1897\": 6347,\n      \"rhythm\": 6348,\n      \"initiative\": 6349,\n      \"breakfast\": 6350,\n      \"carbon\": 6351,\n      \"700\": 6352,\n      \"69\": 6353,\n      \"lasted\": 6354,\n      \"violent\": 6355,\n      \"74\": 6356,\n      \"wound\": 6357,\n      \"ken\": 6358,\n      \"killer\": 6359,\n      \"gradually\": 6360,\n      \"filmed\": 6361,\n      \"°c\": 6362,\n      \"dollars\": 6363,\n      \"processing\": 6364,\n      \"94\": 6365,\n      \"remove\": 6366,\n      \"criticized\": 6367,\n      \"guests\": 6368,\n      \"sang\": 6369,\n      \"chemistry\": 6370,\n      \"##vin\": 6371,\n      \"legislature\": 6372,\n      \"disney\": 6373,\n      \"##bridge\": 6374,\n      \"uniform\": 6375,\n      \"escaped\": 6376,\n      \"integrated\": 6377,\n      \"proposal\": 6378,\n      \"purple\": 6379,\n      \"denied\": 6380,\n      \"liquid\": 6381,\n      \"karl\": 6382,\n      \"influential\": 6383,\n      \"morris\": 6384,\n      \"nights\": 6385,\n      \"stones\": 6386,\n      \"intense\": 6387,\n      \"experimental\": 6388,\n      \"twisted\": 6389,\n      \"71\": 6390,\n      \"84\": 6391,\n      \"##ld\": 6392,\n      \"pace\": 6393,\n      \"nazi\": 6394,\n      \"mitchell\": 6395,\n      \"ny\": 6396,\n      \"blind\": 6397,\n      \"reporter\": 6398,\n      \"newspapers\": 6399,\n      \"14th\": 6400,\n      \"centers\": 6401,\n      \"burn\": 6402,\n      \"basin\": 6403,\n      \"forgotten\": 6404,\n      \"surviving\": 6405,\n      \"filed\": 6406,\n      \"collections\": 6407,\n      \"monastery\": 6408,\n      \"losses\": 6409,\n      \"manual\": 6410,\n      \"couch\": 6411,\n      \"description\": 6412,\n      \"appropriate\": 6413,\n      \"merely\": 6414,\n      \"tag\": 6415,\n      \"missions\": 6416,\n      \"sebastian\": 6417,\n      \"restoration\": 6418,\n      \"replacing\": 6419,\n      \"triple\": 6420,\n      \"73\": 6421,\n      \"elder\": 6422,\n      \"julia\": 6423,\n      \"warriors\": 6424,\n      \"benjamin\": 6425,\n      \"julian\": 6426,\n      \"convinced\": 6427,\n      \"stronger\": 6428,\n      \"amazing\": 6429,\n      \"declined\": 6430,\n      \"versus\": 6431,\n      \"merchant\": 6432,\n      \"happens\": 6433,\n      \"output\": 6434,\n      \"finland\": 6435,\n      \"bare\": 6436,\n      \"barbara\": 6437,\n      \"absence\": 6438,\n      \"ignored\": 6439,\n      \"dawn\": 6440,\n      \"injuries\": 6441,\n      \"##port\": 6442,\n      \"producers\": 6443,\n      \"##ram\": 6444,\n      \"82\": 6445,\n      \"luis\": 6446,\n      \"##ities\": 6447,\n      \"kw\": 6448,\n      \"admit\": 6449,\n      \"expensive\": 6450,\n      \"electricity\": 6451,\n      \"nba\": 6452,\n      \"exception\": 6453,\n      \"symbol\": 6454,\n      \"##ving\": 6455,\n      \"ladies\": 6456,\n      \"shower\": 6457,\n      \"sheriff\": 6458,\n      \"characteristics\": 6459,\n      \"##je\": 6460,\n      \"aimed\": 6461,\n      \"button\": 6462,\n      \"ratio\": 6463,\n      \"effectively\": 6464,\n      \"summit\": 6465,\n      \"angle\": 6466,\n      \"jury\": 6467,\n      \"bears\": 6468,\n      \"foster\": 6469,\n      \"vessels\": 6470,\n      \"pants\": 6471,\n      \"executed\": 6472,\n      \"evans\": 6473,\n      \"dozen\": 6474,\n      \"advertising\": 6475,\n      \"kicked\": 6476,\n      \"patrol\": 6477,\n      \"1889\": 6478,\n      \"competitions\": 6479,\n      \"lifetime\": 6480,\n      \"principles\": 6481,\n      \"athletics\": 6482,\n      \"##logy\": 6483,\n      \"birmingham\": 6484,\n      \"sponsored\": 6485,\n      \"89\": 6486,\n      \"rob\": 6487,\n      \"nomination\": 6488,\n      \"1893\": 6489,\n      \"acoustic\": 6490,\n      \"##sm\": 6491,\n      \"creature\": 6492,\n      \"longest\": 6493,\n      \"##tra\": 6494,\n      \"credits\": 6495,\n      \"harbor\": 6496,\n      \"dust\": 6497,\n      \"josh\": 6498,\n      \"##so\": 6499,\n      \"territories\": 6500,\n      \"milk\": 6501,\n      \"infrastructure\": 6502,\n      \"completion\": 6503,\n      \"thailand\": 6504,\n      \"indians\": 6505,\n      \"leon\": 6506,\n      \"archbishop\": 6507,\n      \"##sy\": 6508,\n      \"assist\": 6509,\n      \"pitch\": 6510,\n      \"blake\": 6511,\n      \"arrangement\": 6512,\n      \"girlfriend\": 6513,\n      \"serbian\": 6514,\n      \"operational\": 6515,\n      \"hence\": 6516,\n      \"sad\": 6517,\n      \"scent\": 6518,\n      \"fur\": 6519,\n      \"dj\": 6520,\n      \"sessions\": 6521,\n      \"hp\": 6522,\n      \"refer\": 6523,\n      \"rarely\": 6524,\n      \"##ora\": 6525,\n      \"exists\": 6526,\n      \"1892\": 6527,\n      \"##ten\": 6528,\n      \"scientists\": 6529,\n      \"dirty\": 6530,\n      \"penalty\": 6531,\n      \"burst\": 6532,\n      \"portrait\": 6533,\n      \"seed\": 6534,\n      \"79\": 6535,\n      \"pole\": 6536,\n      \"limits\": 6537,\n      \"rival\": 6538,\n      \"1894\": 6539,\n      \"stable\": 6540,\n      \"alpha\": 6541,\n      \"grave\": 6542,\n      \"constitutional\": 6543,\n      \"alcohol\": 6544,\n      \"arrest\": 6545,\n      \"flower\": 6546,\n      \"mystery\": 6547,\n      \"devil\": 6548,\n      \"architectural\": 6549,\n      \"relationships\": 6550,\n      \"greatly\": 6551,\n      \"habitat\": 6552,\n      \"##istic\": 6553,\n      \"larry\": 6554,\n      \"progressive\": 6555,\n      \"remote\": 6556,\n      \"cotton\": 6557,\n      \"##ics\": 6558,\n      \"##ok\": 6559,\n      \"preserved\": 6560,\n      \"reaches\": 6561,\n      \"##ming\": 6562,\n      \"cited\": 6563,\n      \"86\": 6564,\n      \"vast\": 6565,\n      \"scholarship\": 6566,\n      \"decisions\": 6567,\n      \"cbs\": 6568,\n      \"joy\": 6569,\n      \"teach\": 6570,\n      \"1885\": 6571,\n      \"editions\": 6572,\n      \"knocked\": 6573,\n      \"eve\": 6574,\n      \"searching\": 6575,\n      \"partly\": 6576,\n      \"participation\": 6577,\n      \"gap\": 6578,\n      \"animated\": 6579,\n      \"fate\": 6580,\n      \"excellent\": 6581,\n      \"##ett\": 6582,\n      \"na\": 6583,\n      \"87\": 6584,\n      \"alternate\": 6585,\n      \"saints\": 6586,\n      \"youngest\": 6587,\n      \"##ily\": 6588,\n      \"climbed\": 6589,\n      \"##ita\": 6590,\n      \"##tors\": 6591,\n      \"suggest\": 6592,\n      \"##ct\": 6593,\n      \"discussion\": 6594,\n      \"staying\": 6595,\n      \"choir\": 6596,\n      \"lakes\": 6597,\n      \"jacket\": 6598,\n      \"revenue\": 6599,\n      \"nevertheless\": 6600,\n      \"peaked\": 6601,\n      \"instrument\": 6602,\n      \"wondering\": 6603,\n      \"annually\": 6604,\n      \"managing\": 6605,\n      \"neil\": 6606,\n      \"1891\": 6607,\n      \"signing\": 6608,\n      \"terry\": 6609,\n      \"##ice\": 6610,\n      \"apply\": 6611,\n      \"clinical\": 6612,\n      \"brooklyn\": 6613,\n      \"aim\": 6614,\n      \"catherine\": 6615,\n      \"fuck\": 6616,\n      \"farmers\": 6617,\n      \"figured\": 6618,\n      \"ninth\": 6619,\n      \"pride\": 6620,\n      \"hugh\": 6621,\n      \"evolution\": 6622,\n      \"ordinary\": 6623,\n      \"involvement\": 6624,\n      \"comfortable\": 6625,\n      \"shouted\": 6626,\n      \"tech\": 6627,\n      \"encouraged\": 6628,\n      \"taiwan\": 6629,\n      \"representation\": 6630,\n      \"sharing\": 6631,\n      \"##lia\": 6632,\n      \"##em\": 6633,\n      \"panic\": 6634,\n      \"exact\": 6635,\n      \"cargo\": 6636,\n      \"competing\": 6637,\n      \"fat\": 6638,\n      \"cried\": 6639,\n      \"83\": 6640,\n      \"1920s\": 6641,\n      \"occasions\": 6642,\n      \"pa\": 6643,\n      \"cabin\": 6644,\n      \"borders\": 6645,\n      \"utah\": 6646,\n      \"marcus\": 6647,\n      \"##isation\": 6648,\n      \"badly\": 6649,\n      \"muscles\": 6650,\n      \"##ance\": 6651,\n      \"victorian\": 6652,\n      \"transition\": 6653,\n      \"warner\": 6654,\n      \"bet\": 6655,\n      \"permission\": 6656,\n      \"##rin\": 6657,\n      \"slave\": 6658,\n      \"terrible\": 6659,\n      \"similarly\": 6660,\n      \"shares\": 6661,\n      \"seth\": 6662,\n      \"uefa\": 6663,\n      \"possession\": 6664,\n      \"medals\": 6665,\n      \"benefits\": 6666,\n      \"colleges\": 6667,\n      \"lowered\": 6668,\n      \"perfectly\": 6669,\n      \"mall\": 6670,\n      \"transit\": 6671,\n      \"##ye\": 6672,\n      \"##kar\": 6673,\n      \"publisher\": 6674,\n      \"##ened\": 6675,\n      \"harrison\": 6676,\n      \"deaths\": 6677,\n      \"elevation\": 6678,\n      \"##ae\": 6679,\n      \"asleep\": 6680,\n      \"machines\": 6681,\n      \"sigh\": 6682,\n      \"ash\": 6683,\n      \"hardly\": 6684,\n      \"argument\": 6685,\n      \"occasion\": 6686,\n      \"parent\": 6687,\n      \"leo\": 6688,\n      \"decline\": 6689,\n      \"1888\": 6690,\n      \"contribution\": 6691,\n      \"##ua\": 6692,\n      \"concentration\": 6693,\n      \"1000\": 6694,\n      \"opportunities\": 6695,\n      \"hispanic\": 6696,\n      \"guardian\": 6697,\n      \"extent\": 6698,\n      \"emotions\": 6699,\n      \"hips\": 6700,\n      \"mason\": 6701,\n      \"volumes\": 6702,\n      \"bloody\": 6703,\n      \"controversy\": 6704,\n      \"diameter\": 6705,\n      \"steady\": 6706,\n      \"mistake\": 6707,\n      \"phoenix\": 6708,\n      \"identify\": 6709,\n      \"violin\": 6710,\n      \"##sk\": 6711,\n      \"departure\": 6712,\n      \"richmond\": 6713,\n      \"spin\": 6714,\n      \"funeral\": 6715,\n      \"enemies\": 6716,\n      \"1864\": 6717,\n      \"gear\": 6718,\n      \"literally\": 6719,\n      \"connor\": 6720,\n      \"random\": 6721,\n      \"sergeant\": 6722,\n      \"grab\": 6723,\n      \"confusion\": 6724,\n      \"1865\": 6725,\n      \"transmission\": 6726,\n      \"informed\": 6727,\n      \"op\": 6728,\n      \"leaning\": 6729,\n      \"sacred\": 6730,\n      \"suspended\": 6731,\n      \"thinks\": 6732,\n      \"gates\": 6733,\n      \"portland\": 6734,\n      \"luck\": 6735,\n      \"agencies\": 6736,\n      \"yours\": 6737,\n      \"hull\": 6738,\n      \"expert\": 6739,\n      \"muscle\": 6740,\n      \"layer\": 6741,\n      \"practical\": 6742,\n      \"sculpture\": 6743,\n      \"jerusalem\": 6744,\n      \"latest\": 6745,\n      \"lloyd\": 6746,\n      \"statistics\": 6747,\n      \"deeper\": 6748,\n      \"recommended\": 6749,\n      \"warrior\": 6750,\n      \"arkansas\": 6751,\n      \"mess\": 6752,\n      \"supports\": 6753,\n      \"greg\": 6754,\n      \"eagle\": 6755,\n      \"1880\": 6756,\n      \"recovered\": 6757,\n      \"rated\": 6758,\n      \"concerts\": 6759,\n      \"rushed\": 6760,\n      \"##ano\": 6761,\n      \"stops\": 6762,\n      \"eggs\": 6763,\n      \"files\": 6764,\n      \"premiere\": 6765,\n      \"keith\": 6766,\n      \"##vo\": 6767,\n      \"delhi\": 6768,\n      \"turner\": 6769,\n      \"pit\": 6770,\n      \"affair\": 6771,\n      \"belief\": 6772,\n      \"paint\": 6773,\n      \"##zing\": 6774,\n      \"mate\": 6775,\n      \"##ach\": 6776,\n      \"##ev\": 6777,\n      \"victim\": 6778,\n      \"##ology\": 6779,\n      \"withdrew\": 6780,\n      \"bonus\": 6781,\n      \"styles\": 6782,\n      \"fled\": 6783,\n      \"##ud\": 6784,\n      \"glasgow\": 6785,\n      \"technologies\": 6786,\n      \"funded\": 6787,\n      \"nbc\": 6788,\n      \"adaptation\": 6789,\n      \"##ata\": 6790,\n      \"portrayed\": 6791,\n      \"cooperation\": 6792,\n      \"supporters\": 6793,\n      \"judges\": 6794,\n      \"bernard\": 6795,\n      \"justin\": 6796,\n      \"hallway\": 6797,\n      \"ralph\": 6798,\n      \"##ick\": 6799,\n      \"graduating\": 6800,\n      \"controversial\": 6801,\n      \"distant\": 6802,\n      \"continental\": 6803,\n      \"spider\": 6804,\n      \"bite\": 6805,\n      \"##ho\": 6806,\n      \"recognize\": 6807,\n      \"intention\": 6808,\n      \"mixing\": 6809,\n      \"##ese\": 6810,\n      \"egyptian\": 6811,\n      \"bow\": 6812,\n      \"tourism\": 6813,\n      \"suppose\": 6814,\n      \"claiming\": 6815,\n      \"tiger\": 6816,\n      \"dominated\": 6817,\n      \"participants\": 6818,\n      \"vi\": 6819,\n      \"##ru\": 6820,\n      \"nurse\": 6821,\n      \"partially\": 6822,\n      \"tape\": 6823,\n      \"##rum\": 6824,\n      \"psychology\": 6825,\n      \"##rn\": 6826,\n      \"essential\": 6827,\n      \"touring\": 6828,\n      \"duo\": 6829,\n      \"voting\": 6830,\n      \"civilian\": 6831,\n      \"emotional\": 6832,\n      \"channels\": 6833,\n      \"##king\": 6834,\n      \"apparent\": 6835,\n      \"hebrew\": 6836,\n      \"1887\": 6837,\n      \"tommy\": 6838,\n      \"carrier\": 6839,\n      \"intersection\": 6840,\n      \"beast\": 6841,\n      \"hudson\": 6842,\n      \"##gar\": 6843,\n      \"##zo\": 6844,\n      \"lab\": 6845,\n      \"nova\": 6846,\n      \"bench\": 6847,\n      \"discuss\": 6848,\n      \"costa\": 6849,\n      \"##ered\": 6850,\n      \"detailed\": 6851,\n      \"behalf\": 6852,\n      \"drivers\": 6853,\n      \"unfortunately\": 6854,\n      \"obtain\": 6855,\n      \"##lis\": 6856,\n      \"rocky\": 6857,\n      \"##dae\": 6858,\n      \"siege\": 6859,\n      \"friendship\": 6860,\n      \"honey\": 6861,\n      \"##rian\": 6862,\n      \"1861\": 6863,\n      \"amy\": 6864,\n      \"hang\": 6865,\n      \"posted\": 6866,\n      \"governments\": 6867,\n      \"collins\": 6868,\n      \"respond\": 6869,\n      \"wildlife\": 6870,\n      \"preferred\": 6871,\n      \"operator\": 6872,\n      \"##po\": 6873,\n      \"laura\": 6874,\n      \"pregnant\": 6875,\n      \"videos\": 6876,\n      \"dennis\": 6877,\n      \"suspected\": 6878,\n      \"boots\": 6879,\n      \"instantly\": 6880,\n      \"weird\": 6881,\n      \"automatic\": 6882,\n      \"businessman\": 6883,\n      \"alleged\": 6884,\n      \"placing\": 6885,\n      \"throwing\": 6886,\n      \"ph\": 6887,\n      \"mood\": 6888,\n      \"1862\": 6889,\n      \"perry\": 6890,\n      \"venue\": 6891,\n      \"jet\": 6892,\n      \"remainder\": 6893,\n      \"##lli\": 6894,\n      \"##ci\": 6895,\n      \"passion\": 6896,\n      \"biological\": 6897,\n      \"boyfriend\": 6898,\n      \"1863\": 6899,\n      \"dirt\": 6900,\n      \"buffalo\": 6901,\n      \"ron\": 6902,\n      \"segment\": 6903,\n      \"fa\": 6904,\n      \"abuse\": 6905,\n      \"##era\": 6906,\n      \"genre\": 6907,\n      \"thrown\": 6908,\n      \"stroke\": 6909,\n      \"colored\": 6910,\n      \"stress\": 6911,\n      \"exercise\": 6912,\n      \"displayed\": 6913,\n      \"##gen\": 6914,\n      \"struggled\": 6915,\n      \"##tti\": 6916,\n      \"abroad\": 6917,\n      \"dramatic\": 6918,\n      \"wonderful\": 6919,\n      \"thereafter\": 6920,\n      \"madrid\": 6921,\n      \"component\": 6922,\n      \"widespread\": 6923,\n      \"##sed\": 6924,\n      \"tale\": 6925,\n      \"citizen\": 6926,\n      \"todd\": 6927,\n      \"monday\": 6928,\n      \"1886\": 6929,\n      \"vancouver\": 6930,\n      \"overseas\": 6931,\n      \"forcing\": 6932,\n      \"crying\": 6933,\n      \"descent\": 6934,\n      \"##ris\": 6935,\n      \"discussed\": 6936,\n      \"substantial\": 6937,\n      \"ranks\": 6938,\n      \"regime\": 6939,\n      \"1870\": 6940,\n      \"provinces\": 6941,\n      \"switch\": 6942,\n      \"drum\": 6943,\n      \"zane\": 6944,\n      \"ted\": 6945,\n      \"tribes\": 6946,\n      \"proof\": 6947,\n      \"lp\": 6948,\n      \"cream\": 6949,\n      \"researchers\": 6950,\n      \"volunteer\": 6951,\n      \"manor\": 6952,\n      \"silk\": 6953,\n      \"milan\": 6954,\n      \"donated\": 6955,\n      \"allies\": 6956,\n      \"venture\": 6957,\n      \"principle\": 6958,\n      \"delivery\": 6959,\n      \"enterprise\": 6960,\n      \"##ves\": 6961,\n      \"##ans\": 6962,\n      \"bars\": 6963,\n      \"traditionally\": 6964,\n      \"witch\": 6965,\n      \"reminded\": 6966,\n      \"copper\": 6967,\n      \"##uk\": 6968,\n      \"pete\": 6969,\n      \"inter\": 6970,\n      \"links\": 6971,\n      \"colin\": 6972,\n      \"grinned\": 6973,\n      \"elsewhere\": 6974,\n      \"competitive\": 6975,\n      \"frequent\": 6976,\n      \"##oy\": 6977,\n      \"scream\": 6978,\n      \"##hu\": 6979,\n      \"tension\": 6980,\n      \"texts\": 6981,\n      \"submarine\": 6982,\n      \"finnish\": 6983,\n      \"defending\": 6984,\n      \"defend\": 6985,\n      \"pat\": 6986,\n      \"detail\": 6987,\n      \"1884\": 6988,\n      \"affiliated\": 6989,\n      \"stuart\": 6990,\n      \"themes\": 6991,\n      \"villa\": 6992,\n      \"periods\": 6993,\n      \"tool\": 6994,\n      \"belgian\": 6995,\n      \"ruling\": 6996,\n      \"crimes\": 6997,\n      \"answers\": 6998,\n      \"folded\": 6999,\n      \"licensed\": 7000,\n      \"resort\": 7001,\n      \"demolished\": 7002,\n      \"hans\": 7003,\n      \"lucy\": 7004,\n      \"1881\": 7005,\n      \"lion\": 7006,\n      \"traded\": 7007,\n      \"photographs\": 7008,\n      \"writes\": 7009,\n      \"craig\": 7010,\n      \"##fa\": 7011,\n      \"trials\": 7012,\n      \"generated\": 7013,\n      \"beth\": 7014,\n      \"noble\": 7015,\n      \"debt\": 7016,\n      \"percentage\": 7017,\n      \"yorkshire\": 7018,\n      \"erected\": 7019,\n      \"ss\": 7020,\n      \"viewed\": 7021,\n      \"grades\": 7022,\n      \"confidence\": 7023,\n      \"ceased\": 7024,\n      \"islam\": 7025,\n      \"telephone\": 7026,\n      \"retail\": 7027,\n      \"##ible\": 7028,\n      \"chile\": 7029,\n      \"m²\": 7030,\n      \"roberts\": 7031,\n      \"sixteen\": 7032,\n      \"##ich\": 7033,\n      \"commented\": 7034,\n      \"hampshire\": 7035,\n      \"innocent\": 7036,\n      \"dual\": 7037,\n      \"pounds\": 7038,\n      \"checked\": 7039,\n      \"regulations\": 7040,\n      \"afghanistan\": 7041,\n      \"sung\": 7042,\n      \"rico\": 7043,\n      \"liberty\": 7044,\n      \"assets\": 7045,\n      \"bigger\": 7046,\n      \"options\": 7047,\n      \"angels\": 7048,\n      \"relegated\": 7049,\n      \"tribute\": 7050,\n      \"wells\": 7051,\n      \"attending\": 7052,\n      \"leaf\": 7053,\n      \"##yan\": 7054,\n      \"butler\": 7055,\n      \"romanian\": 7056,\n      \"forum\": 7057,\n      \"monthly\": 7058,\n      \"lisa\": 7059,\n      \"patterns\": 7060,\n      \"gmina\": 7061,\n      \"##tory\": 7062,\n      \"madison\": 7063,\n      \"hurricane\": 7064,\n      \"rev\": 7065,\n      \"##ians\": 7066,\n      \"bristol\": 7067,\n      \"##ula\": 7068,\n      \"elite\": 7069,\n      \"valuable\": 7070,\n      \"disaster\": 7071,\n      \"democracy\": 7072,\n      \"awareness\": 7073,\n      \"germans\": 7074,\n      \"freyja\": 7075,\n      \"##ins\": 7076,\n      \"loop\": 7077,\n      \"absolutely\": 7078,\n      \"paying\": 7079,\n      \"populations\": 7080,\n      \"maine\": 7081,\n      \"sole\": 7082,\n      \"prayer\": 7083,\n      \"spencer\": 7084,\n      \"releases\": 7085,\n      \"doorway\": 7086,\n      \"bull\": 7087,\n      \"##ani\": 7088,\n      \"lover\": 7089,\n      \"midnight\": 7090,\n      \"conclusion\": 7091,\n      \"##sson\": 7092,\n      \"thirteen\": 7093,\n      \"lily\": 7094,\n      \"mediterranean\": 7095,\n      \"##lt\": 7096,\n      \"nhl\": 7097,\n      \"proud\": 7098,\n      \"sample\": 7099,\n      \"##hill\": 7100,\n      \"drummer\": 7101,\n      \"guinea\": 7102,\n      \"##ova\": 7103,\n      \"murphy\": 7104,\n      \"climb\": 7105,\n      \"##ston\": 7106,\n      \"instant\": 7107,\n      \"attributed\": 7108,\n      \"horn\": 7109,\n      \"ain\": 7110,\n      \"railways\": 7111,\n      \"steven\": 7112,\n      \"##ao\": 7113,\n      \"autumn\": 7114,\n      \"ferry\": 7115,\n      \"opponent\": 7116,\n      \"root\": 7117,\n      \"traveling\": 7118,\n      \"secured\": 7119,\n      \"corridor\": 7120,\n      \"stretched\": 7121,\n      \"tales\": 7122,\n      \"sheet\": 7123,\n      \"trinity\": 7124,\n      \"cattle\": 7125,\n      \"helps\": 7126,\n      \"indicates\": 7127,\n      \"manhattan\": 7128,\n      \"murdered\": 7129,\n      \"fitted\": 7130,\n      \"1882\": 7131,\n      \"gentle\": 7132,\n      \"grandmother\": 7133,\n      \"mines\": 7134,\n      \"shocked\": 7135,\n      \"vegas\": 7136,\n      \"produces\": 7137,\n      \"##light\": 7138,\n      \"caribbean\": 7139,\n      \"##ou\": 7140,\n      \"belong\": 7141,\n      \"continuous\": 7142,\n      \"desperate\": 7143,\n      \"drunk\": 7144,\n      \"historically\": 7145,\n      \"trio\": 7146,\n      \"waved\": 7147,\n      \"raf\": 7148,\n      \"dealing\": 7149,\n      \"nathan\": 7150,\n      \"bat\": 7151,\n      \"murmured\": 7152,\n      \"interrupted\": 7153,\n      \"residing\": 7154,\n      \"scientist\": 7155,\n      \"pioneer\": 7156,\n      \"harold\": 7157,\n      \"aaron\": 7158,\n      \"##net\": 7159,\n      \"delta\": 7160,\n      \"attempting\": 7161,\n      \"minority\": 7162,\n      \"mini\": 7163,\n      \"believes\": 7164,\n      \"chorus\": 7165,\n      \"tend\": 7166,\n      \"lots\": 7167,\n      \"eyed\": 7168,\n      \"indoor\": 7169,\n      \"load\": 7170,\n      \"shots\": 7171,\n      \"updated\": 7172,\n      \"jail\": 7173,\n      \"##llo\": 7174,\n      \"concerning\": 7175,\n      \"connecting\": 7176,\n      \"wealth\": 7177,\n      \"##ved\": 7178,\n      \"slaves\": 7179,\n      \"arrive\": 7180,\n      \"rangers\": 7181,\n      \"sufficient\": 7182,\n      \"rebuilt\": 7183,\n      \"##wick\": 7184,\n      \"cardinal\": 7185,\n      \"flood\": 7186,\n      \"muhammad\": 7187,\n      \"whenever\": 7188,\n      \"relation\": 7189,\n      \"runners\": 7190,\n      \"moral\": 7191,\n      \"repair\": 7192,\n      \"viewers\": 7193,\n      \"arriving\": 7194,\n      \"revenge\": 7195,\n      \"punk\": 7196,\n      \"assisted\": 7197,\n      \"bath\": 7198,\n      \"fairly\": 7199,\n      \"breathe\": 7200,\n      \"lists\": 7201,\n      \"innings\": 7202,\n      \"illustrated\": 7203,\n      \"whisper\": 7204,\n      \"nearest\": 7205,\n      \"voters\": 7206,\n      \"clinton\": 7207,\n      \"ties\": 7208,\n      \"ultimate\": 7209,\n      \"screamed\": 7210,\n      \"beijing\": 7211,\n      \"lions\": 7212,\n      \"andre\": 7213,\n      \"fictional\": 7214,\n      \"gathering\": 7215,\n      \"comfort\": 7216,\n      \"radar\": 7217,\n      \"suitable\": 7218,\n      \"dismissed\": 7219,\n      \"hms\": 7220,\n      \"ban\": 7221,\n      \"pine\": 7222,\n      \"wrist\": 7223,\n      \"atmosphere\": 7224,\n      \"voivodeship\": 7225,\n      \"bid\": 7226,\n      \"timber\": 7227,\n      \"##ned\": 7228,\n      \"##nan\": 7229,\n      \"giants\": 7230,\n      \"##ane\": 7231,\n      \"cameron\": 7232,\n      \"recovery\": 7233,\n      \"uss\": 7234,\n      \"identical\": 7235,\n      \"categories\": 7236,\n      \"switched\": 7237,\n      \"serbia\": 7238,\n      \"laughter\": 7239,\n      \"noah\": 7240,\n      \"ensemble\": 7241,\n      \"therapy\": 7242,\n      \"peoples\": 7243,\n      \"touching\": 7244,\n      \"##off\": 7245,\n      \"locally\": 7246,\n      \"pearl\": 7247,\n      \"platforms\": 7248,\n      \"everywhere\": 7249,\n      \"ballet\": 7250,\n      \"tables\": 7251,\n      \"lanka\": 7252,\n      \"herbert\": 7253,\n      \"outdoor\": 7254,\n      \"toured\": 7255,\n      \"derek\": 7256,\n      \"1883\": 7257,\n      \"spaces\": 7258,\n      \"contested\": 7259,\n      \"swept\": 7260,\n      \"1878\": 7261,\n      \"exclusive\": 7262,\n      \"slight\": 7263,\n      \"connections\": 7264,\n      \"##dra\": 7265,\n      \"winds\": 7266,\n      \"prisoner\": 7267,\n      \"collective\": 7268,\n      \"bangladesh\": 7269,\n      \"tube\": 7270,\n      \"publicly\": 7271,\n      \"wealthy\": 7272,\n      \"thai\": 7273,\n      \"##ys\": 7274,\n      \"isolated\": 7275,\n      \"select\": 7276,\n      \"##ric\": 7277,\n      \"insisted\": 7278,\n      \"pen\": 7279,\n      \"fortune\": 7280,\n      \"ticket\": 7281,\n      \"spotted\": 7282,\n      \"reportedly\": 7283,\n      \"animation\": 7284,\n      \"enforcement\": 7285,\n      \"tanks\": 7286,\n      \"110\": 7287,\n      \"decides\": 7288,\n      \"wider\": 7289,\n      \"lowest\": 7290,\n      \"owen\": 7291,\n      \"##time\": 7292,\n      \"nod\": 7293,\n      \"hitting\": 7294,\n      \"##hn\": 7295,\n      \"gregory\": 7296,\n      \"furthermore\": 7297,\n      \"magazines\": 7298,\n      \"fighters\": 7299,\n      \"solutions\": 7300,\n      \"##ery\": 7301,\n      \"pointing\": 7302,\n      \"requested\": 7303,\n      \"peru\": 7304,\n      \"reed\": 7305,\n      \"chancellor\": 7306,\n      \"knights\": 7307,\n      \"mask\": 7308,\n      \"worker\": 7309,\n      \"eldest\": 7310,\n      \"flames\": 7311,\n      \"reduction\": 7312,\n      \"1860\": 7313,\n      \"volunteers\": 7314,\n      \"##tis\": 7315,\n      \"reporting\": 7316,\n      \"##hl\": 7317,\n      \"wire\": 7318,\n      \"advisory\": 7319,\n      \"endemic\": 7320,\n      \"origins\": 7321,\n      \"settlers\": 7322,\n      \"pursue\": 7323,\n      \"knock\": 7324,\n      \"consumer\": 7325,\n      \"1876\": 7326,\n      \"eu\": 7327,\n      \"compound\": 7328,\n      \"creatures\": 7329,\n      \"mansion\": 7330,\n      \"sentenced\": 7331,\n      \"ivan\": 7332,\n      \"deployed\": 7333,\n      \"guitars\": 7334,\n      \"frowned\": 7335,\n      \"involves\": 7336,\n      \"mechanism\": 7337,\n      \"kilometers\": 7338,\n      \"perspective\": 7339,\n      \"shops\": 7340,\n      \"maps\": 7341,\n      \"terminus\": 7342,\n      \"duncan\": 7343,\n      \"alien\": 7344,\n      \"fist\": 7345,\n      \"bridges\": 7346,\n      \"##pers\": 7347,\n      \"heroes\": 7348,\n      \"fed\": 7349,\n      \"derby\": 7350,\n      \"swallowed\": 7351,\n      \"##ros\": 7352,\n      \"patent\": 7353,\n      \"sara\": 7354,\n      \"illness\": 7355,\n      \"characterized\": 7356,\n      \"adventures\": 7357,\n      \"slide\": 7358,\n      \"hawaii\": 7359,\n      \"jurisdiction\": 7360,\n      \"##op\": 7361,\n      \"organised\": 7362,\n      \"##side\": 7363,\n      \"adelaide\": 7364,\n      \"walks\": 7365,\n      \"biology\": 7366,\n      \"se\": 7367,\n      \"##ties\": 7368,\n      \"rogers\": 7369,\n      \"swing\": 7370,\n      \"tightly\": 7371,\n      \"boundaries\": 7372,\n      \"##rie\": 7373,\n      \"prepare\": 7374,\n      \"implementation\": 7375,\n      \"stolen\": 7376,\n      \"##sha\": 7377,\n      \"certified\": 7378,\n      \"colombia\": 7379,\n      \"edwards\": 7380,\n      \"garage\": 7381,\n      \"##mm\": 7382,\n      \"recalled\": 7383,\n      \"##ball\": 7384,\n      \"rage\": 7385,\n      \"harm\": 7386,\n      \"nigeria\": 7387,\n      \"breast\": 7388,\n      \"##ren\": 7389,\n      \"furniture\": 7390,\n      \"pupils\": 7391,\n      \"settle\": 7392,\n      \"##lus\": 7393,\n      \"cuba\": 7394,\n      \"balls\": 7395,\n      \"client\": 7396,\n      \"alaska\": 7397,\n      \"21st\": 7398,\n      \"linear\": 7399,\n      \"thrust\": 7400,\n      \"celebration\": 7401,\n      \"latino\": 7402,\n      \"genetic\": 7403,\n      \"terror\": 7404,\n      \"##cia\": 7405,\n      \"##ening\": 7406,\n      \"lightning\": 7407,\n      \"fee\": 7408,\n      \"witness\": 7409,\n      \"lodge\": 7410,\n      \"establishing\": 7411,\n      \"skull\": 7412,\n      \"##ique\": 7413,\n      \"earning\": 7414,\n      \"hood\": 7415,\n      \"##ei\": 7416,\n      \"rebellion\": 7417,\n      \"wang\": 7418,\n      \"sporting\": 7419,\n      \"warned\": 7420,\n      \"missile\": 7421,\n      \"devoted\": 7422,\n      \"activist\": 7423,\n      \"porch\": 7424,\n      \"worship\": 7425,\n      \"fourteen\": 7426,\n      \"package\": 7427,\n      \"1871\": 7428,\n      \"decorated\": 7429,\n      \"##shire\": 7430,\n      \"housed\": 7431,\n      \"##ock\": 7432,\n      \"chess\": 7433,\n      \"sailed\": 7434,\n      \"doctors\": 7435,\n      \"oscar\": 7436,\n      \"joan\": 7437,\n      \"treat\": 7438,\n      \"garcia\": 7439,\n      \"harbour\": 7440,\n      \"jeremy\": 7441,\n      \"##ire\": 7442,\n      \"traditions\": 7443,\n      \"dominant\": 7444,\n      \"jacques\": 7445,\n      \"##gon\": 7446,\n      \"##wan\": 7447,\n      \"relocated\": 7448,\n      \"1879\": 7449,\n      \"amendment\": 7450,\n      \"sized\": 7451,\n      \"companion\": 7452,\n      \"simultaneously\": 7453,\n      \"volleyball\": 7454,\n      \"spun\": 7455,\n      \"acre\": 7456,\n      \"increases\": 7457,\n      \"stopping\": 7458,\n      \"loves\": 7459,\n      \"belongs\": 7460,\n      \"affect\": 7461,\n      \"drafted\": 7462,\n      \"tossed\": 7463,\n      \"scout\": 7464,\n      \"battles\": 7465,\n      \"1875\": 7466,\n      \"filming\": 7467,\n      \"shoved\": 7468,\n      \"munich\": 7469,\n      \"tenure\": 7470,\n      \"vertical\": 7471,\n      \"romance\": 7472,\n      \"pc\": 7473,\n      \"##cher\": 7474,\n      \"argue\": 7475,\n      \"##ical\": 7476,\n      \"craft\": 7477,\n      \"ranging\": 7478,\n      \"www\": 7479,\n      \"opens\": 7480,\n      \"honest\": 7481,\n      \"tyler\": 7482,\n      \"yesterday\": 7483,\n      \"virtual\": 7484,\n      \"##let\": 7485,\n      \"muslims\": 7486,\n      \"reveal\": 7487,\n      \"snake\": 7488,\n      \"immigrants\": 7489,\n      \"radical\": 7490,\n      \"screaming\": 7491,\n      \"speakers\": 7492,\n      \"firing\": 7493,\n      \"saving\": 7494,\n      \"belonging\": 7495,\n      \"ease\": 7496,\n      \"lighting\": 7497,\n      \"prefecture\": 7498,\n      \"blame\": 7499,\n      \"farmer\": 7500,\n      \"hungry\": 7501,\n      \"grows\": 7502,\n      \"rubbed\": 7503,\n      \"beam\": 7504,\n      \"sur\": 7505,\n      \"subsidiary\": 7506,\n      \"##cha\": 7507,\n      \"armenian\": 7508,\n      \"sao\": 7509,\n      \"dropping\": 7510,\n      \"conventional\": 7511,\n      \"##fer\": 7512,\n      \"microsoft\": 7513,\n      \"reply\": 7514,\n      \"qualify\": 7515,\n      \"spots\": 7516,\n      \"1867\": 7517,\n      \"sweat\": 7518,\n      \"festivals\": 7519,\n      \"##ken\": 7520,\n      \"immigration\": 7521,\n      \"physician\": 7522,\n      \"discover\": 7523,\n      \"exposure\": 7524,\n      \"sandy\": 7525,\n      \"explanation\": 7526,\n      \"isaac\": 7527,\n      \"implemented\": 7528,\n      \"##fish\": 7529,\n      \"hart\": 7530,\n      \"initiated\": 7531,\n      \"connect\": 7532,\n      \"stakes\": 7533,\n      \"presents\": 7534,\n      \"heights\": 7535,\n      \"householder\": 7536,\n      \"pleased\": 7537,\n      \"tourist\": 7538,\n      \"regardless\": 7539,\n      \"slip\": 7540,\n      \"closest\": 7541,\n      \"##ction\": 7542,\n      \"surely\": 7543,\n      \"sultan\": 7544,\n      \"brings\": 7545,\n      \"riley\": 7546,\n      \"preparation\": 7547,\n      \"aboard\": 7548,\n      \"slammed\": 7549,\n      \"baptist\": 7550,\n      \"experiment\": 7551,\n      \"ongoing\": 7552,\n      \"interstate\": 7553,\n      \"organic\": 7554,\n      \"playoffs\": 7555,\n      \"##ika\": 7556,\n      \"1877\": 7557,\n      \"130\": 7558,\n      \"##tar\": 7559,\n      \"hindu\": 7560,\n      \"error\": 7561,\n      \"tours\": 7562,\n      \"tier\": 7563,\n      \"plenty\": 7564,\n      \"arrangements\": 7565,\n      \"talks\": 7566,\n      \"trapped\": 7567,\n      \"excited\": 7568,\n      \"sank\": 7569,\n      \"ho\": 7570,\n      \"athens\": 7571,\n      \"1872\": 7572,\n      \"denver\": 7573,\n      \"welfare\": 7574,\n      \"suburb\": 7575,\n      \"athletes\": 7576,\n      \"trick\": 7577,\n      \"diverse\": 7578,\n      \"belly\": 7579,\n      \"exclusively\": 7580,\n      \"yelled\": 7581,\n      \"1868\": 7582,\n      \"##med\": 7583,\n      \"conversion\": 7584,\n      \"##ette\": 7585,\n      \"1874\": 7586,\n      \"internationally\": 7587,\n      \"computers\": 7588,\n      \"conductor\": 7589,\n      \"abilities\": 7590,\n      \"sensitive\": 7591,\n      \"hello\": 7592,\n      \"dispute\": 7593,\n      \"measured\": 7594,\n      \"globe\": 7595,\n      \"rocket\": 7596,\n      \"prices\": 7597,\n      \"amsterdam\": 7598,\n      \"flights\": 7599,\n      \"tigers\": 7600,\n      \"inn\": 7601,\n      \"municipalities\": 7602,\n      \"emotion\": 7603,\n      \"references\": 7604,\n      \"3d\": 7605,\n      \"##mus\": 7606,\n      \"explains\": 7607,\n      \"airlines\": 7608,\n      \"manufactured\": 7609,\n      \"pm\": 7610,\n      \"archaeological\": 7611,\n      \"1873\": 7612,\n      \"interpretation\": 7613,\n      \"devon\": 7614,\n      \"comment\": 7615,\n      \"##ites\": 7616,\n      \"settlements\": 7617,\n      \"kissing\": 7618,\n      \"absolute\": 7619,\n      \"improvement\": 7620,\n      \"suite\": 7621,\n      \"impressed\": 7622,\n      \"barcelona\": 7623,\n      \"sullivan\": 7624,\n      \"jefferson\": 7625,\n      \"towers\": 7626,\n      \"jesse\": 7627,\n      \"julie\": 7628,\n      \"##tin\": 7629,\n      \"##lu\": 7630,\n      \"grandson\": 7631,\n      \"hi\": 7632,\n      \"gauge\": 7633,\n      \"regard\": 7634,\n      \"rings\": 7635,\n      \"interviews\": 7636,\n      \"trace\": 7637,\n      \"raymond\": 7638,\n      \"thumb\": 7639,\n      \"departments\": 7640,\n      \"burns\": 7641,\n      \"serial\": 7642,\n      \"bulgarian\": 7643,\n      \"scores\": 7644,\n      \"demonstrated\": 7645,\n      \"##ix\": 7646,\n      \"1866\": 7647,\n      \"kyle\": 7648,\n      \"alberta\": 7649,\n      \"underneath\": 7650,\n      \"romanized\": 7651,\n      \"##ward\": 7652,\n      \"relieved\": 7653,\n      \"acquisition\": 7654,\n      \"phrase\": 7655,\n      \"cliff\": 7656,\n      \"reveals\": 7657,\n      \"han\": 7658,\n      \"cuts\": 7659,\n      \"merger\": 7660,\n      \"custom\": 7661,\n      \"##dar\": 7662,\n      \"nee\": 7663,\n      \"gilbert\": 7664,\n      \"graduation\": 7665,\n      \"##nts\": 7666,\n      \"assessment\": 7667,\n      \"cafe\": 7668,\n      \"difficulty\": 7669,\n      \"demands\": 7670,\n      \"swung\": 7671,\n      \"democrat\": 7672,\n      \"jennifer\": 7673,\n      \"commons\": 7674,\n      \"1940s\": 7675,\n      \"grove\": 7676,\n      \"##yo\": 7677,\n      \"completing\": 7678,\n      \"focuses\": 7679,\n      \"sum\": 7680,\n      \"substitute\": 7681,\n      \"bearing\": 7682,\n      \"stretch\": 7683,\n      \"reception\": 7684,\n      \"##py\": 7685,\n      \"reflected\": 7686,\n      \"essentially\": 7687,\n      \"destination\": 7688,\n      \"pairs\": 7689,\n      \"##ched\": 7690,\n      \"survival\": 7691,\n      \"resource\": 7692,\n      \"##bach\": 7693,\n      \"promoting\": 7694,\n      \"doubles\": 7695,\n      \"messages\": 7696,\n      \"tear\": 7697,\n      \"##down\": 7698,\n      \"##fully\": 7699,\n      \"parade\": 7700,\n      \"florence\": 7701,\n      \"harvey\": 7702,\n      \"incumbent\": 7703,\n      \"partial\": 7704,\n      \"framework\": 7705,\n      \"900\": 7706,\n      \"pedro\": 7707,\n      \"frozen\": 7708,\n      \"procedure\": 7709,\n      \"olivia\": 7710,\n      \"controls\": 7711,\n      \"##mic\": 7712,\n      \"shelter\": 7713,\n      \"personally\": 7714,\n      \"temperatures\": 7715,\n      \"##od\": 7716,\n      \"brisbane\": 7717,\n      \"tested\": 7718,\n      \"sits\": 7719,\n      \"marble\": 7720,\n      \"comprehensive\": 7721,\n      \"oxygen\": 7722,\n      \"leonard\": 7723,\n      \"##kov\": 7724,\n      \"inaugural\": 7725,\n      \"iranian\": 7726,\n      \"referring\": 7727,\n      \"quarters\": 7728,\n      \"attitude\": 7729,\n      \"##ivity\": 7730,\n      \"mainstream\": 7731,\n      \"lined\": 7732,\n      \"mars\": 7733,\n      \"dakota\": 7734,\n      \"norfolk\": 7735,\n      \"unsuccessful\": 7736,\n      \"##°\": 7737,\n      \"explosion\": 7738,\n      \"helicopter\": 7739,\n      \"congressional\": 7740,\n      \"##sing\": 7741,\n      \"inspector\": 7742,\n      \"bitch\": 7743,\n      \"seal\": 7744,\n      \"departed\": 7745,\n      \"divine\": 7746,\n      \"##ters\": 7747,\n      \"coaching\": 7748,\n      \"examination\": 7749,\n      \"punishment\": 7750,\n      \"manufacturer\": 7751,\n      \"sink\": 7752,\n      \"columns\": 7753,\n      \"unincorporated\": 7754,\n      \"signals\": 7755,\n      \"nevada\": 7756,\n      \"squeezed\": 7757,\n      \"dylan\": 7758,\n      \"dining\": 7759,\n      \"photos\": 7760,\n      \"martial\": 7761,\n      \"manuel\": 7762,\n      \"eighteen\": 7763,\n      \"elevator\": 7764,\n      \"brushed\": 7765,\n      \"plates\": 7766,\n      \"ministers\": 7767,\n      \"ivy\": 7768,\n      \"congregation\": 7769,\n      \"##len\": 7770,\n      \"slept\": 7771,\n      \"specialized\": 7772,\n      \"taxes\": 7773,\n      \"curve\": 7774,\n      \"restricted\": 7775,\n      \"negotiations\": 7776,\n      \"likes\": 7777,\n      \"statistical\": 7778,\n      \"arnold\": 7779,\n      \"inspiration\": 7780,\n      \"execution\": 7781,\n      \"bold\": 7782,\n      \"intermediate\": 7783,\n      \"significance\": 7784,\n      \"margin\": 7785,\n      \"ruler\": 7786,\n      \"wheels\": 7787,\n      \"gothic\": 7788,\n      \"intellectual\": 7789,\n      \"dependent\": 7790,\n      \"listened\": 7791,\n      \"eligible\": 7792,\n      \"buses\": 7793,\n      \"widow\": 7794,\n      \"syria\": 7795,\n      \"earn\": 7796,\n      \"cincinnati\": 7797,\n      \"collapsed\": 7798,\n      \"recipient\": 7799,\n      \"secrets\": 7800,\n      \"accessible\": 7801,\n      \"philippine\": 7802,\n      \"maritime\": 7803,\n      \"goddess\": 7804,\n      \"clerk\": 7805,\n      \"surrender\": 7806,\n      \"breaks\": 7807,\n      \"playoff\": 7808,\n      \"database\": 7809,\n      \"##ified\": 7810,\n      \"##lon\": 7811,\n      \"ideal\": 7812,\n      \"beetle\": 7813,\n      \"aspect\": 7814,\n      \"soap\": 7815,\n      \"regulation\": 7816,\n      \"strings\": 7817,\n      \"expand\": 7818,\n      \"anglo\": 7819,\n      \"shorter\": 7820,\n      \"crosses\": 7821,\n      \"retreat\": 7822,\n      \"tough\": 7823,\n      \"coins\": 7824,\n      \"wallace\": 7825,\n      \"directions\": 7826,\n      \"pressing\": 7827,\n      \"##oon\": 7828,\n      \"shipping\": 7829,\n      \"locomotives\": 7830,\n      \"comparison\": 7831,\n      \"topics\": 7832,\n      \"nephew\": 7833,\n      \"##mes\": 7834,\n      \"distinction\": 7835,\n      \"honors\": 7836,\n      \"travelled\": 7837,\n      \"sierra\": 7838,\n      \"ibn\": 7839,\n      \"##over\": 7840,\n      \"fortress\": 7841,\n      \"sa\": 7842,\n      \"recognised\": 7843,\n      \"carved\": 7844,\n      \"1869\": 7845,\n      \"clients\": 7846,\n      \"##dan\": 7847,\n      \"intent\": 7848,\n      \"##mar\": 7849,\n      \"coaches\": 7850,\n      \"describing\": 7851,\n      \"bread\": 7852,\n      \"##ington\": 7853,\n      \"beaten\": 7854,\n      \"northwestern\": 7855,\n      \"##ona\": 7856,\n      \"merit\": 7857,\n      \"youtube\": 7858,\n      \"collapse\": 7859,\n      \"challenges\": 7860,\n      \"em\": 7861,\n      \"historians\": 7862,\n      \"objective\": 7863,\n      \"submitted\": 7864,\n      \"virus\": 7865,\n      \"attacking\": 7866,\n      \"drake\": 7867,\n      \"assume\": 7868,\n      \"##ere\": 7869,\n      \"diseases\": 7870,\n      \"marc\": 7871,\n      \"stem\": 7872,\n      \"leeds\": 7873,\n      \"##cus\": 7874,\n      \"##ab\": 7875,\n      \"farming\": 7876,\n      \"glasses\": 7877,\n      \"##lock\": 7878,\n      \"visits\": 7879,\n      \"nowhere\": 7880,\n      \"fellowship\": 7881,\n      \"relevant\": 7882,\n      \"carries\": 7883,\n      \"restaurants\": 7884,\n      \"experiments\": 7885,\n      \"101\": 7886,\n      \"constantly\": 7887,\n      \"bases\": 7888,\n      \"targets\": 7889,\n      \"shah\": 7890,\n      \"tenth\": 7891,\n      \"opponents\": 7892,\n      \"verse\": 7893,\n      \"territorial\": 7894,\n      \"##ira\": 7895,\n      \"writings\": 7896,\n      \"corruption\": 7897,\n      \"##hs\": 7898,\n      \"instruction\": 7899,\n      \"inherited\": 7900,\n      \"reverse\": 7901,\n      \"emphasis\": 7902,\n      \"##vic\": 7903,\n      \"employee\": 7904,\n      \"arch\": 7905,\n      \"keeps\": 7906,\n      \"rabbi\": 7907,\n      \"watson\": 7908,\n      \"payment\": 7909,\n      \"uh\": 7910,\n      \"##ala\": 7911,\n      \"nancy\": 7912,\n      \"##tre\": 7913,\n      \"venice\": 7914,\n      \"fastest\": 7915,\n      \"sexy\": 7916,\n      \"banned\": 7917,\n      \"adrian\": 7918,\n      \"properly\": 7919,\n      \"ruth\": 7920,\n      \"touchdown\": 7921,\n      \"dollar\": 7922,\n      \"boards\": 7923,\n      \"metre\": 7924,\n      \"circles\": 7925,\n      \"edges\": 7926,\n      \"favour\": 7927,\n      \"comments\": 7928,\n      \"ok\": 7929,\n      \"travels\": 7930,\n      \"liberation\": 7931,\n      \"scattered\": 7932,\n      \"firmly\": 7933,\n      \"##ular\": 7934,\n      \"holland\": 7935,\n      \"permitted\": 7936,\n      \"diesel\": 7937,\n      \"kenya\": 7938,\n      \"den\": 7939,\n      \"originated\": 7940,\n      \"##ral\": 7941,\n      \"demons\": 7942,\n      \"resumed\": 7943,\n      \"dragged\": 7944,\n      \"rider\": 7945,\n      \"##rus\": 7946,\n      \"servant\": 7947,\n      \"blinked\": 7948,\n      \"extend\": 7949,\n      \"torn\": 7950,\n      \"##ias\": 7951,\n      \"##sey\": 7952,\n      \"input\": 7953,\n      \"meal\": 7954,\n      \"everybody\": 7955,\n      \"cylinder\": 7956,\n      \"kinds\": 7957,\n      \"camps\": 7958,\n      \"##fe\": 7959,\n      \"bullet\": 7960,\n      \"logic\": 7961,\n      \"##wn\": 7962,\n      \"croatian\": 7963,\n      \"evolved\": 7964,\n      \"healthy\": 7965,\n      \"fool\": 7966,\n      \"chocolate\": 7967,\n      \"wise\": 7968,\n      \"preserve\": 7969,\n      \"pradesh\": 7970,\n      \"##ess\": 7971,\n      \"respective\": 7972,\n      \"1850\": 7973,\n      \"##ew\": 7974,\n      \"chicken\": 7975,\n      \"artificial\": 7976,\n      \"gross\": 7977,\n      \"corresponding\": 7978,\n      \"convicted\": 7979,\n      \"cage\": 7980,\n      \"caroline\": 7981,\n      \"dialogue\": 7982,\n      \"##dor\": 7983,\n      \"narrative\": 7984,\n      \"stranger\": 7985,\n      \"mario\": 7986,\n      \"br\": 7987,\n      \"christianity\": 7988,\n      \"failing\": 7989,\n      \"trent\": 7990,\n      \"commanding\": 7991,\n      \"buddhist\": 7992,\n      \"1848\": 7993,\n      \"maurice\": 7994,\n      \"focusing\": 7995,\n      \"yale\": 7996,\n      \"bike\": 7997,\n      \"altitude\": 7998,\n      \"##ering\": 7999,\n      \"mouse\": 8000,\n      \"revised\": 8001,\n      \"##sley\": 8002,\n      \"veteran\": 8003,\n      \"##ig\": 8004,\n      \"pulls\": 8005,\n      \"theology\": 8006,\n      \"crashed\": 8007,\n      \"campaigns\": 8008,\n      \"legion\": 8009,\n      \"##ability\": 8010,\n      \"drag\": 8011,\n      \"excellence\": 8012,\n      \"customer\": 8013,\n      \"cancelled\": 8014,\n      \"intensity\": 8015,\n      \"excuse\": 8016,\n      \"##lar\": 8017,\n      \"liga\": 8018,\n      \"participating\": 8019,\n      \"contributing\": 8020,\n      \"printing\": 8021,\n      \"##burn\": 8022,\n      \"variable\": 8023,\n      \"##rk\": 8024,\n      \"curious\": 8025,\n      \"bin\": 8026,\n      \"legacy\": 8027,\n      \"renaissance\": 8028,\n      \"##my\": 8029,\n      \"symptoms\": 8030,\n      \"binding\": 8031,\n      \"vocalist\": 8032,\n      \"dancer\": 8033,\n      \"##nie\": 8034,\n      \"grammar\": 8035,\n      \"gospel\": 8036,\n      \"democrats\": 8037,\n      \"ya\": 8038,\n      \"enters\": 8039,\n      \"sc\": 8040,\n      \"diplomatic\": 8041,\n      \"hitler\": 8042,\n      \"##ser\": 8043,\n      \"clouds\": 8044,\n      \"mathematical\": 8045,\n      \"quit\": 8046,\n      \"defended\": 8047,\n      \"oriented\": 8048,\n      \"##heim\": 8049,\n      \"fundamental\": 8050,\n      \"hardware\": 8051,\n      \"impressive\": 8052,\n      \"equally\": 8053,\n      \"convince\": 8054,\n      \"confederate\": 8055,\n      \"guilt\": 8056,\n      \"chuck\": 8057,\n      \"sliding\": 8058,\n      \"##ware\": 8059,\n      \"magnetic\": 8060,\n      \"narrowed\": 8061,\n      \"petersburg\": 8062,\n      \"bulgaria\": 8063,\n      \"otto\": 8064,\n      \"phd\": 8065,\n      \"skill\": 8066,\n      \"##ama\": 8067,\n      \"reader\": 8068,\n      \"hopes\": 8069,\n      \"pitcher\": 8070,\n      \"reservoir\": 8071,\n      \"hearts\": 8072,\n      \"automatically\": 8073,\n      \"expecting\": 8074,\n      \"mysterious\": 8075,\n      \"bennett\": 8076,\n      \"extensively\": 8077,\n      \"imagined\": 8078,\n      \"seeds\": 8079,\n      \"monitor\": 8080,\n      \"fix\": 8081,\n      \"##ative\": 8082,\n      \"journalism\": 8083,\n      \"struggling\": 8084,\n      \"signature\": 8085,\n      \"ranch\": 8086,\n      \"encounter\": 8087,\n      \"photographer\": 8088,\n      \"observation\": 8089,\n      \"protests\": 8090,\n      \"##pin\": 8091,\n      \"influences\": 8092,\n      \"##hr\": 8093,\n      \"calendar\": 8094,\n      \"##all\": 8095,\n      \"cruz\": 8096,\n      \"croatia\": 8097,\n      \"locomotive\": 8098,\n      \"hughes\": 8099,\n      \"naturally\": 8100,\n      \"shakespeare\": 8101,\n      \"basement\": 8102,\n      \"hook\": 8103,\n      \"uncredited\": 8104,\n      \"faded\": 8105,\n      \"theories\": 8106,\n      \"approaches\": 8107,\n      \"dare\": 8108,\n      \"phillips\": 8109,\n      \"filling\": 8110,\n      \"fury\": 8111,\n      \"obama\": 8112,\n      \"##ain\": 8113,\n      \"efficient\": 8114,\n      \"arc\": 8115,\n      \"deliver\": 8116,\n      \"min\": 8117,\n      \"raid\": 8118,\n      \"breeding\": 8119,\n      \"inducted\": 8120,\n      \"leagues\": 8121,\n      \"efficiency\": 8122,\n      \"axis\": 8123,\n      \"montana\": 8124,\n      \"eagles\": 8125,\n      \"##ked\": 8126,\n      \"supplied\": 8127,\n      \"instructions\": 8128,\n      \"karen\": 8129,\n      \"picking\": 8130,\n      \"indicating\": 8131,\n      \"trap\": 8132,\n      \"anchor\": 8133,\n      \"practically\": 8134,\n      \"christians\": 8135,\n      \"tomb\": 8136,\n      \"vary\": 8137,\n      \"occasional\": 8138,\n      \"electronics\": 8139,\n      \"lords\": 8140,\n      \"readers\": 8141,\n      \"newcastle\": 8142,\n      \"faint\": 8143,\n      \"innovation\": 8144,\n      \"collect\": 8145,\n      \"situations\": 8146,\n      \"engagement\": 8147,\n      \"160\": 8148,\n      \"claude\": 8149,\n      \"mixture\": 8150,\n      \"##feld\": 8151,\n      \"peer\": 8152,\n      \"tissue\": 8153,\n      \"logo\": 8154,\n      \"lean\": 8155,\n      \"##ration\": 8156,\n      \"°f\": 8157,\n      \"floors\": 8158,\n      \"##ven\": 8159,\n      \"architects\": 8160,\n      \"reducing\": 8161,\n      \"##our\": 8162,\n      \"##ments\": 8163,\n      \"rope\": 8164,\n      \"1859\": 8165,\n      \"ottawa\": 8166,\n      \"##har\": 8167,\n      \"samples\": 8168,\n      \"banking\": 8169,\n      \"declaration\": 8170,\n      \"proteins\": 8171,\n      \"resignation\": 8172,\n      \"francois\": 8173,\n      \"saudi\": 8174,\n      \"advocate\": 8175,\n      \"exhibited\": 8176,\n      \"armor\": 8177,\n      \"twins\": 8178,\n      \"divorce\": 8179,\n      \"##ras\": 8180,\n      \"abraham\": 8181,\n      \"reviewed\": 8182,\n      \"jo\": 8183,\n      \"temporarily\": 8184,\n      \"matrix\": 8185,\n      \"physically\": 8186,\n      \"pulse\": 8187,\n      \"curled\": 8188,\n      \"##ena\": 8189,\n      \"difficulties\": 8190,\n      \"bengal\": 8191,\n      \"usage\": 8192,\n      \"##ban\": 8193,\n      \"annie\": 8194,\n      \"riders\": 8195,\n      \"certificate\": 8196,\n      \"##pi\": 8197,\n      \"holes\": 8198,\n      \"warsaw\": 8199,\n      \"distinctive\": 8200,\n      \"jessica\": 8201,\n      \"##mon\": 8202,\n      \"mutual\": 8203,\n      \"1857\": 8204,\n      \"customs\": 8205,\n      \"circular\": 8206,\n      \"eugene\": 8207,\n      \"removal\": 8208,\n      \"loaded\": 8209,\n      \"mere\": 8210,\n      \"vulnerable\": 8211,\n      \"depicted\": 8212,\n      \"generations\": 8213,\n      \"dame\": 8214,\n      \"heir\": 8215,\n      \"enormous\": 8216,\n      \"lightly\": 8217,\n      \"climbing\": 8218,\n      \"pitched\": 8219,\n      \"lessons\": 8220,\n      \"pilots\": 8221,\n      \"nepal\": 8222,\n      \"ram\": 8223,\n      \"google\": 8224,\n      \"preparing\": 8225,\n      \"brad\": 8226,\n      \"louise\": 8227,\n      \"renowned\": 8228,\n      \"##₂\": 8229,\n      \"liam\": 8230,\n      \"##ably\": 8231,\n      \"plaza\": 8232,\n      \"shaw\": 8233,\n      \"sophie\": 8234,\n      \"brilliant\": 8235,\n      \"bills\": 8236,\n      \"##bar\": 8237,\n      \"##nik\": 8238,\n      \"fucking\": 8239,\n      \"mainland\": 8240,\n      \"server\": 8241,\n      \"pleasant\": 8242,\n      \"seized\": 8243,\n      \"veterans\": 8244,\n      \"jerked\": 8245,\n      \"fail\": 8246,\n      \"beta\": 8247,\n      \"brush\": 8248,\n      \"radiation\": 8249,\n      \"stored\": 8250,\n      \"warmth\": 8251,\n      \"southeastern\": 8252,\n      \"nate\": 8253,\n      \"sin\": 8254,\n      \"raced\": 8255,\n      \"berkeley\": 8256,\n      \"joke\": 8257,\n      \"athlete\": 8258,\n      \"designation\": 8259,\n      \"trunk\": 8260,\n      \"##low\": 8261,\n      \"roland\": 8262,\n      \"qualification\": 8263,\n      \"archives\": 8264,\n      \"heels\": 8265,\n      \"artwork\": 8266,\n      \"receives\": 8267,\n      \"judicial\": 8268,\n      \"reserves\": 8269,\n      \"##bed\": 8270,\n      \"woke\": 8271,\n      \"installation\": 8272,\n      \"abu\": 8273,\n      \"floating\": 8274,\n      \"fake\": 8275,\n      \"lesser\": 8276,\n      \"excitement\": 8277,\n      \"interface\": 8278,\n      \"concentrated\": 8279,\n      \"addressed\": 8280,\n      \"characteristic\": 8281,\n      \"amanda\": 8282,\n      \"saxophone\": 8283,\n      \"monk\": 8284,\n      \"auto\": 8285,\n      \"##bus\": 8286,\n      \"releasing\": 8287,\n      \"egg\": 8288,\n      \"dies\": 8289,\n      \"interaction\": 8290,\n      \"defender\": 8291,\n      \"ce\": 8292,\n      \"outbreak\": 8293,\n      \"glory\": 8294,\n      \"loving\": 8295,\n      \"##bert\": 8296,\n      \"sequel\": 8297,\n      \"consciousness\": 8298,\n      \"http\": 8299,\n      \"awake\": 8300,\n      \"ski\": 8301,\n      \"enrolled\": 8302,\n      \"##ress\": 8303,\n      \"handling\": 8304,\n      \"rookie\": 8305,\n      \"brow\": 8306,\n      \"somebody\": 8307,\n      \"biography\": 8308,\n      \"warfare\": 8309,\n      \"amounts\": 8310,\n      \"contracts\": 8311,\n      \"presentation\": 8312,\n      \"fabric\": 8313,\n      \"dissolved\": 8314,\n      \"challenged\": 8315,\n      \"meter\": 8316,\n      \"psychological\": 8317,\n      \"lt\": 8318,\n      \"elevated\": 8319,\n      \"rally\": 8320,\n      \"accurate\": 8321,\n      \"##tha\": 8322,\n      \"hospitals\": 8323,\n      \"undergraduate\": 8324,\n      \"specialist\": 8325,\n      \"venezuela\": 8326,\n      \"exhibit\": 8327,\n      \"shed\": 8328,\n      \"nursing\": 8329,\n      \"protestant\": 8330,\n      \"fluid\": 8331,\n      \"structural\": 8332,\n      \"footage\": 8333,\n      \"jared\": 8334,\n      \"consistent\": 8335,\n      \"prey\": 8336,\n      \"##ska\": 8337,\n      \"succession\": 8338,\n      \"reflect\": 8339,\n      \"exile\": 8340,\n      \"lebanon\": 8341,\n      \"wiped\": 8342,\n      \"suspect\": 8343,\n      \"shanghai\": 8344,\n      \"resting\": 8345,\n      \"integration\": 8346,\n      \"preservation\": 8347,\n      \"marvel\": 8348,\n      \"variant\": 8349,\n      \"pirates\": 8350,\n      \"sheep\": 8351,\n      \"rounded\": 8352,\n      \"capita\": 8353,\n      \"sailing\": 8354,\n      \"colonies\": 8355,\n      \"manuscript\": 8356,\n      \"deemed\": 8357,\n      \"variations\": 8358,\n      \"clarke\": 8359,\n      \"functional\": 8360,\n      \"emerging\": 8361,\n      \"boxing\": 8362,\n      \"relaxed\": 8363,\n      \"curse\": 8364,\n      \"azerbaijan\": 8365,\n      \"heavyweight\": 8366,\n      \"nickname\": 8367,\n      \"editorial\": 8368,\n      \"rang\": 8369,\n      \"grid\": 8370,\n      \"tightened\": 8371,\n      \"earthquake\": 8372,\n      \"flashed\": 8373,\n      \"miguel\": 8374,\n      \"rushing\": 8375,\n      \"##ches\": 8376,\n      \"improvements\": 8377,\n      \"boxes\": 8378,\n      \"brooks\": 8379,\n      \"180\": 8380,\n      \"consumption\": 8381,\n      \"molecular\": 8382,\n      \"felix\": 8383,\n      \"societies\": 8384,\n      \"repeatedly\": 8385,\n      \"variation\": 8386,\n      \"aids\": 8387,\n      \"civic\": 8388,\n      \"graphics\": 8389,\n      \"professionals\": 8390,\n      \"realm\": 8391,\n      \"autonomous\": 8392,\n      \"receiver\": 8393,\n      \"delayed\": 8394,\n      \"workshop\": 8395,\n      \"militia\": 8396,\n      \"chairs\": 8397,\n      \"trump\": 8398,\n      \"canyon\": 8399,\n      \"##point\": 8400,\n      \"harsh\": 8401,\n      \"extending\": 8402,\n      \"lovely\": 8403,\n      \"happiness\": 8404,\n      \"##jan\": 8405,\n      \"stake\": 8406,\n      \"eyebrows\": 8407,\n      \"embassy\": 8408,\n      \"wellington\": 8409,\n      \"hannah\": 8410,\n      \"##ella\": 8411,\n      \"sony\": 8412,\n      \"corners\": 8413,\n      \"bishops\": 8414,\n      \"swear\": 8415,\n      \"cloth\": 8416,\n      \"contents\": 8417,\n      \"xi\": 8418,\n      \"namely\": 8419,\n      \"commenced\": 8420,\n      \"1854\": 8421,\n      \"stanford\": 8422,\n      \"nashville\": 8423,\n      \"courage\": 8424,\n      \"graphic\": 8425,\n      \"commitment\": 8426,\n      \"garrison\": 8427,\n      \"##bin\": 8428,\n      \"hamlet\": 8429,\n      \"clearing\": 8430,\n      \"rebels\": 8431,\n      \"attraction\": 8432,\n      \"literacy\": 8433,\n      \"cooking\": 8434,\n      \"ruins\": 8435,\n      \"temples\": 8436,\n      \"jenny\": 8437,\n      \"humanity\": 8438,\n      \"celebrate\": 8439,\n      \"hasn\": 8440,\n      \"freight\": 8441,\n      \"sixty\": 8442,\n      \"rebel\": 8443,\n      \"bastard\": 8444,\n      \"##art\": 8445,\n      \"newton\": 8446,\n      \"##ada\": 8447,\n      \"deer\": 8448,\n      \"##ges\": 8449,\n      \"##ching\": 8450,\n      \"smiles\": 8451,\n      \"delaware\": 8452,\n      \"singers\": 8453,\n      \"##ets\": 8454,\n      \"approaching\": 8455,\n      \"assists\": 8456,\n      \"flame\": 8457,\n      \"##ph\": 8458,\n      \"boulevard\": 8459,\n      \"barrel\": 8460,\n      \"planted\": 8461,\n      \"##ome\": 8462,\n      \"pursuit\": 8463,\n      \"##sia\": 8464,\n      \"consequences\": 8465,\n      \"posts\": 8466,\n      \"shallow\": 8467,\n      \"invitation\": 8468,\n      \"rode\": 8469,\n      \"depot\": 8470,\n      \"ernest\": 8471,\n      \"kane\": 8472,\n      \"rod\": 8473,\n      \"concepts\": 8474,\n      \"preston\": 8475,\n      \"topic\": 8476,\n      \"chambers\": 8477,\n      \"striking\": 8478,\n      \"blast\": 8479,\n      \"arrives\": 8480,\n      \"descendants\": 8481,\n      \"montgomery\": 8482,\n      \"ranges\": 8483,\n      \"worlds\": 8484,\n      \"##lay\": 8485,\n      \"##ari\": 8486,\n      \"span\": 8487,\n      \"chaos\": 8488,\n      \"praise\": 8489,\n      \"##ag\": 8490,\n      \"fewer\": 8491,\n      \"1855\": 8492,\n      \"sanctuary\": 8493,\n      \"mud\": 8494,\n      \"fbi\": 8495,\n      \"##ions\": 8496,\n      \"programmes\": 8497,\n      \"maintaining\": 8498,\n      \"unity\": 8499,\n      \"harper\": 8500,\n      \"bore\": 8501,\n      \"handsome\": 8502,\n      \"closure\": 8503,\n      \"tournaments\": 8504,\n      \"thunder\": 8505,\n      \"nebraska\": 8506,\n      \"linda\": 8507,\n      \"facade\": 8508,\n      \"puts\": 8509,\n      \"satisfied\": 8510,\n      \"argentine\": 8511,\n      \"dale\": 8512,\n      \"cork\": 8513,\n      \"dome\": 8514,\n      \"panama\": 8515,\n      \"##yl\": 8516,\n      \"1858\": 8517,\n      \"tasks\": 8518,\n      \"experts\": 8519,\n      \"##ates\": 8520,\n      \"feeding\": 8521,\n      \"equation\": 8522,\n      \"##las\": 8523,\n      \"##ida\": 8524,\n      \"##tu\": 8525,\n      \"engage\": 8526,\n      \"bryan\": 8527,\n      \"##ax\": 8528,\n      \"um\": 8529,\n      \"quartet\": 8530,\n      \"melody\": 8531,\n      \"disbanded\": 8532,\n      \"sheffield\": 8533,\n      \"blocked\": 8534,\n      \"gasped\": 8535,\n      \"delay\": 8536,\n      \"kisses\": 8537,\n      \"maggie\": 8538,\n      \"connects\": 8539,\n      \"##non\": 8540,\n      \"sts\": 8541,\n      \"poured\": 8542,\n      \"creator\": 8543,\n      \"publishers\": 8544,\n      \"##we\": 8545,\n      \"guided\": 8546,\n      \"ellis\": 8547,\n      \"extinct\": 8548,\n      \"hug\": 8549,\n      \"gaining\": 8550,\n      \"##ord\": 8551,\n      \"complicated\": 8552,\n      \"##bility\": 8553,\n      \"poll\": 8554,\n      \"clenched\": 8555,\n      \"investigate\": 8556,\n      \"##use\": 8557,\n      \"thereby\": 8558,\n      \"quantum\": 8559,\n      \"spine\": 8560,\n      \"cdp\": 8561,\n      \"humor\": 8562,\n      \"kills\": 8563,\n      \"administered\": 8564,\n      \"semifinals\": 8565,\n      \"##du\": 8566,\n      \"encountered\": 8567,\n      \"ignore\": 8568,\n      \"##bu\": 8569,\n      \"commentary\": 8570,\n      \"##maker\": 8571,\n      \"bother\": 8572,\n      \"roosevelt\": 8573,\n      \"140\": 8574,\n      \"plains\": 8575,\n      \"halfway\": 8576,\n      \"flowing\": 8577,\n      \"cultures\": 8578,\n      \"crack\": 8579,\n      \"imprisoned\": 8580,\n      \"neighboring\": 8581,\n      \"airline\": 8582,\n      \"##ses\": 8583,\n      \"##view\": 8584,\n      \"##mate\": 8585,\n      \"##ec\": 8586,\n      \"gather\": 8587,\n      \"wolves\": 8588,\n      \"marathon\": 8589,\n      \"transformed\": 8590,\n      \"##ill\": 8591,\n      \"cruise\": 8592,\n      \"organisations\": 8593,\n      \"carol\": 8594,\n      \"punch\": 8595,\n      \"exhibitions\": 8596,\n      \"numbered\": 8597,\n      \"alarm\": 8598,\n      \"ratings\": 8599,\n      \"daddy\": 8600,\n      \"silently\": 8601,\n      \"##stein\": 8602,\n      \"queens\": 8603,\n      \"colours\": 8604,\n      \"impression\": 8605,\n      \"guidance\": 8606,\n      \"liu\": 8607,\n      \"tactical\": 8608,\n      \"##rat\": 8609,\n      \"marshal\": 8610,\n      \"della\": 8611,\n      \"arrow\": 8612,\n      \"##ings\": 8613,\n      \"rested\": 8614,\n      \"feared\": 8615,\n      \"tender\": 8616,\n      \"owns\": 8617,\n      \"bitter\": 8618,\n      \"advisor\": 8619,\n      \"escort\": 8620,\n      \"##ides\": 8621,\n      \"spare\": 8622,\n      \"farms\": 8623,\n      \"grants\": 8624,\n      \"##ene\": 8625,\n      \"dragons\": 8626,\n      \"encourage\": 8627,\n      \"colleagues\": 8628,\n      \"cameras\": 8629,\n      \"##und\": 8630,\n      \"sucked\": 8631,\n      \"pile\": 8632,\n      \"spirits\": 8633,\n      \"prague\": 8634,\n      \"statements\": 8635,\n      \"suspension\": 8636,\n      \"landmark\": 8637,\n      \"fence\": 8638,\n      \"torture\": 8639,\n      \"recreation\": 8640,\n      \"bags\": 8641,\n      \"permanently\": 8642,\n      \"survivors\": 8643,\n      \"pond\": 8644,\n      \"spy\": 8645,\n      \"predecessor\": 8646,\n      \"bombing\": 8647,\n      \"coup\": 8648,\n      \"##og\": 8649,\n      \"protecting\": 8650,\n      \"transformation\": 8651,\n      \"glow\": 8652,\n      \"##lands\": 8653,\n      \"##book\": 8654,\n      \"dug\": 8655,\n      \"priests\": 8656,\n      \"andrea\": 8657,\n      \"feat\": 8658,\n      \"barn\": 8659,\n      \"jumping\": 8660,\n      \"##chen\": 8661,\n      \"##ologist\": 8662,\n      \"##con\": 8663,\n      \"casualties\": 8664,\n      \"stern\": 8665,\n      \"auckland\": 8666,\n      \"pipe\": 8667,\n      \"serie\": 8668,\n      \"revealing\": 8669,\n      \"ba\": 8670,\n      \"##bel\": 8671,\n      \"trevor\": 8672,\n      \"mercy\": 8673,\n      \"spectrum\": 8674,\n      \"yang\": 8675,\n      \"consist\": 8676,\n      \"governing\": 8677,\n      \"collaborated\": 8678,\n      \"possessed\": 8679,\n      \"epic\": 8680,\n      \"comprises\": 8681,\n      \"blew\": 8682,\n      \"shane\": 8683,\n      \"##ack\": 8684,\n      \"lopez\": 8685,\n      \"honored\": 8686,\n      \"magical\": 8687,\n      \"sacrifice\": 8688,\n      \"judgment\": 8689,\n      \"perceived\": 8690,\n      \"hammer\": 8691,\n      \"mtv\": 8692,\n      \"baronet\": 8693,\n      \"tune\": 8694,\n      \"das\": 8695,\n      \"missionary\": 8696,\n      \"sheets\": 8697,\n      \"350\": 8698,\n      \"neutral\": 8699,\n      \"oral\": 8700,\n      \"threatening\": 8701,\n      \"attractive\": 8702,\n      \"shade\": 8703,\n      \"aims\": 8704,\n      \"seminary\": 8705,\n      \"##master\": 8706,\n      \"estates\": 8707,\n      \"1856\": 8708,\n      \"michel\": 8709,\n      \"wounds\": 8710,\n      \"refugees\": 8711,\n      \"manufacturers\": 8712,\n      \"##nic\": 8713,\n      \"mercury\": 8714,\n      \"syndrome\": 8715,\n      \"porter\": 8716,\n      \"##iya\": 8717,\n      \"##din\": 8718,\n      \"hamburg\": 8719,\n      \"identification\": 8720,\n      \"upstairs\": 8721,\n      \"purse\": 8722,\n      \"widened\": 8723,\n      \"pause\": 8724,\n      \"cared\": 8725,\n      \"breathed\": 8726,\n      \"affiliate\": 8727,\n      \"santiago\": 8728,\n      \"prevented\": 8729,\n      \"celtic\": 8730,\n      \"fisher\": 8731,\n      \"125\": 8732,\n      \"recruited\": 8733,\n      \"byzantine\": 8734,\n      \"reconstruction\": 8735,\n      \"farther\": 8736,\n      \"##mp\": 8737,\n      \"diet\": 8738,\n      \"sake\": 8739,\n      \"au\": 8740,\n      \"spite\": 8741,\n      \"sensation\": 8742,\n      \"##ert\": 8743,\n      \"blank\": 8744,\n      \"separation\": 8745,\n      \"105\": 8746,\n      \"##hon\": 8747,\n      \"vladimir\": 8748,\n      \"armies\": 8749,\n      \"anime\": 8750,\n      \"##lie\": 8751,\n      \"accommodate\": 8752,\n      \"orbit\": 8753,\n      \"cult\": 8754,\n      \"sofia\": 8755,\n      \"archive\": 8756,\n      \"##ify\": 8757,\n      \"##box\": 8758,\n      \"founders\": 8759,\n      \"sustained\": 8760,\n      \"disorder\": 8761,\n      \"honours\": 8762,\n      \"northeastern\": 8763,\n      \"mia\": 8764,\n      \"crops\": 8765,\n      \"violet\": 8766,\n      \"threats\": 8767,\n      \"blanket\": 8768,\n      \"fires\": 8769,\n      \"canton\": 8770,\n      \"followers\": 8771,\n      \"southwestern\": 8772,\n      \"prototype\": 8773,\n      \"voyage\": 8774,\n      \"assignment\": 8775,\n      \"altered\": 8776,\n      \"moderate\": 8777,\n      \"protocol\": 8778,\n      \"pistol\": 8779,\n      \"##eo\": 8780,\n      \"questioned\": 8781,\n      \"brass\": 8782,\n      \"lifting\": 8783,\n      \"1852\": 8784,\n      \"math\": 8785,\n      \"authored\": 8786,\n      \"##ual\": 8787,\n      \"doug\": 8788,\n      \"dimensional\": 8789,\n      \"dynamic\": 8790,\n      \"##san\": 8791,\n      \"1851\": 8792,\n      \"pronounced\": 8793,\n      \"grateful\": 8794,\n      \"quest\": 8795,\n      \"uncomfortable\": 8796,\n      \"boom\": 8797,\n      \"presidency\": 8798,\n      \"stevens\": 8799,\n      \"relating\": 8800,\n      \"politicians\": 8801,\n      \"chen\": 8802,\n      \"barrier\": 8803,\n      \"quinn\": 8804,\n      \"diana\": 8805,\n      \"mosque\": 8806,\n      \"tribal\": 8807,\n      \"cheese\": 8808,\n      \"palmer\": 8809,\n      \"portions\": 8810,\n      \"sometime\": 8811,\n      \"chester\": 8812,\n      \"treasure\": 8813,\n      \"wu\": 8814,\n      \"bend\": 8815,\n      \"download\": 8816,\n      \"millions\": 8817,\n      \"reforms\": 8818,\n      \"registration\": 8819,\n      \"##osa\": 8820,\n      \"consequently\": 8821,\n      \"monitoring\": 8822,\n      \"ate\": 8823,\n      \"preliminary\": 8824,\n      \"brandon\": 8825,\n      \"invented\": 8826,\n      \"ps\": 8827,\n      \"eaten\": 8828,\n      \"exterior\": 8829,\n      \"intervention\": 8830,\n      \"ports\": 8831,\n      \"documented\": 8832,\n      \"log\": 8833,\n      \"displays\": 8834,\n      \"lecture\": 8835,\n      \"sally\": 8836,\n      \"favourite\": 8837,\n      \"##itz\": 8838,\n      \"vermont\": 8839,\n      \"lo\": 8840,\n      \"invisible\": 8841,\n      \"isle\": 8842,\n      \"breed\": 8843,\n      \"##ator\": 8844,\n      \"journalists\": 8845,\n      \"relay\": 8846,\n      \"speaks\": 8847,\n      \"backward\": 8848,\n      \"explore\": 8849,\n      \"midfielder\": 8850,\n      \"actively\": 8851,\n      \"stefan\": 8852,\n      \"procedures\": 8853,\n      \"cannon\": 8854,\n      \"blond\": 8855,\n      \"kenneth\": 8856,\n      \"centered\": 8857,\n      \"servants\": 8858,\n      \"chains\": 8859,\n      \"libraries\": 8860,\n      \"malcolm\": 8861,\n      \"essex\": 8862,\n      \"henri\": 8863,\n      \"slavery\": 8864,\n      \"##hal\": 8865,\n      \"facts\": 8866,\n      \"fairy\": 8867,\n      \"coached\": 8868,\n      \"cassie\": 8869,\n      \"cats\": 8870,\n      \"washed\": 8871,\n      \"cop\": 8872,\n      \"##fi\": 8873,\n      \"announcement\": 8874,\n      \"item\": 8875,\n      \"2000s\": 8876,\n      \"vinyl\": 8877,\n      \"activated\": 8878,\n      \"marco\": 8879,\n      \"frontier\": 8880,\n      \"growled\": 8881,\n      \"curriculum\": 8882,\n      \"##das\": 8883,\n      \"loyal\": 8884,\n      \"accomplished\": 8885,\n      \"leslie\": 8886,\n      \"ritual\": 8887,\n      \"kenny\": 8888,\n      \"##00\": 8889,\n      \"vii\": 8890,\n      \"napoleon\": 8891,\n      \"hollow\": 8892,\n      \"hybrid\": 8893,\n      \"jungle\": 8894,\n      \"stationed\": 8895,\n      \"friedrich\": 8896,\n      \"counted\": 8897,\n      \"##ulated\": 8898,\n      \"platinum\": 8899,\n      \"theatrical\": 8900,\n      \"seated\": 8901,\n      \"col\": 8902,\n      \"rubber\": 8903,\n      \"glen\": 8904,\n      \"1840\": 8905,\n      \"diversity\": 8906,\n      \"healing\": 8907,\n      \"extends\": 8908,\n      \"id\": 8909,\n      \"provisions\": 8910,\n      \"administrator\": 8911,\n      \"columbus\": 8912,\n      \"##oe\": 8913,\n      \"tributary\": 8914,\n      \"te\": 8915,\n      \"assured\": 8916,\n      \"org\": 8917,\n      \"##uous\": 8918,\n      \"prestigious\": 8919,\n      \"examined\": 8920,\n      \"lectures\": 8921,\n      \"grammy\": 8922,\n      \"ronald\": 8923,\n      \"associations\": 8924,\n      \"bailey\": 8925,\n      \"allan\": 8926,\n      \"essays\": 8927,\n      \"flute\": 8928,\n      \"believing\": 8929,\n      \"consultant\": 8930,\n      \"proceedings\": 8931,\n      \"travelling\": 8932,\n      \"1853\": 8933,\n      \"kit\": 8934,\n      \"kerala\": 8935,\n      \"yugoslavia\": 8936,\n      \"buddy\": 8937,\n      \"methodist\": 8938,\n      \"##ith\": 8939,\n      \"burial\": 8940,\n      \"centres\": 8941,\n      \"batman\": 8942,\n      \"##nda\": 8943,\n      \"discontinued\": 8944,\n      \"bo\": 8945,\n      \"dock\": 8946,\n      \"stockholm\": 8947,\n      \"lungs\": 8948,\n      \"severely\": 8949,\n      \"##nk\": 8950,\n      \"citing\": 8951,\n      \"manga\": 8952,\n      \"##ugh\": 8953,\n      \"steal\": 8954,\n      \"mumbai\": 8955,\n      \"iraqi\": 8956,\n      \"robot\": 8957,\n      \"celebrity\": 8958,\n      \"bride\": 8959,\n      \"broadcasts\": 8960,\n      \"abolished\": 8961,\n      \"pot\": 8962,\n      \"joel\": 8963,\n      \"overhead\": 8964,\n      \"franz\": 8965,\n      \"packed\": 8966,\n      \"reconnaissance\": 8967,\n      \"johann\": 8968,\n      \"acknowledged\": 8969,\n      \"introduce\": 8970,\n      \"handled\": 8971,\n      \"doctorate\": 8972,\n      \"developments\": 8973,\n      \"drinks\": 8974,\n      \"alley\": 8975,\n      \"palestine\": 8976,\n      \"##nis\": 8977,\n      \"##aki\": 8978,\n      \"proceeded\": 8979,\n      \"recover\": 8980,\n      \"bradley\": 8981,\n      \"grain\": 8982,\n      \"patch\": 8983,\n      \"afford\": 8984,\n      \"infection\": 8985,\n      \"nationalist\": 8986,\n      \"legendary\": 8987,\n      \"##ath\": 8988,\n      \"interchange\": 8989,\n      \"virtually\": 8990,\n      \"gen\": 8991,\n      \"gravity\": 8992,\n      \"exploration\": 8993,\n      \"amber\": 8994,\n      \"vital\": 8995,\n      \"wishes\": 8996,\n      \"powell\": 8997,\n      \"doctrine\": 8998,\n      \"elbow\": 8999,\n      \"screenplay\": 9000,\n      \"##bird\": 9001,\n      \"contribute\": 9002,\n      \"indonesian\": 9003,\n      \"pet\": 9004,\n      \"creates\": 9005,\n      \"##com\": 9006,\n      \"enzyme\": 9007,\n      \"kylie\": 9008,\n      \"discipline\": 9009,\n      \"drops\": 9010,\n      \"manila\": 9011,\n      \"hunger\": 9012,\n      \"##ien\": 9013,\n      \"layers\": 9014,\n      \"suffer\": 9015,\n      \"fever\": 9016,\n      \"bits\": 9017,\n      \"monica\": 9018,\n      \"keyboard\": 9019,\n      \"manages\": 9020,\n      \"##hood\": 9021,\n      \"searched\": 9022,\n      \"appeals\": 9023,\n      \"##bad\": 9024,\n      \"testament\": 9025,\n      \"grande\": 9026,\n      \"reid\": 9027,\n      \"##war\": 9028,\n      \"beliefs\": 9029,\n      \"congo\": 9030,\n      \"##ification\": 9031,\n      \"##dia\": 9032,\n      \"si\": 9033,\n      \"requiring\": 9034,\n      \"##via\": 9035,\n      \"casey\": 9036,\n      \"1849\": 9037,\n      \"regret\": 9038,\n      \"streak\": 9039,\n      \"rape\": 9040,\n      \"depends\": 9041,\n      \"syrian\": 9042,\n      \"sprint\": 9043,\n      \"pound\": 9044,\n      \"tourists\": 9045,\n      \"upcoming\": 9046,\n      \"pub\": 9047,\n      \"##xi\": 9048,\n      \"tense\": 9049,\n      \"##els\": 9050,\n      \"practiced\": 9051,\n      \"echo\": 9052,\n      \"nationwide\": 9053,\n      \"guild\": 9054,\n      \"motorcycle\": 9055,\n      \"liz\": 9056,\n      \"##zar\": 9057,\n      \"chiefs\": 9058,\n      \"desired\": 9059,\n      \"elena\": 9060,\n      \"bye\": 9061,\n      \"precious\": 9062,\n      \"absorbed\": 9063,\n      \"relatives\": 9064,\n      \"booth\": 9065,\n      \"pianist\": 9066,\n      \"##mal\": 9067,\n      \"citizenship\": 9068,\n      \"exhausted\": 9069,\n      \"wilhelm\": 9070,\n      \"##ceae\": 9071,\n      \"##hed\": 9072,\n      \"noting\": 9073,\n      \"quarterback\": 9074,\n      \"urge\": 9075,\n      \"hectares\": 9076,\n      \"##gue\": 9077,\n      \"ace\": 9078,\n      \"holly\": 9079,\n      \"##tal\": 9080,\n      \"blonde\": 9081,\n      \"davies\": 9082,\n      \"parked\": 9083,\n      \"sustainable\": 9084,\n      \"stepping\": 9085,\n      \"twentieth\": 9086,\n      \"airfield\": 9087,\n      \"galaxy\": 9088,\n      \"nest\": 9089,\n      \"chip\": 9090,\n      \"##nell\": 9091,\n      \"tan\": 9092,\n      \"shaft\": 9093,\n      \"paulo\": 9094,\n      \"requirement\": 9095,\n      \"##zy\": 9096,\n      \"paradise\": 9097,\n      \"tobacco\": 9098,\n      \"trans\": 9099,\n      \"renewed\": 9100,\n      \"vietnamese\": 9101,\n      \"##cker\": 9102,\n      \"##ju\": 9103,\n      \"suggesting\": 9104,\n      \"catching\": 9105,\n      \"holmes\": 9106,\n      \"enjoying\": 9107,\n      \"md\": 9108,\n      \"trips\": 9109,\n      \"colt\": 9110,\n      \"holder\": 9111,\n      \"butterfly\": 9112,\n      \"nerve\": 9113,\n      \"reformed\": 9114,\n      \"cherry\": 9115,\n      \"bowling\": 9116,\n      \"trailer\": 9117,\n      \"carriage\": 9118,\n      \"goodbye\": 9119,\n      \"appreciate\": 9120,\n      \"toy\": 9121,\n      \"joshua\": 9122,\n      \"interactive\": 9123,\n      \"enabled\": 9124,\n      \"involve\": 9125,\n      \"##kan\": 9126,\n      \"collar\": 9127,\n      \"determination\": 9128,\n      \"bunch\": 9129,\n      \"facebook\": 9130,\n      \"recall\": 9131,\n      \"shorts\": 9132,\n      \"superintendent\": 9133,\n      \"episcopal\": 9134,\n      \"frustration\": 9135,\n      \"giovanni\": 9136,\n      \"nineteenth\": 9137,\n      \"laser\": 9138,\n      \"privately\": 9139,\n      \"array\": 9140,\n      \"circulation\": 9141,\n      \"##ovic\": 9142,\n      \"armstrong\": 9143,\n      \"deals\": 9144,\n      \"painful\": 9145,\n      \"permit\": 9146,\n      \"discrimination\": 9147,\n      \"##wi\": 9148,\n      \"aires\": 9149,\n      \"retiring\": 9150,\n      \"cottage\": 9151,\n      \"ni\": 9152,\n      \"##sta\": 9153,\n      \"horizon\": 9154,\n      \"ellen\": 9155,\n      \"jamaica\": 9156,\n      \"ripped\": 9157,\n      \"fernando\": 9158,\n      \"chapters\": 9159,\n      \"playstation\": 9160,\n      \"patron\": 9161,\n      \"lecturer\": 9162,\n      \"navigation\": 9163,\n      \"behaviour\": 9164,\n      \"genes\": 9165,\n      \"georgian\": 9166,\n      \"export\": 9167,\n      \"solomon\": 9168,\n      \"rivals\": 9169,\n      \"swift\": 9170,\n      \"seventeen\": 9171,\n      \"rodriguez\": 9172,\n      \"princeton\": 9173,\n      \"independently\": 9174,\n      \"sox\": 9175,\n      \"1847\": 9176,\n      \"arguing\": 9177,\n      \"entity\": 9178,\n      \"casting\": 9179,\n      \"hank\": 9180,\n      \"criteria\": 9181,\n      \"oakland\": 9182,\n      \"geographic\": 9183,\n      \"milwaukee\": 9184,\n      \"reflection\": 9185,\n      \"expanding\": 9186,\n      \"conquest\": 9187,\n      \"dubbed\": 9188,\n      \"##tv\": 9189,\n      \"halt\": 9190,\n      \"brave\": 9191,\n      \"brunswick\": 9192,\n      \"doi\": 9193,\n      \"arched\": 9194,\n      \"curtis\": 9195,\n      \"divorced\": 9196,\n      \"predominantly\": 9197,\n      \"somerset\": 9198,\n      \"streams\": 9199,\n      \"ugly\": 9200,\n      \"zoo\": 9201,\n      \"horrible\": 9202,\n      \"curved\": 9203,\n      \"buenos\": 9204,\n      \"fierce\": 9205,\n      \"dictionary\": 9206,\n      \"vector\": 9207,\n      \"theological\": 9208,\n      \"unions\": 9209,\n      \"handful\": 9210,\n      \"stability\": 9211,\n      \"chan\": 9212,\n      \"punjab\": 9213,\n      \"segments\": 9214,\n      \"##lly\": 9215,\n      \"altar\": 9216,\n      \"ignoring\": 9217,\n      \"gesture\": 9218,\n      \"monsters\": 9219,\n      \"pastor\": 9220,\n      \"##stone\": 9221,\n      \"thighs\": 9222,\n      \"unexpected\": 9223,\n      \"operators\": 9224,\n      \"abruptly\": 9225,\n      \"coin\": 9226,\n      \"compiled\": 9227,\n      \"associates\": 9228,\n      \"improving\": 9229,\n      \"migration\": 9230,\n      \"pin\": 9231,\n      \"##ose\": 9232,\n      \"compact\": 9233,\n      \"collegiate\": 9234,\n      \"reserved\": 9235,\n      \"##urs\": 9236,\n      \"quarterfinals\": 9237,\n      \"roster\": 9238,\n      \"restore\": 9239,\n      \"assembled\": 9240,\n      \"hurry\": 9241,\n      \"oval\": 9242,\n      \"##cies\": 9243,\n      \"1846\": 9244,\n      \"flags\": 9245,\n      \"martha\": 9246,\n      \"##del\": 9247,\n      \"victories\": 9248,\n      \"sharply\": 9249,\n      \"##rated\": 9250,\n      \"argues\": 9251,\n      \"deadly\": 9252,\n      \"neo\": 9253,\n      \"drawings\": 9254,\n      \"symbols\": 9255,\n      \"performer\": 9256,\n      \"##iel\": 9257,\n      \"griffin\": 9258,\n      \"restrictions\": 9259,\n      \"editing\": 9260,\n      \"andrews\": 9261,\n      \"java\": 9262,\n      \"journals\": 9263,\n      \"arabia\": 9264,\n      \"compositions\": 9265,\n      \"dee\": 9266,\n      \"pierce\": 9267,\n      \"removing\": 9268,\n      \"hindi\": 9269,\n      \"casino\": 9270,\n      \"runway\": 9271,\n      \"civilians\": 9272,\n      \"minds\": 9273,\n      \"nasa\": 9274,\n      \"hotels\": 9275,\n      \"##zation\": 9276,\n      \"refuge\": 9277,\n      \"rent\": 9278,\n      \"retain\": 9279,\n      \"potentially\": 9280,\n      \"conferences\": 9281,\n      \"suburban\": 9282,\n      \"conducting\": 9283,\n      \"##tto\": 9284,\n      \"##tions\": 9285,\n      \"##tle\": 9286,\n      \"descended\": 9287,\n      \"massacre\": 9288,\n      \"##cal\": 9289,\n      \"ammunition\": 9290,\n      \"terrain\": 9291,\n      \"fork\": 9292,\n      \"souls\": 9293,\n      \"counts\": 9294,\n      \"chelsea\": 9295,\n      \"durham\": 9296,\n      \"drives\": 9297,\n      \"cab\": 9298,\n      \"##bank\": 9299,\n      \"perth\": 9300,\n      \"realizing\": 9301,\n      \"palestinian\": 9302,\n      \"finn\": 9303,\n      \"simpson\": 9304,\n      \"##dal\": 9305,\n      \"betty\": 9306,\n      \"##ule\": 9307,\n      \"moreover\": 9308,\n      \"particles\": 9309,\n      \"cardinals\": 9310,\n      \"tent\": 9311,\n      \"evaluation\": 9312,\n      \"extraordinary\": 9313,\n      \"##oid\": 9314,\n      \"inscription\": 9315,\n      \"##works\": 9316,\n      \"wednesday\": 9317,\n      \"chloe\": 9318,\n      \"maintains\": 9319,\n      \"panels\": 9320,\n      \"ashley\": 9321,\n      \"trucks\": 9322,\n      \"##nation\": 9323,\n      \"cluster\": 9324,\n      \"sunlight\": 9325,\n      \"strikes\": 9326,\n      \"zhang\": 9327,\n      \"##wing\": 9328,\n      \"dialect\": 9329,\n      \"canon\": 9330,\n      \"##ap\": 9331,\n      \"tucked\": 9332,\n      \"##ws\": 9333,\n      \"collecting\": 9334,\n      \"##mas\": 9335,\n      \"##can\": 9336,\n      \"##sville\": 9337,\n      \"maker\": 9338,\n      \"quoted\": 9339,\n      \"evan\": 9340,\n      \"franco\": 9341,\n      \"aria\": 9342,\n      \"buying\": 9343,\n      \"cleaning\": 9344,\n      \"eva\": 9345,\n      \"closet\": 9346,\n      \"provision\": 9347,\n      \"apollo\": 9348,\n      \"clinic\": 9349,\n      \"rat\": 9350,\n      \"##ez\": 9351,\n      \"necessarily\": 9352,\n      \"ac\": 9353,\n      \"##gle\": 9354,\n      \"##ising\": 9355,\n      \"venues\": 9356,\n      \"flipped\": 9357,\n      \"cent\": 9358,\n      \"spreading\": 9359,\n      \"trustees\": 9360,\n      \"checking\": 9361,\n      \"authorized\": 9362,\n      \"##sco\": 9363,\n      \"disappointed\": 9364,\n      \"##ado\": 9365,\n      \"notion\": 9366,\n      \"duration\": 9367,\n      \"trumpet\": 9368,\n      \"hesitated\": 9369,\n      \"topped\": 9370,\n      \"brussels\": 9371,\n      \"rolls\": 9372,\n      \"theoretical\": 9373,\n      \"hint\": 9374,\n      \"define\": 9375,\n      \"aggressive\": 9376,\n      \"repeat\": 9377,\n      \"wash\": 9378,\n      \"peaceful\": 9379,\n      \"optical\": 9380,\n      \"width\": 9381,\n      \"allegedly\": 9382,\n      \"mcdonald\": 9383,\n      \"strict\": 9384,\n      \"copyright\": 9385,\n      \"##illa\": 9386,\n      \"investors\": 9387,\n      \"mar\": 9388,\n      \"jam\": 9389,\n      \"witnesses\": 9390,\n      \"sounding\": 9391,\n      \"miranda\": 9392,\n      \"michelle\": 9393,\n      \"privacy\": 9394,\n      \"hugo\": 9395,\n      \"harmony\": 9396,\n      \"##pp\": 9397,\n      \"valid\": 9398,\n      \"lynn\": 9399,\n      \"glared\": 9400,\n      \"nina\": 9401,\n      \"102\": 9402,\n      \"headquartered\": 9403,\n      \"diving\": 9404,\n      \"boarding\": 9405,\n      \"gibson\": 9406,\n      \"##ncy\": 9407,\n      \"albanian\": 9408,\n      \"marsh\": 9409,\n      \"routine\": 9410,\n      \"dealt\": 9411,\n      \"enhanced\": 9412,\n      \"er\": 9413,\n      \"intelligent\": 9414,\n      \"substance\": 9415,\n      \"targeted\": 9416,\n      \"enlisted\": 9417,\n      \"discovers\": 9418,\n      \"spinning\": 9419,\n      \"observations\": 9420,\n      \"pissed\": 9421,\n      \"smoking\": 9422,\n      \"rebecca\": 9423,\n      \"capitol\": 9424,\n      \"visa\": 9425,\n      \"varied\": 9426,\n      \"costume\": 9427,\n      \"seemingly\": 9428,\n      \"indies\": 9429,\n      \"compensation\": 9430,\n      \"surgeon\": 9431,\n      \"thursday\": 9432,\n      \"arsenal\": 9433,\n      \"westminster\": 9434,\n      \"suburbs\": 9435,\n      \"rid\": 9436,\n      \"anglican\": 9437,\n      \"##ridge\": 9438,\n      \"knots\": 9439,\n      \"foods\": 9440,\n      \"alumni\": 9441,\n      \"lighter\": 9442,\n      \"fraser\": 9443,\n      \"whoever\": 9444,\n      \"portal\": 9445,\n      \"scandal\": 9446,\n      \"##ray\": 9447,\n      \"gavin\": 9448,\n      \"advised\": 9449,\n      \"instructor\": 9450,\n      \"flooding\": 9451,\n      \"terrorist\": 9452,\n      \"##ale\": 9453,\n      \"teenage\": 9454,\n      \"interim\": 9455,\n      \"senses\": 9456,\n      \"duck\": 9457,\n      \"teen\": 9458,\n      \"thesis\": 9459,\n      \"abby\": 9460,\n      \"eager\": 9461,\n      \"overcome\": 9462,\n      \"##ile\": 9463,\n      \"newport\": 9464,\n      \"glenn\": 9465,\n      \"rises\": 9466,\n      \"shame\": 9467,\n      \"##cc\": 9468,\n      \"prompted\": 9469,\n      \"priority\": 9470,\n      \"forgot\": 9471,\n      \"bomber\": 9472,\n      \"nicolas\": 9473,\n      \"protective\": 9474,\n      \"360\": 9475,\n      \"cartoon\": 9476,\n      \"katherine\": 9477,\n      \"breeze\": 9478,\n      \"lonely\": 9479,\n      \"trusted\": 9480,\n      \"henderson\": 9481,\n      \"richardson\": 9482,\n      \"relax\": 9483,\n      \"banner\": 9484,\n      \"candy\": 9485,\n      \"palms\": 9486,\n      \"remarkable\": 9487,\n      \"##rio\": 9488,\n      \"legends\": 9489,\n      \"cricketer\": 9490,\n      \"essay\": 9491,\n      \"ordained\": 9492,\n      \"edmund\": 9493,\n      \"rifles\": 9494,\n      \"trigger\": 9495,\n      \"##uri\": 9496,\n      \"##away\": 9497,\n      \"sail\": 9498,\n      \"alert\": 9499,\n      \"1830\": 9500,\n      \"audiences\": 9501,\n      \"penn\": 9502,\n      \"sussex\": 9503,\n      \"siblings\": 9504,\n      \"pursued\": 9505,\n      \"indianapolis\": 9506,\n      \"resist\": 9507,\n      \"rosa\": 9508,\n      \"consequence\": 9509,\n      \"succeed\": 9510,\n      \"avoided\": 9511,\n      \"1845\": 9512,\n      \"##ulation\": 9513,\n      \"inland\": 9514,\n      \"##tie\": 9515,\n      \"##nna\": 9516,\n      \"counsel\": 9517,\n      \"profession\": 9518,\n      \"chronicle\": 9519,\n      \"hurried\": 9520,\n      \"##una\": 9521,\n      \"eyebrow\": 9522,\n      \"eventual\": 9523,\n      \"bleeding\": 9524,\n      \"innovative\": 9525,\n      \"cure\": 9526,\n      \"##dom\": 9527,\n      \"committees\": 9528,\n      \"accounting\": 9529,\n      \"con\": 9530,\n      \"scope\": 9531,\n      \"hardy\": 9532,\n      \"heather\": 9533,\n      \"tenor\": 9534,\n      \"gut\": 9535,\n      \"herald\": 9536,\n      \"codes\": 9537,\n      \"tore\": 9538,\n      \"scales\": 9539,\n      \"wagon\": 9540,\n      \"##oo\": 9541,\n      \"luxury\": 9542,\n      \"tin\": 9543,\n      \"prefer\": 9544,\n      \"fountain\": 9545,\n      \"triangle\": 9546,\n      \"bonds\": 9547,\n      \"darling\": 9548,\n      \"convoy\": 9549,\n      \"dried\": 9550,\n      \"traced\": 9551,\n      \"beings\": 9552,\n      \"troy\": 9553,\n      \"accidentally\": 9554,\n      \"slam\": 9555,\n      \"findings\": 9556,\n      \"smelled\": 9557,\n      \"joey\": 9558,\n      \"lawyers\": 9559,\n      \"outcome\": 9560,\n      \"steep\": 9561,\n      \"bosnia\": 9562,\n      \"configuration\": 9563,\n      \"shifting\": 9564,\n      \"toll\": 9565,\n      \"brook\": 9566,\n      \"performers\": 9567,\n      \"lobby\": 9568,\n      \"philosophical\": 9569,\n      \"construct\": 9570,\n      \"shrine\": 9571,\n      \"aggregate\": 9572,\n      \"boot\": 9573,\n      \"cox\": 9574,\n      \"phenomenon\": 9575,\n      \"savage\": 9576,\n      \"insane\": 9577,\n      \"solely\": 9578,\n      \"reynolds\": 9579,\n      \"lifestyle\": 9580,\n      \"##ima\": 9581,\n      \"nationally\": 9582,\n      \"holdings\": 9583,\n      \"consideration\": 9584,\n      \"enable\": 9585,\n      \"edgar\": 9586,\n      \"mo\": 9587,\n      \"mama\": 9588,\n      \"##tein\": 9589,\n      \"fights\": 9590,\n      \"relegation\": 9591,\n      \"chances\": 9592,\n      \"atomic\": 9593,\n      \"hub\": 9594,\n      \"conjunction\": 9595,\n      \"awkward\": 9596,\n      \"reactions\": 9597,\n      \"currency\": 9598,\n      \"finale\": 9599,\n      \"kumar\": 9600,\n      \"underwent\": 9601,\n      \"steering\": 9602,\n      \"elaborate\": 9603,\n      \"gifts\": 9604,\n      \"comprising\": 9605,\n      \"melissa\": 9606,\n      \"veins\": 9607,\n      \"reasonable\": 9608,\n      \"sunshine\": 9609,\n      \"chi\": 9610,\n      \"solve\": 9611,\n      \"trails\": 9612,\n      \"inhabited\": 9613,\n      \"elimination\": 9614,\n      \"ethics\": 9615,\n      \"huh\": 9616,\n      \"ana\": 9617,\n      \"molly\": 9618,\n      \"consent\": 9619,\n      \"apartments\": 9620,\n      \"layout\": 9621,\n      \"marines\": 9622,\n      \"##ces\": 9623,\n      \"hunters\": 9624,\n      \"bulk\": 9625,\n      \"##oma\": 9626,\n      \"hometown\": 9627,\n      \"##wall\": 9628,\n      \"##mont\": 9629,\n      \"cracked\": 9630,\n      \"reads\": 9631,\n      \"neighbouring\": 9632,\n      \"withdrawn\": 9633,\n      \"admission\": 9634,\n      \"wingspan\": 9635,\n      \"damned\": 9636,\n      \"anthology\": 9637,\n      \"lancashire\": 9638,\n      \"brands\": 9639,\n      \"batting\": 9640,\n      \"forgive\": 9641,\n      \"cuban\": 9642,\n      \"awful\": 9643,\n      \"##lyn\": 9644,\n      \"104\": 9645,\n      \"dimensions\": 9646,\n      \"imagination\": 9647,\n      \"##ade\": 9648,\n      \"dante\": 9649,\n      \"##ship\": 9650,\n      \"tracking\": 9651,\n      \"desperately\": 9652,\n      \"goalkeeper\": 9653,\n      \"##yne\": 9654,\n      \"groaned\": 9655,\n      \"workshops\": 9656,\n      \"confident\": 9657,\n      \"burton\": 9658,\n      \"gerald\": 9659,\n      \"milton\": 9660,\n      \"circus\": 9661,\n      \"uncertain\": 9662,\n      \"slope\": 9663,\n      \"copenhagen\": 9664,\n      \"sophia\": 9665,\n      \"fog\": 9666,\n      \"philosopher\": 9667,\n      \"portraits\": 9668,\n      \"accent\": 9669,\n      \"cycling\": 9670,\n      \"varying\": 9671,\n      \"gripped\": 9672,\n      \"larvae\": 9673,\n      \"garrett\": 9674,\n      \"specified\": 9675,\n      \"scotia\": 9676,\n      \"mature\": 9677,\n      \"luther\": 9678,\n      \"kurt\": 9679,\n      \"rap\": 9680,\n      \"##kes\": 9681,\n      \"aerial\": 9682,\n      \"750\": 9683,\n      \"ferdinand\": 9684,\n      \"heated\": 9685,\n      \"es\": 9686,\n      \"transported\": 9687,\n      \"##shan\": 9688,\n      \"safely\": 9689,\n      \"nonetheless\": 9690,\n      \"##orn\": 9691,\n      \"##gal\": 9692,\n      \"motors\": 9693,\n      \"demanding\": 9694,\n      \"##sburg\": 9695,\n      \"startled\": 9696,\n      \"##brook\": 9697,\n      \"ally\": 9698,\n      \"generate\": 9699,\n      \"caps\": 9700,\n      \"ghana\": 9701,\n      \"stained\": 9702,\n      \"demo\": 9703,\n      \"mentions\": 9704,\n      \"beds\": 9705,\n      \"ap\": 9706,\n      \"afterward\": 9707,\n      \"diary\": 9708,\n      \"##bling\": 9709,\n      \"utility\": 9710,\n      \"##iro\": 9711,\n      \"richards\": 9712,\n      \"1837\": 9713,\n      \"conspiracy\": 9714,\n      \"conscious\": 9715,\n      \"shining\": 9716,\n      \"footsteps\": 9717,\n      \"observer\": 9718,\n      \"cyprus\": 9719,\n      \"urged\": 9720,\n      \"loyalty\": 9721,\n      \"developer\": 9722,\n      \"probability\": 9723,\n      \"olive\": 9724,\n      \"upgraded\": 9725,\n      \"gym\": 9726,\n      \"miracle\": 9727,\n      \"insects\": 9728,\n      \"graves\": 9729,\n      \"1844\": 9730,\n      \"ourselves\": 9731,\n      \"hydrogen\": 9732,\n      \"amazon\": 9733,\n      \"katie\": 9734,\n      \"tickets\": 9735,\n      \"poets\": 9736,\n      \"##pm\": 9737,\n      \"planes\": 9738,\n      \"##pan\": 9739,\n      \"prevention\": 9740,\n      \"witnessed\": 9741,\n      \"dense\": 9742,\n      \"jin\": 9743,\n      \"randy\": 9744,\n      \"tang\": 9745,\n      \"warehouse\": 9746,\n      \"monroe\": 9747,\n      \"bang\": 9748,\n      \"archived\": 9749,\n      \"elderly\": 9750,\n      \"investigations\": 9751,\n      \"alec\": 9752,\n      \"granite\": 9753,\n      \"mineral\": 9754,\n      \"conflicts\": 9755,\n      \"controlling\": 9756,\n      \"aboriginal\": 9757,\n      \"carlo\": 9758,\n      \"##zu\": 9759,\n      \"mechanics\": 9760,\n      \"stan\": 9761,\n      \"stark\": 9762,\n      \"rhode\": 9763,\n      \"skirt\": 9764,\n      \"est\": 9765,\n      \"##berry\": 9766,\n      \"bombs\": 9767,\n      \"respected\": 9768,\n      \"##horn\": 9769,\n      \"imposed\": 9770,\n      \"limestone\": 9771,\n      \"deny\": 9772,\n      \"nominee\": 9773,\n      \"memphis\": 9774,\n      \"grabbing\": 9775,\n      \"disabled\": 9776,\n      \"##als\": 9777,\n      \"amusement\": 9778,\n      \"aa\": 9779,\n      \"frankfurt\": 9780,\n      \"corn\": 9781,\n      \"referendum\": 9782,\n      \"varies\": 9783,\n      \"slowed\": 9784,\n      \"disk\": 9785,\n      \"firms\": 9786,\n      \"unconscious\": 9787,\n      \"incredible\": 9788,\n      \"clue\": 9789,\n      \"sue\": 9790,\n      \"##zhou\": 9791,\n      \"twist\": 9792,\n      \"##cio\": 9793,\n      \"joins\": 9794,\n      \"idaho\": 9795,\n      \"chad\": 9796,\n      \"developers\": 9797,\n      \"computing\": 9798,\n      \"destroyer\": 9799,\n      \"103\": 9800,\n      \"mortal\": 9801,\n      \"tucker\": 9802,\n      \"kingston\": 9803,\n      \"choices\": 9804,\n      \"yu\": 9805,\n      \"carson\": 9806,\n      \"1800\": 9807,\n      \"os\": 9808,\n      \"whitney\": 9809,\n      \"geneva\": 9810,\n      \"pretend\": 9811,\n      \"dimension\": 9812,\n      \"staged\": 9813,\n      \"plateau\": 9814,\n      \"maya\": 9815,\n      \"##une\": 9816,\n      \"freestyle\": 9817,\n      \"##bc\": 9818,\n      \"rovers\": 9819,\n      \"hiv\": 9820,\n      \"##ids\": 9821,\n      \"tristan\": 9822,\n      \"classroom\": 9823,\n      \"prospect\": 9824,\n      \"##hus\": 9825,\n      \"honestly\": 9826,\n      \"diploma\": 9827,\n      \"lied\": 9828,\n      \"thermal\": 9829,\n      \"auxiliary\": 9830,\n      \"feast\": 9831,\n      \"unlikely\": 9832,\n      \"iata\": 9833,\n      \"##tel\": 9834,\n      \"morocco\": 9835,\n      \"pounding\": 9836,\n      \"treasury\": 9837,\n      \"lithuania\": 9838,\n      \"considerably\": 9839,\n      \"1841\": 9840,\n      \"dish\": 9841,\n      \"1812\": 9842,\n      \"geological\": 9843,\n      \"matching\": 9844,\n      \"stumbled\": 9845,\n      \"destroying\": 9846,\n      \"marched\": 9847,\n      \"brien\": 9848,\n      \"advances\": 9849,\n      \"cake\": 9850,\n      \"nicole\": 9851,\n      \"belle\": 9852,\n      \"settling\": 9853,\n      \"measuring\": 9854,\n      \"directing\": 9855,\n      \"##mie\": 9856,\n      \"tuesday\": 9857,\n      \"bassist\": 9858,\n      \"capabilities\": 9859,\n      \"stunned\": 9860,\n      \"fraud\": 9861,\n      \"torpedo\": 9862,\n      \"##list\": 9863,\n      \"##phone\": 9864,\n      \"anton\": 9865,\n      \"wisdom\": 9866,\n      \"surveillance\": 9867,\n      \"ruined\": 9868,\n      \"##ulate\": 9869,\n      \"lawsuit\": 9870,\n      \"healthcare\": 9871,\n      \"theorem\": 9872,\n      \"halls\": 9873,\n      \"trend\": 9874,\n      \"aka\": 9875,\n      \"horizontal\": 9876,\n      \"dozens\": 9877,\n      \"acquire\": 9878,\n      \"lasting\": 9879,\n      \"swim\": 9880,\n      \"hawk\": 9881,\n      \"gorgeous\": 9882,\n      \"fees\": 9883,\n      \"vicinity\": 9884,\n      \"decrease\": 9885,\n      \"adoption\": 9886,\n      \"tactics\": 9887,\n      \"##ography\": 9888,\n      \"pakistani\": 9889,\n      \"##ole\": 9890,\n      \"draws\": 9891,\n      \"##hall\": 9892,\n      \"willie\": 9893,\n      \"burke\": 9894,\n      \"heath\": 9895,\n      \"algorithm\": 9896,\n      \"integral\": 9897,\n      \"powder\": 9898,\n      \"elliott\": 9899,\n      \"brigadier\": 9900,\n      \"jackie\": 9901,\n      \"tate\": 9902,\n      \"varieties\": 9903,\n      \"darker\": 9904,\n      \"##cho\": 9905,\n      \"lately\": 9906,\n      \"cigarette\": 9907,\n      \"specimens\": 9908,\n      \"adds\": 9909,\n      \"##ree\": 9910,\n      \"##ensis\": 9911,\n      \"##inger\": 9912,\n      \"exploded\": 9913,\n      \"finalist\": 9914,\n      \"cia\": 9915,\n      \"murders\": 9916,\n      \"wilderness\": 9917,\n      \"arguments\": 9918,\n      \"nicknamed\": 9919,\n      \"acceptance\": 9920,\n      \"onwards\": 9921,\n      \"manufacture\": 9922,\n      \"robertson\": 9923,\n      \"jets\": 9924,\n      \"tampa\": 9925,\n      \"enterprises\": 9926,\n      \"blog\": 9927,\n      \"loudly\": 9928,\n      \"composers\": 9929,\n      \"nominations\": 9930,\n      \"1838\": 9931,\n      \"ai\": 9932,\n      \"malta\": 9933,\n      \"inquiry\": 9934,\n      \"automobile\": 9935,\n      \"hosting\": 9936,\n      \"viii\": 9937,\n      \"rays\": 9938,\n      \"tilted\": 9939,\n      \"grief\": 9940,\n      \"museums\": 9941,\n      \"strategies\": 9942,\n      \"furious\": 9943,\n      \"euro\": 9944,\n      \"equality\": 9945,\n      \"cohen\": 9946,\n      \"poison\": 9947,\n      \"surrey\": 9948,\n      \"wireless\": 9949,\n      \"governed\": 9950,\n      \"ridiculous\": 9951,\n      \"moses\": 9952,\n      \"##esh\": 9953,\n      \"##room\": 9954,\n      \"vanished\": 9955,\n      \"##ito\": 9956,\n      \"barnes\": 9957,\n      \"attract\": 9958,\n      \"morrison\": 9959,\n      \"istanbul\": 9960,\n      \"##iness\": 9961,\n      \"absent\": 9962,\n      \"rotation\": 9963,\n      \"petition\": 9964,\n      \"janet\": 9965,\n      \"##logical\": 9966,\n      \"satisfaction\": 9967,\n      \"custody\": 9968,\n      \"deliberately\": 9969,\n      \"observatory\": 9970,\n      \"comedian\": 9971,\n      \"surfaces\": 9972,\n      \"pinyin\": 9973,\n      \"novelist\": 9974,\n      \"strictly\": 9975,\n      \"canterbury\": 9976,\n      \"oslo\": 9977,\n      \"monks\": 9978,\n      \"embrace\": 9979,\n      \"ibm\": 9980,\n      \"jealous\": 9981,\n      \"photograph\": 9982,\n      \"continent\": 9983,\n      \"dorothy\": 9984,\n      \"marina\": 9985,\n      \"doc\": 9986,\n      \"excess\": 9987,\n      \"holden\": 9988,\n      \"allegations\": 9989,\n      \"explaining\": 9990,\n      \"stack\": 9991,\n      \"avoiding\": 9992,\n      \"lance\": 9993,\n      \"storyline\": 9994,\n      \"majesty\": 9995,\n      \"poorly\": 9996,\n      \"spike\": 9997,\n      \"dos\": 9998,\n      \"bradford\": 9999,\n      \"raven\": 10000,\n      \"travis\": 10001,\n      \"classics\": 10002,\n      \"proven\": 10003,\n      \"voltage\": 10004,\n      \"pillow\": 10005,\n      \"fists\": 10006,\n      \"butt\": 10007,\n      \"1842\": 10008,\n      \"interpreted\": 10009,\n      \"##car\": 10010,\n      \"1839\": 10011,\n      \"gage\": 10012,\n      \"telegraph\": 10013,\n      \"lens\": 10014,\n      \"promising\": 10015,\n      \"expelled\": 10016,\n      \"casual\": 10017,\n      \"collector\": 10018,\n      \"zones\": 10019,\n      \"##min\": 10020,\n      \"silly\": 10021,\n      \"nintendo\": 10022,\n      \"##kh\": 10023,\n      \"##bra\": 10024,\n      \"downstairs\": 10025,\n      \"chef\": 10026,\n      \"suspicious\": 10027,\n      \"afl\": 10028,\n      \"flies\": 10029,\n      \"vacant\": 10030,\n      \"uganda\": 10031,\n      \"pregnancy\": 10032,\n      \"condemned\": 10033,\n      \"lutheran\": 10034,\n      \"estimates\": 10035,\n      \"cheap\": 10036,\n      \"decree\": 10037,\n      \"saxon\": 10038,\n      \"proximity\": 10039,\n      \"stripped\": 10040,\n      \"idiot\": 10041,\n      \"deposits\": 10042,\n      \"contrary\": 10043,\n      \"presenter\": 10044,\n      \"magnus\": 10045,\n      \"glacier\": 10046,\n      \"im\": 10047,\n      \"offense\": 10048,\n      \"edwin\": 10049,\n      \"##ori\": 10050,\n      \"upright\": 10051,\n      \"##long\": 10052,\n      \"bolt\": 10053,\n      \"##ois\": 10054,\n      \"toss\": 10055,\n      \"geographical\": 10056,\n      \"##izes\": 10057,\n      \"environments\": 10058,\n      \"delicate\": 10059,\n      \"marking\": 10060,\n      \"abstract\": 10061,\n      \"xavier\": 10062,\n      \"nails\": 10063,\n      \"windsor\": 10064,\n      \"plantation\": 10065,\n      \"occurring\": 10066,\n      \"equity\": 10067,\n      \"saskatchewan\": 10068,\n      \"fears\": 10069,\n      \"drifted\": 10070,\n      \"sequences\": 10071,\n      \"vegetation\": 10072,\n      \"revolt\": 10073,\n      \"##stic\": 10074,\n      \"1843\": 10075,\n      \"sooner\": 10076,\n      \"fusion\": 10077,\n      \"opposing\": 10078,\n      \"nato\": 10079,\n      \"skating\": 10080,\n      \"1836\": 10081,\n      \"secretly\": 10082,\n      \"ruin\": 10083,\n      \"lease\": 10084,\n      \"##oc\": 10085,\n      \"edit\": 10086,\n      \"##nne\": 10087,\n      \"flora\": 10088,\n      \"anxiety\": 10089,\n      \"ruby\": 10090,\n      \"##ological\": 10091,\n      \"##mia\": 10092,\n      \"tel\": 10093,\n      \"bout\": 10094,\n      \"taxi\": 10095,\n      \"emmy\": 10096,\n      \"frost\": 10097,\n      \"rainbow\": 10098,\n      \"compounds\": 10099,\n      \"foundations\": 10100,\n      \"rainfall\": 10101,\n      \"assassination\": 10102,\n      \"nightmare\": 10103,\n      \"dominican\": 10104,\n      \"##win\": 10105,\n      \"achievements\": 10106,\n      \"deserve\": 10107,\n      \"orlando\": 10108,\n      \"intact\": 10109,\n      \"armenia\": 10110,\n      \"##nte\": 10111,\n      \"calgary\": 10112,\n      \"valentine\": 10113,\n      \"106\": 10114,\n      \"marion\": 10115,\n      \"proclaimed\": 10116,\n      \"theodore\": 10117,\n      \"bells\": 10118,\n      \"courtyard\": 10119,\n      \"thigh\": 10120,\n      \"gonzalez\": 10121,\n      \"console\": 10122,\n      \"troop\": 10123,\n      \"minimal\": 10124,\n      \"monte\": 10125,\n      \"everyday\": 10126,\n      \"##ence\": 10127,\n      \"##if\": 10128,\n      \"supporter\": 10129,\n      \"terrorism\": 10130,\n      \"buck\": 10131,\n      \"openly\": 10132,\n      \"presbyterian\": 10133,\n      \"activists\": 10134,\n      \"carpet\": 10135,\n      \"##iers\": 10136,\n      \"rubbing\": 10137,\n      \"uprising\": 10138,\n      \"##yi\": 10139,\n      \"cute\": 10140,\n      \"conceived\": 10141,\n      \"legally\": 10142,\n      \"##cht\": 10143,\n      \"millennium\": 10144,\n      \"cello\": 10145,\n      \"velocity\": 10146,\n      \"ji\": 10147,\n      \"rescued\": 10148,\n      \"cardiff\": 10149,\n      \"1835\": 10150,\n      \"rex\": 10151,\n      \"concentrate\": 10152,\n      \"senators\": 10153,\n      \"beard\": 10154,\n      \"rendered\": 10155,\n      \"glowing\": 10156,\n      \"battalions\": 10157,\n      \"scouts\": 10158,\n      \"competitors\": 10159,\n      \"sculptor\": 10160,\n      \"catalogue\": 10161,\n      \"arctic\": 10162,\n      \"ion\": 10163,\n      \"raja\": 10164,\n      \"bicycle\": 10165,\n      \"wow\": 10166,\n      \"glancing\": 10167,\n      \"lawn\": 10168,\n      \"##woman\": 10169,\n      \"gentleman\": 10170,\n      \"lighthouse\": 10171,\n      \"publish\": 10172,\n      \"predicted\": 10173,\n      \"calculated\": 10174,\n      \"##val\": 10175,\n      \"variants\": 10176,\n      \"##gne\": 10177,\n      \"strain\": 10178,\n      \"##ui\": 10179,\n      \"winston\": 10180,\n      \"deceased\": 10181,\n      \"##nus\": 10182,\n      \"touchdowns\": 10183,\n      \"brady\": 10184,\n      \"caleb\": 10185,\n      \"sinking\": 10186,\n      \"echoed\": 10187,\n      \"crush\": 10188,\n      \"hon\": 10189,\n      \"blessed\": 10190,\n      \"protagonist\": 10191,\n      \"hayes\": 10192,\n      \"endangered\": 10193,\n      \"magnitude\": 10194,\n      \"editors\": 10195,\n      \"##tine\": 10196,\n      \"estimate\": 10197,\n      \"responsibilities\": 10198,\n      \"##mel\": 10199,\n      \"backup\": 10200,\n      \"laying\": 10201,\n      \"consumed\": 10202,\n      \"sealed\": 10203,\n      \"zurich\": 10204,\n      \"lovers\": 10205,\n      \"frustrated\": 10206,\n      \"##eau\": 10207,\n      \"ahmed\": 10208,\n      \"kicking\": 10209,\n      \"mit\": 10210,\n      \"treasurer\": 10211,\n      \"1832\": 10212,\n      \"biblical\": 10213,\n      \"refuse\": 10214,\n      \"terrified\": 10215,\n      \"pump\": 10216,\n      \"agrees\": 10217,\n      \"genuine\": 10218,\n      \"imprisonment\": 10219,\n      \"refuses\": 10220,\n      \"plymouth\": 10221,\n      \"##hen\": 10222,\n      \"lou\": 10223,\n      \"##nen\": 10224,\n      \"tara\": 10225,\n      \"trembling\": 10226,\n      \"antarctic\": 10227,\n      \"ton\": 10228,\n      \"learns\": 10229,\n      \"##tas\": 10230,\n      \"crap\": 10231,\n      \"crucial\": 10232,\n      \"faction\": 10233,\n      \"atop\": 10234,\n      \"##borough\": 10235,\n      \"wrap\": 10236,\n      \"lancaster\": 10237,\n      \"odds\": 10238,\n      \"hopkins\": 10239,\n      \"erik\": 10240,\n      \"lyon\": 10241,\n      \"##eon\": 10242,\n      \"bros\": 10243,\n      \"##ode\": 10244,\n      \"snap\": 10245,\n      \"locality\": 10246,\n      \"tips\": 10247,\n      \"empress\": 10248,\n      \"crowned\": 10249,\n      \"cal\": 10250,\n      \"acclaimed\": 10251,\n      \"chuckled\": 10252,\n      \"##ory\": 10253,\n      \"clara\": 10254,\n      \"sends\": 10255,\n      \"mild\": 10256,\n      \"towel\": 10257,\n      \"##fl\": 10258,\n      \"##day\": 10259,\n      \"##а\": 10260,\n      \"wishing\": 10261,\n      \"assuming\": 10262,\n      \"interviewed\": 10263,\n      \"##bal\": 10264,\n      \"##die\": 10265,\n      \"interactions\": 10266,\n      \"eden\": 10267,\n      \"cups\": 10268,\n      \"helena\": 10269,\n      \"##lf\": 10270,\n      \"indie\": 10271,\n      \"beck\": 10272,\n      \"##fire\": 10273,\n      \"batteries\": 10274,\n      \"filipino\": 10275,\n      \"wizard\": 10276,\n      \"parted\": 10277,\n      \"##lam\": 10278,\n      \"traces\": 10279,\n      \"##born\": 10280,\n      \"rows\": 10281,\n      \"idol\": 10282,\n      \"albany\": 10283,\n      \"delegates\": 10284,\n      \"##ees\": 10285,\n      \"##sar\": 10286,\n      \"discussions\": 10287,\n      \"##ex\": 10288,\n      \"notre\": 10289,\n      \"instructed\": 10290,\n      \"belgrade\": 10291,\n      \"highways\": 10292,\n      \"suggestion\": 10293,\n      \"lauren\": 10294,\n      \"possess\": 10295,\n      \"orientation\": 10296,\n      \"alexandria\": 10297,\n      \"abdul\": 10298,\n      \"beats\": 10299,\n      \"salary\": 10300,\n      \"reunion\": 10301,\n      \"ludwig\": 10302,\n      \"alright\": 10303,\n      \"wagner\": 10304,\n      \"intimate\": 10305,\n      \"pockets\": 10306,\n      \"slovenia\": 10307,\n      \"hugged\": 10308,\n      \"brighton\": 10309,\n      \"merchants\": 10310,\n      \"cruel\": 10311,\n      \"stole\": 10312,\n      \"trek\": 10313,\n      \"slopes\": 10314,\n      \"repairs\": 10315,\n      \"enrollment\": 10316,\n      \"politically\": 10317,\n      \"underlying\": 10318,\n      \"promotional\": 10319,\n      \"counting\": 10320,\n      \"boeing\": 10321,\n      \"##bb\": 10322,\n      \"isabella\": 10323,\n      \"naming\": 10324,\n      \"##и\": 10325,\n      \"keen\": 10326,\n      \"bacteria\": 10327,\n      \"listing\": 10328,\n      \"separately\": 10329,\n      \"belfast\": 10330,\n      \"ussr\": 10331,\n      \"450\": 10332,\n      \"lithuanian\": 10333,\n      \"anybody\": 10334,\n      \"ribs\": 10335,\n      \"sphere\": 10336,\n      \"martinez\": 10337,\n      \"cock\": 10338,\n      \"embarrassed\": 10339,\n      \"proposals\": 10340,\n      \"fragments\": 10341,\n      \"nationals\": 10342,\n      \"##fs\": 10343,\n      \"##wski\": 10344,\n      \"premises\": 10345,\n      \"fin\": 10346,\n      \"1500\": 10347,\n      \"alpine\": 10348,\n      \"matched\": 10349,\n      \"freely\": 10350,\n      \"bounded\": 10351,\n      \"jace\": 10352,\n      \"sleeve\": 10353,\n      \"##af\": 10354,\n      \"gaming\": 10355,\n      \"pier\": 10356,\n      \"populated\": 10357,\n      \"evident\": 10358,\n      \"##like\": 10359,\n      \"frances\": 10360,\n      \"flooded\": 10361,\n      \"##dle\": 10362,\n      \"frightened\": 10363,\n      \"pour\": 10364,\n      \"trainer\": 10365,\n      \"framed\": 10366,\n      \"visitor\": 10367,\n      \"challenging\": 10368,\n      \"pig\": 10369,\n      \"wickets\": 10370,\n      \"##fold\": 10371,\n      \"infected\": 10372,\n      \"email\": 10373,\n      \"##pes\": 10374,\n      \"arose\": 10375,\n      \"##aw\": 10376,\n      \"reward\": 10377,\n      \"ecuador\": 10378,\n      \"oblast\": 10379,\n      \"vale\": 10380,\n      \"ch\": 10381,\n      \"shuttle\": 10382,\n      \"##usa\": 10383,\n      \"bach\": 10384,\n      \"rankings\": 10385,\n      \"forbidden\": 10386,\n      \"cornwall\": 10387,\n      \"accordance\": 10388,\n      \"salem\": 10389,\n      \"consumers\": 10390,\n      \"bruno\": 10391,\n      \"fantastic\": 10392,\n      \"toes\": 10393,\n      \"machinery\": 10394,\n      \"resolved\": 10395,\n      \"julius\": 10396,\n      \"remembering\": 10397,\n      \"propaganda\": 10398,\n      \"iceland\": 10399,\n      \"bombardment\": 10400,\n      \"tide\": 10401,\n      \"contacts\": 10402,\n      \"wives\": 10403,\n      \"##rah\": 10404,\n      \"concerto\": 10405,\n      \"macdonald\": 10406,\n      \"albania\": 10407,\n      \"implement\": 10408,\n      \"daisy\": 10409,\n      \"tapped\": 10410,\n      \"sudan\": 10411,\n      \"helmet\": 10412,\n      \"angela\": 10413,\n      \"mistress\": 10414,\n      \"##lic\": 10415,\n      \"crop\": 10416,\n      \"sunk\": 10417,\n      \"finest\": 10418,\n      \"##craft\": 10419,\n      \"hostile\": 10420,\n      \"##ute\": 10421,\n      \"##tsu\": 10422,\n      \"boxer\": 10423,\n      \"fr\": 10424,\n      \"paths\": 10425,\n      \"adjusted\": 10426,\n      \"habit\": 10427,\n      \"ballot\": 10428,\n      \"supervision\": 10429,\n      \"soprano\": 10430,\n      \"##zen\": 10431,\n      \"bullets\": 10432,\n      \"wicked\": 10433,\n      \"sunset\": 10434,\n      \"regiments\": 10435,\n      \"disappear\": 10436,\n      \"lamp\": 10437,\n      \"performs\": 10438,\n      \"app\": 10439,\n      \"##gia\": 10440,\n      \"##oa\": 10441,\n      \"rabbit\": 10442,\n      \"digging\": 10443,\n      \"incidents\": 10444,\n      \"entries\": 10445,\n      \"##cion\": 10446,\n      \"dishes\": 10447,\n      \"##oi\": 10448,\n      \"introducing\": 10449,\n      \"##ati\": 10450,\n      \"##fied\": 10451,\n      \"freshman\": 10452,\n      \"slot\": 10453,\n      \"jill\": 10454,\n      \"tackles\": 10455,\n      \"baroque\": 10456,\n      \"backs\": 10457,\n      \"##iest\": 10458,\n      \"lone\": 10459,\n      \"sponsor\": 10460,\n      \"destiny\": 10461,\n      \"altogether\": 10462,\n      \"convert\": 10463,\n      \"##aro\": 10464,\n      \"consensus\": 10465,\n      \"shapes\": 10466,\n      \"demonstration\": 10467,\n      \"basically\": 10468,\n      \"feminist\": 10469,\n      \"auction\": 10470,\n      \"artifacts\": 10471,\n      \"##bing\": 10472,\n      \"strongest\": 10473,\n      \"twitter\": 10474,\n      \"halifax\": 10475,\n      \"2019\": 10476,\n      \"allmusic\": 10477,\n      \"mighty\": 10478,\n      \"smallest\": 10479,\n      \"precise\": 10480,\n      \"alexandra\": 10481,\n      \"viola\": 10482,\n      \"##los\": 10483,\n      \"##ille\": 10484,\n      \"manuscripts\": 10485,\n      \"##illo\": 10486,\n      \"dancers\": 10487,\n      \"ari\": 10488,\n      \"managers\": 10489,\n      \"monuments\": 10490,\n      \"blades\": 10491,\n      \"barracks\": 10492,\n      \"springfield\": 10493,\n      \"maiden\": 10494,\n      \"consolidated\": 10495,\n      \"electron\": 10496,\n      \"##end\": 10497,\n      \"berry\": 10498,\n      \"airing\": 10499,\n      \"wheat\": 10500,\n      \"nobel\": 10501,\n      \"inclusion\": 10502,\n      \"blair\": 10503,\n      \"payments\": 10504,\n      \"geography\": 10505,\n      \"bee\": 10506,\n      \"cc\": 10507,\n      \"eleanor\": 10508,\n      \"react\": 10509,\n      \"##hurst\": 10510,\n      \"afc\": 10511,\n      \"manitoba\": 10512,\n      \"##yu\": 10513,\n      \"su\": 10514,\n      \"lineup\": 10515,\n      \"fitness\": 10516,\n      \"recreational\": 10517,\n      \"investments\": 10518,\n      \"airborne\": 10519,\n      \"disappointment\": 10520,\n      \"##dis\": 10521,\n      \"edmonton\": 10522,\n      \"viewing\": 10523,\n      \"##row\": 10524,\n      \"renovation\": 10525,\n      \"##cast\": 10526,\n      \"infant\": 10527,\n      \"bankruptcy\": 10528,\n      \"roses\": 10529,\n      \"aftermath\": 10530,\n      \"pavilion\": 10531,\n      \"##yer\": 10532,\n      \"carpenter\": 10533,\n      \"withdrawal\": 10534,\n      \"ladder\": 10535,\n      \"##hy\": 10536,\n      \"discussing\": 10537,\n      \"popped\": 10538,\n      \"reliable\": 10539,\n      \"agreements\": 10540,\n      \"rochester\": 10541,\n      \"##abad\": 10542,\n      \"curves\": 10543,\n      \"bombers\": 10544,\n      \"220\": 10545,\n      \"rao\": 10546,\n      \"reverend\": 10547,\n      \"decreased\": 10548,\n      \"choosing\": 10549,\n      \"107\": 10550,\n      \"stiff\": 10551,\n      \"consulting\": 10552,\n      \"naples\": 10553,\n      \"crawford\": 10554,\n      \"tracy\": 10555,\n      \"ka\": 10556,\n      \"ribbon\": 10557,\n      \"cops\": 10558,\n      \"##lee\": 10559,\n      \"crushed\": 10560,\n      \"deciding\": 10561,\n      \"unified\": 10562,\n      \"teenager\": 10563,\n      \"accepting\": 10564,\n      \"flagship\": 10565,\n      \"explorer\": 10566,\n      \"poles\": 10567,\n      \"sanchez\": 10568,\n      \"inspection\": 10569,\n      \"revived\": 10570,\n      \"skilled\": 10571,\n      \"induced\": 10572,\n      \"exchanged\": 10573,\n      \"flee\": 10574,\n      \"locals\": 10575,\n      \"tragedy\": 10576,\n      \"swallow\": 10577,\n      \"loading\": 10578,\n      \"hanna\": 10579,\n      \"demonstrate\": 10580,\n      \"##ela\": 10581,\n      \"salvador\": 10582,\n      \"flown\": 10583,\n      \"contestants\": 10584,\n      \"civilization\": 10585,\n      \"##ines\": 10586,\n      \"wanna\": 10587,\n      \"rhodes\": 10588,\n      \"fletcher\": 10589,\n      \"hector\": 10590,\n      \"knocking\": 10591,\n      \"considers\": 10592,\n      \"##ough\": 10593,\n      \"nash\": 10594,\n      \"mechanisms\": 10595,\n      \"sensed\": 10596,\n      \"mentally\": 10597,\n      \"walt\": 10598,\n      \"unclear\": 10599,\n      \"##eus\": 10600,\n      \"renovated\": 10601,\n      \"madame\": 10602,\n      \"##cks\": 10603,\n      \"crews\": 10604,\n      \"governmental\": 10605,\n      \"##hin\": 10606,\n      \"undertaken\": 10607,\n      \"monkey\": 10608,\n      \"##ben\": 10609,\n      \"##ato\": 10610,\n      \"fatal\": 10611,\n      \"armored\": 10612,\n      \"copa\": 10613,\n      \"caves\": 10614,\n      \"governance\": 10615,\n      \"grasp\": 10616,\n      \"perception\": 10617,\n      \"certification\": 10618,\n      \"froze\": 10619,\n      \"damp\": 10620,\n      \"tugged\": 10621,\n      \"wyoming\": 10622,\n      \"##rg\": 10623,\n      \"##ero\": 10624,\n      \"newman\": 10625,\n      \"##lor\": 10626,\n      \"nerves\": 10627,\n      \"curiosity\": 10628,\n      \"graph\": 10629,\n      \"115\": 10630,\n      \"##ami\": 10631,\n      \"withdraw\": 10632,\n      \"tunnels\": 10633,\n      \"dull\": 10634,\n      \"meredith\": 10635,\n      \"moss\": 10636,\n      \"exhibits\": 10637,\n      \"neighbors\": 10638,\n      \"communicate\": 10639,\n      \"accuracy\": 10640,\n      \"explored\": 10641,\n      \"raiders\": 10642,\n      \"republicans\": 10643,\n      \"secular\": 10644,\n      \"kat\": 10645,\n      \"superman\": 10646,\n      \"penny\": 10647,\n      \"criticised\": 10648,\n      \"##tch\": 10649,\n      \"freed\": 10650,\n      \"update\": 10651,\n      \"conviction\": 10652,\n      \"wade\": 10653,\n      \"ham\": 10654,\n      \"likewise\": 10655,\n      \"delegation\": 10656,\n      \"gotta\": 10657,\n      \"doll\": 10658,\n      \"promises\": 10659,\n      \"technological\": 10660,\n      \"myth\": 10661,\n      \"nationality\": 10662,\n      \"resolve\": 10663,\n      \"convent\": 10664,\n      \"##mark\": 10665,\n      \"sharon\": 10666,\n      \"dig\": 10667,\n      \"sip\": 10668,\n      \"coordinator\": 10669,\n      \"entrepreneur\": 10670,\n      \"fold\": 10671,\n      \"##dine\": 10672,\n      \"capability\": 10673,\n      \"councillor\": 10674,\n      \"synonym\": 10675,\n      \"blown\": 10676,\n      \"swan\": 10677,\n      \"cursed\": 10678,\n      \"1815\": 10679,\n      \"jonas\": 10680,\n      \"haired\": 10681,\n      \"sofa\": 10682,\n      \"canvas\": 10683,\n      \"keeper\": 10684,\n      \"rivalry\": 10685,\n      \"##hart\": 10686,\n      \"rapper\": 10687,\n      \"speedway\": 10688,\n      \"swords\": 10689,\n      \"postal\": 10690,\n      \"maxwell\": 10691,\n      \"estonia\": 10692,\n      \"potter\": 10693,\n      \"recurring\": 10694,\n      \"##nn\": 10695,\n      \"##ave\": 10696,\n      \"errors\": 10697,\n      \"##oni\": 10698,\n      \"cognitive\": 10699,\n      \"1834\": 10700,\n      \"##²\": 10701,\n      \"claws\": 10702,\n      \"nadu\": 10703,\n      \"roberto\": 10704,\n      \"bce\": 10705,\n      \"wrestler\": 10706,\n      \"ellie\": 10707,\n      \"##ations\": 10708,\n      \"infinite\": 10709,\n      \"ink\": 10710,\n      \"##tia\": 10711,\n      \"presumably\": 10712,\n      \"finite\": 10713,\n      \"staircase\": 10714,\n      \"108\": 10715,\n      \"noel\": 10716,\n      \"patricia\": 10717,\n      \"nacional\": 10718,\n      \"##cation\": 10719,\n      \"chill\": 10720,\n      \"eternal\": 10721,\n      \"tu\": 10722,\n      \"preventing\": 10723,\n      \"prussia\": 10724,\n      \"fossil\": 10725,\n      \"limbs\": 10726,\n      \"##logist\": 10727,\n      \"ernst\": 10728,\n      \"frog\": 10729,\n      \"perez\": 10730,\n      \"rene\": 10731,\n      \"##ace\": 10732,\n      \"pizza\": 10733,\n      \"prussian\": 10734,\n      \"##ios\": 10735,\n      \"##vy\": 10736,\n      \"molecules\": 10737,\n      \"regulatory\": 10738,\n      \"answering\": 10739,\n      \"opinions\": 10740,\n      \"sworn\": 10741,\n      \"lengths\": 10742,\n      \"supposedly\": 10743,\n      \"hypothesis\": 10744,\n      \"upward\": 10745,\n      \"habitats\": 10746,\n      \"seating\": 10747,\n      \"ancestors\": 10748,\n      \"drank\": 10749,\n      \"yield\": 10750,\n      \"hd\": 10751,\n      \"synthesis\": 10752,\n      \"researcher\": 10753,\n      \"modest\": 10754,\n      \"##var\": 10755,\n      \"mothers\": 10756,\n      \"peered\": 10757,\n      \"voluntary\": 10758,\n      \"homeland\": 10759,\n      \"##the\": 10760,\n      \"acclaim\": 10761,\n      \"##igan\": 10762,\n      \"static\": 10763,\n      \"valve\": 10764,\n      \"luxembourg\": 10765,\n      \"alto\": 10766,\n      \"carroll\": 10767,\n      \"fe\": 10768,\n      \"receptor\": 10769,\n      \"norton\": 10770,\n      \"ambulance\": 10771,\n      \"##tian\": 10772,\n      \"johnston\": 10773,\n      \"catholics\": 10774,\n      \"depicting\": 10775,\n      \"jointly\": 10776,\n      \"elephant\": 10777,\n      \"gloria\": 10778,\n      \"mentor\": 10779,\n      \"badge\": 10780,\n      \"ahmad\": 10781,\n      \"distinguish\": 10782,\n      \"remarked\": 10783,\n      \"councils\": 10784,\n      \"precisely\": 10785,\n      \"allison\": 10786,\n      \"advancing\": 10787,\n      \"detection\": 10788,\n      \"crowded\": 10789,\n      \"##10\": 10790,\n      \"cooperative\": 10791,\n      \"ankle\": 10792,\n      \"mercedes\": 10793,\n      \"dagger\": 10794,\n      \"surrendered\": 10795,\n      \"pollution\": 10796,\n      \"commit\": 10797,\n      \"subway\": 10798,\n      \"jeffrey\": 10799,\n      \"lesson\": 10800,\n      \"sculptures\": 10801,\n      \"provider\": 10802,\n      \"##fication\": 10803,\n      \"membrane\": 10804,\n      \"timothy\": 10805,\n      \"rectangular\": 10806,\n      \"fiscal\": 10807,\n      \"heating\": 10808,\n      \"teammate\": 10809,\n      \"basket\": 10810,\n      \"particle\": 10811,\n      \"anonymous\": 10812,\n      \"deployment\": 10813,\n      \"##ple\": 10814,\n      \"missiles\": 10815,\n      \"courthouse\": 10816,\n      \"proportion\": 10817,\n      \"shoe\": 10818,\n      \"sec\": 10819,\n      \"##ller\": 10820,\n      \"complaints\": 10821,\n      \"forbes\": 10822,\n      \"blacks\": 10823,\n      \"abandon\": 10824,\n      \"remind\": 10825,\n      \"sizes\": 10826,\n      \"overwhelming\": 10827,\n      \"autobiography\": 10828,\n      \"natalie\": 10829,\n      \"##awa\": 10830,\n      \"risks\": 10831,\n      \"contestant\": 10832,\n      \"countryside\": 10833,\n      \"babies\": 10834,\n      \"scorer\": 10835,\n      \"invaded\": 10836,\n      \"enclosed\": 10837,\n      \"proceed\": 10838,\n      \"hurling\": 10839,\n      \"disorders\": 10840,\n      \"##cu\": 10841,\n      \"reflecting\": 10842,\n      \"continuously\": 10843,\n      \"cruiser\": 10844,\n      \"graduates\": 10845,\n      \"freeway\": 10846,\n      \"investigated\": 10847,\n      \"ore\": 10848,\n      \"deserved\": 10849,\n      \"maid\": 10850,\n      \"blocking\": 10851,\n      \"phillip\": 10852,\n      \"jorge\": 10853,\n      \"shakes\": 10854,\n      \"dove\": 10855,\n      \"mann\": 10856,\n      \"variables\": 10857,\n      \"lacked\": 10858,\n      \"burden\": 10859,\n      \"accompanying\": 10860,\n      \"que\": 10861,\n      \"consistently\": 10862,\n      \"organizing\": 10863,\n      \"provisional\": 10864,\n      \"complained\": 10865,\n      \"endless\": 10866,\n      \"##rm\": 10867,\n      \"tubes\": 10868,\n      \"juice\": 10869,\n      \"georges\": 10870,\n      \"krishna\": 10871,\n      \"mick\": 10872,\n      \"labels\": 10873,\n      \"thriller\": 10874,\n      \"##uch\": 10875,\n      \"laps\": 10876,\n      \"arcade\": 10877,\n      \"sage\": 10878,\n      \"snail\": 10879,\n      \"##table\": 10880,\n      \"shannon\": 10881,\n      \"fi\": 10882,\n      \"laurence\": 10883,\n      \"seoul\": 10884,\n      \"vacation\": 10885,\n      \"presenting\": 10886,\n      \"hire\": 10887,\n      \"churchill\": 10888,\n      \"surprisingly\": 10889,\n      \"prohibited\": 10890,\n      \"savannah\": 10891,\n      \"technically\": 10892,\n      \"##oli\": 10893,\n      \"170\": 10894,\n      \"##lessly\": 10895,\n      \"testimony\": 10896,\n      \"suited\": 10897,\n      \"speeds\": 10898,\n      \"toys\": 10899,\n      \"romans\": 10900,\n      \"mlb\": 10901,\n      \"flowering\": 10902,\n      \"measurement\": 10903,\n      \"talented\": 10904,\n      \"kay\": 10905,\n      \"settings\": 10906,\n      \"charleston\": 10907,\n      \"expectations\": 10908,\n      \"shattered\": 10909,\n      \"achieving\": 10910,\n      \"triumph\": 10911,\n      \"ceremonies\": 10912,\n      \"portsmouth\": 10913,\n      \"lanes\": 10914,\n      \"mandatory\": 10915,\n      \"loser\": 10916,\n      \"stretching\": 10917,\n      \"cologne\": 10918,\n      \"realizes\": 10919,\n      \"seventy\": 10920,\n      \"cornell\": 10921,\n      \"careers\": 10922,\n      \"webb\": 10923,\n      \"##ulating\": 10924,\n      \"americas\": 10925,\n      \"budapest\": 10926,\n      \"ava\": 10927,\n      \"suspicion\": 10928,\n      \"##ison\": 10929,\n      \"yo\": 10930,\n      \"conrad\": 10931,\n      \"##hai\": 10932,\n      \"sterling\": 10933,\n      \"jessie\": 10934,\n      \"rector\": 10935,\n      \"##az\": 10936,\n      \"1831\": 10937,\n      \"transform\": 10938,\n      \"organize\": 10939,\n      \"loans\": 10940,\n      \"christine\": 10941,\n      \"volcanic\": 10942,\n      \"warrant\": 10943,\n      \"slender\": 10944,\n      \"summers\": 10945,\n      \"subfamily\": 10946,\n      \"newer\": 10947,\n      \"danced\": 10948,\n      \"dynamics\": 10949,\n      \"rhine\": 10950,\n      \"proceeds\": 10951,\n      \"heinrich\": 10952,\n      \"gastropod\": 10953,\n      \"commands\": 10954,\n      \"sings\": 10955,\n      \"facilitate\": 10956,\n      \"easter\": 10957,\n      \"ra\": 10958,\n      \"positioned\": 10959,\n      \"responses\": 10960,\n      \"expense\": 10961,\n      \"fruits\": 10962,\n      \"yanked\": 10963,\n      \"imported\": 10964,\n      \"25th\": 10965,\n      \"velvet\": 10966,\n      \"vic\": 10967,\n      \"primitive\": 10968,\n      \"tribune\": 10969,\n      \"baldwin\": 10970,\n      \"neighbourhood\": 10971,\n      \"donna\": 10972,\n      \"rip\": 10973,\n      \"hay\": 10974,\n      \"pr\": 10975,\n      \"##uro\": 10976,\n      \"1814\": 10977,\n      \"espn\": 10978,\n      \"welcomed\": 10979,\n      \"##aria\": 10980,\n      \"qualifier\": 10981,\n      \"glare\": 10982,\n      \"highland\": 10983,\n      \"timing\": 10984,\n      \"##cted\": 10985,\n      \"shells\": 10986,\n      \"eased\": 10987,\n      \"geometry\": 10988,\n      \"louder\": 10989,\n      \"exciting\": 10990,\n      \"slovakia\": 10991,\n      \"##sion\": 10992,\n      \"##iz\": 10993,\n      \"##lot\": 10994,\n      \"savings\": 10995,\n      \"prairie\": 10996,\n      \"##ques\": 10997,\n      \"marching\": 10998,\n      \"rafael\": 10999,\n      \"tonnes\": 11000,\n      \"##lled\": 11001,\n      \"curtain\": 11002,\n      \"preceding\": 11003,\n      \"shy\": 11004,\n      \"heal\": 11005,\n      \"greene\": 11006,\n      \"worthy\": 11007,\n      \"##pot\": 11008,\n      \"detachment\": 11009,\n      \"bury\": 11010,\n      \"sherman\": 11011,\n      \"##eck\": 11012,\n      \"reinforced\": 11013,\n      \"seeks\": 11014,\n      \"bottles\": 11015,\n      \"contracted\": 11016,\n      \"duchess\": 11017,\n      \"outfit\": 11018,\n      \"walsh\": 11019,\n      \"##sc\": 11020,\n      \"mickey\": 11021,\n      \"##ase\": 11022,\n      \"geoffrey\": 11023,\n      \"archer\": 11024,\n      \"squeeze\": 11025,\n      \"dawson\": 11026,\n      \"eliminate\": 11027,\n      \"invention\": 11028,\n      \"##enberg\": 11029,\n      \"neal\": 11030,\n      \"##eth\": 11031,\n      \"stance\": 11032,\n      \"dealer\": 11033,\n      \"coral\": 11034,\n      \"maple\": 11035,\n      \"retire\": 11036,\n      \"polo\": 11037,\n      \"simplified\": 11038,\n      \"##ht\": 11039,\n      \"1833\": 11040,\n      \"hid\": 11041,\n      \"watts\": 11042,\n      \"backwards\": 11043,\n      \"jules\": 11044,\n      \"##oke\": 11045,\n      \"genesis\": 11046,\n      \"mt\": 11047,\n      \"frames\": 11048,\n      \"rebounds\": 11049,\n      \"burma\": 11050,\n      \"woodland\": 11051,\n      \"moist\": 11052,\n      \"santos\": 11053,\n      \"whispers\": 11054,\n      \"drained\": 11055,\n      \"subspecies\": 11056,\n      \"##aa\": 11057,\n      \"streaming\": 11058,\n      \"ulster\": 11059,\n      \"burnt\": 11060,\n      \"correspondence\": 11061,\n      \"maternal\": 11062,\n      \"gerard\": 11063,\n      \"denis\": 11064,\n      \"stealing\": 11065,\n      \"##load\": 11066,\n      \"genius\": 11067,\n      \"duchy\": 11068,\n      \"##oria\": 11069,\n      \"inaugurated\": 11070,\n      \"momentum\": 11071,\n      \"suits\": 11072,\n      \"placement\": 11073,\n      \"sovereign\": 11074,\n      \"clause\": 11075,\n      \"thames\": 11076,\n      \"##hara\": 11077,\n      \"confederation\": 11078,\n      \"reservation\": 11079,\n      \"sketch\": 11080,\n      \"yankees\": 11081,\n      \"lets\": 11082,\n      \"rotten\": 11083,\n      \"charm\": 11084,\n      \"hal\": 11085,\n      \"verses\": 11086,\n      \"ultra\": 11087,\n      \"commercially\": 11088,\n      \"dot\": 11089,\n      \"salon\": 11090,\n      \"citation\": 11091,\n      \"adopt\": 11092,\n      \"winnipeg\": 11093,\n      \"mist\": 11094,\n      \"allocated\": 11095,\n      \"cairo\": 11096,\n      \"##boy\": 11097,\n      \"jenkins\": 11098,\n      \"interference\": 11099,\n      \"objectives\": 11100,\n      \"##wind\": 11101,\n      \"1820\": 11102,\n      \"portfolio\": 11103,\n      \"armoured\": 11104,\n      \"sectors\": 11105,\n      \"##eh\": 11106,\n      \"initiatives\": 11107,\n      \"##world\": 11108,\n      \"integrity\": 11109,\n      \"exercises\": 11110,\n      \"robe\": 11111,\n      \"tap\": 11112,\n      \"ab\": 11113,\n      \"gazed\": 11114,\n      \"##tones\": 11115,\n      \"distracted\": 11116,\n      \"rulers\": 11117,\n      \"111\": 11118,\n      \"favorable\": 11119,\n      \"jerome\": 11120,\n      \"tended\": 11121,\n      \"cart\": 11122,\n      \"factories\": 11123,\n      \"##eri\": 11124,\n      \"diplomat\": 11125,\n      \"valued\": 11126,\n      \"gravel\": 11127,\n      \"charitable\": 11128,\n      \"##try\": 11129,\n      \"calvin\": 11130,\n      \"exploring\": 11131,\n      \"chang\": 11132,\n      \"shepherd\": 11133,\n      \"terrace\": 11134,\n      \"pdf\": 11135,\n      \"pupil\": 11136,\n      \"##ural\": 11137,\n      \"reflects\": 11138,\n      \"ups\": 11139,\n      \"##rch\": 11140,\n      \"governors\": 11141,\n      \"shelf\": 11142,\n      \"depths\": 11143,\n      \"##nberg\": 11144,\n      \"trailed\": 11145,\n      \"crest\": 11146,\n      \"tackle\": 11147,\n      \"##nian\": 11148,\n      \"##ats\": 11149,\n      \"hatred\": 11150,\n      \"##kai\": 11151,\n      \"clare\": 11152,\n      \"makers\": 11153,\n      \"ethiopia\": 11154,\n      \"longtime\": 11155,\n      \"detected\": 11156,\n      \"embedded\": 11157,\n      \"lacking\": 11158,\n      \"slapped\": 11159,\n      \"rely\": 11160,\n      \"thomson\": 11161,\n      \"anticipation\": 11162,\n      \"iso\": 11163,\n      \"morton\": 11164,\n      \"successive\": 11165,\n      \"agnes\": 11166,\n      \"screenwriter\": 11167,\n      \"straightened\": 11168,\n      \"philippe\": 11169,\n      \"playwright\": 11170,\n      \"haunted\": 11171,\n      \"licence\": 11172,\n      \"iris\": 11173,\n      \"intentions\": 11174,\n      \"sutton\": 11175,\n      \"112\": 11176,\n      \"logical\": 11177,\n      \"correctly\": 11178,\n      \"##weight\": 11179,\n      \"branded\": 11180,\n      \"licked\": 11181,\n      \"tipped\": 11182,\n      \"silva\": 11183,\n      \"ricky\": 11184,\n      \"narrator\": 11185,\n      \"requests\": 11186,\n      \"##ents\": 11187,\n      \"greeted\": 11188,\n      \"supernatural\": 11189,\n      \"cow\": 11190,\n      \"##wald\": 11191,\n      \"lung\": 11192,\n      \"refusing\": 11193,\n      \"employer\": 11194,\n      \"strait\": 11195,\n      \"gaelic\": 11196,\n      \"liner\": 11197,\n      \"##piece\": 11198,\n      \"zoe\": 11199,\n      \"sabha\": 11200,\n      \"##mba\": 11201,\n      \"driveway\": 11202,\n      \"harvest\": 11203,\n      \"prints\": 11204,\n      \"bates\": 11205,\n      \"reluctantly\": 11206,\n      \"threshold\": 11207,\n      \"algebra\": 11208,\n      \"ira\": 11209,\n      \"wherever\": 11210,\n      \"coupled\": 11211,\n      \"240\": 11212,\n      \"assumption\": 11213,\n      \"picks\": 11214,\n      \"##air\": 11215,\n      \"designers\": 11216,\n      \"raids\": 11217,\n      \"gentlemen\": 11218,\n      \"##ean\": 11219,\n      \"roller\": 11220,\n      \"blowing\": 11221,\n      \"leipzig\": 11222,\n      \"locks\": 11223,\n      \"screw\": 11224,\n      \"dressing\": 11225,\n      \"strand\": 11226,\n      \"##lings\": 11227,\n      \"scar\": 11228,\n      \"dwarf\": 11229,\n      \"depicts\": 11230,\n      \"##nu\": 11231,\n      \"nods\": 11232,\n      \"##mine\": 11233,\n      \"differ\": 11234,\n      \"boris\": 11235,\n      \"##eur\": 11236,\n      \"yuan\": 11237,\n      \"flip\": 11238,\n      \"##gie\": 11239,\n      \"mob\": 11240,\n      \"invested\": 11241,\n      \"questioning\": 11242,\n      \"applying\": 11243,\n      \"##ture\": 11244,\n      \"shout\": 11245,\n      \"##sel\": 11246,\n      \"gameplay\": 11247,\n      \"blamed\": 11248,\n      \"illustrations\": 11249,\n      \"bothered\": 11250,\n      \"weakness\": 11251,\n      \"rehabilitation\": 11252,\n      \"##of\": 11253,\n      \"##zes\": 11254,\n      \"envelope\": 11255,\n      \"rumors\": 11256,\n      \"miners\": 11257,\n      \"leicester\": 11258,\n      \"subtle\": 11259,\n      \"kerry\": 11260,\n      \"##ico\": 11261,\n      \"ferguson\": 11262,\n      \"##fu\": 11263,\n      \"premiership\": 11264,\n      \"ne\": 11265,\n      \"##cat\": 11266,\n      \"bengali\": 11267,\n      \"prof\": 11268,\n      \"catches\": 11269,\n      \"remnants\": 11270,\n      \"dana\": 11271,\n      \"##rily\": 11272,\n      \"shouting\": 11273,\n      \"presidents\": 11274,\n      \"baltic\": 11275,\n      \"ought\": 11276,\n      \"ghosts\": 11277,\n      \"dances\": 11278,\n      \"sailors\": 11279,\n      \"shirley\": 11280,\n      \"fancy\": 11281,\n      \"dominic\": 11282,\n      \"##bie\": 11283,\n      \"madonna\": 11284,\n      \"##rick\": 11285,\n      \"bark\": 11286,\n      \"buttons\": 11287,\n      \"gymnasium\": 11288,\n      \"ashes\": 11289,\n      \"liver\": 11290,\n      \"toby\": 11291,\n      \"oath\": 11292,\n      \"providence\": 11293,\n      \"doyle\": 11294,\n      \"evangelical\": 11295,\n      \"nixon\": 11296,\n      \"cement\": 11297,\n      \"carnegie\": 11298,\n      \"embarked\": 11299,\n      \"hatch\": 11300,\n      \"surroundings\": 11301,\n      \"guarantee\": 11302,\n      \"needing\": 11303,\n      \"pirate\": 11304,\n      \"essence\": 11305,\n      \"##bee\": 11306,\n      \"filter\": 11307,\n      \"crane\": 11308,\n      \"hammond\": 11309,\n      \"projected\": 11310,\n      \"immune\": 11311,\n      \"percy\": 11312,\n      \"twelfth\": 11313,\n      \"##ult\": 11314,\n      \"regent\": 11315,\n      \"doctoral\": 11316,\n      \"damon\": 11317,\n      \"mikhail\": 11318,\n      \"##ichi\": 11319,\n      \"lu\": 11320,\n      \"critically\": 11321,\n      \"elect\": 11322,\n      \"realised\": 11323,\n      \"abortion\": 11324,\n      \"acute\": 11325,\n      \"screening\": 11326,\n      \"mythology\": 11327,\n      \"steadily\": 11328,\n      \"##fc\": 11329,\n      \"frown\": 11330,\n      \"nottingham\": 11331,\n      \"kirk\": 11332,\n      \"wa\": 11333,\n      \"minneapolis\": 11334,\n      \"##rra\": 11335,\n      \"module\": 11336,\n      \"algeria\": 11337,\n      \"mc\": 11338,\n      \"nautical\": 11339,\n      \"encounters\": 11340,\n      \"surprising\": 11341,\n      \"statues\": 11342,\n      \"availability\": 11343,\n      \"shirts\": 11344,\n      \"pie\": 11345,\n      \"alma\": 11346,\n      \"brows\": 11347,\n      \"munster\": 11348,\n      \"mack\": 11349,\n      \"soup\": 11350,\n      \"crater\": 11351,\n      \"tornado\": 11352,\n      \"sanskrit\": 11353,\n      \"cedar\": 11354,\n      \"explosive\": 11355,\n      \"bordered\": 11356,\n      \"dixon\": 11357,\n      \"planets\": 11358,\n      \"stamp\": 11359,\n      \"exam\": 11360,\n      \"happily\": 11361,\n      \"##bble\": 11362,\n      \"carriers\": 11363,\n      \"kidnapped\": 11364,\n      \"##vis\": 11365,\n      \"accommodation\": 11366,\n      \"emigrated\": 11367,\n      \"##met\": 11368,\n      \"knockout\": 11369,\n      \"correspondent\": 11370,\n      \"violation\": 11371,\n      \"profits\": 11372,\n      \"peaks\": 11373,\n      \"lang\": 11374,\n      \"specimen\": 11375,\n      \"agenda\": 11376,\n      \"ancestry\": 11377,\n      \"pottery\": 11378,\n      \"spelling\": 11379,\n      \"equations\": 11380,\n      \"obtaining\": 11381,\n      \"ki\": 11382,\n      \"linking\": 11383,\n      \"1825\": 11384,\n      \"debris\": 11385,\n      \"asylum\": 11386,\n      \"##20\": 11387,\n      \"buddhism\": 11388,\n      \"teddy\": 11389,\n      \"##ants\": 11390,\n      \"gazette\": 11391,\n      \"##nger\": 11392,\n      \"##sse\": 11393,\n      \"dental\": 11394,\n      \"eligibility\": 11395,\n      \"utc\": 11396,\n      \"fathers\": 11397,\n      \"averaged\": 11398,\n      \"zimbabwe\": 11399,\n      \"francesco\": 11400,\n      \"coloured\": 11401,\n      \"hissed\": 11402,\n      \"translator\": 11403,\n      \"lynch\": 11404,\n      \"mandate\": 11405,\n      \"humanities\": 11406,\n      \"mackenzie\": 11407,\n      \"uniforms\": 11408,\n      \"lin\": 11409,\n      \"##iana\": 11410,\n      \"##gio\": 11411,\n      \"asset\": 11412,\n      \"mhz\": 11413,\n      \"fitting\": 11414,\n      \"samantha\": 11415,\n      \"genera\": 11416,\n      \"wei\": 11417,\n      \"rim\": 11418,\n      \"beloved\": 11419,\n      \"shark\": 11420,\n      \"riot\": 11421,\n      \"entities\": 11422,\n      \"expressions\": 11423,\n      \"indo\": 11424,\n      \"carmen\": 11425,\n      \"slipping\": 11426,\n      \"owing\": 11427,\n      \"abbot\": 11428,\n      \"neighbor\": 11429,\n      \"sidney\": 11430,\n      \"##av\": 11431,\n      \"rats\": 11432,\n      \"recommendations\": 11433,\n      \"encouraging\": 11434,\n      \"squadrons\": 11435,\n      \"anticipated\": 11436,\n      \"commanders\": 11437,\n      \"conquered\": 11438,\n      \"##oto\": 11439,\n      \"donations\": 11440,\n      \"diagnosed\": 11441,\n      \"##mond\": 11442,\n      \"divide\": 11443,\n      \"##iva\": 11444,\n      \"guessed\": 11445,\n      \"decoration\": 11446,\n      \"vernon\": 11447,\n      \"auditorium\": 11448,\n      \"revelation\": 11449,\n      \"conversations\": 11450,\n      \"##kers\": 11451,\n      \"##power\": 11452,\n      \"herzegovina\": 11453,\n      \"dash\": 11454,\n      \"alike\": 11455,\n      \"protested\": 11456,\n      \"lateral\": 11457,\n      \"herman\": 11458,\n      \"accredited\": 11459,\n      \"mg\": 11460,\n      \"##gent\": 11461,\n      \"freeman\": 11462,\n      \"mel\": 11463,\n      \"fiji\": 11464,\n      \"crow\": 11465,\n      \"crimson\": 11466,\n      \"##rine\": 11467,\n      \"livestock\": 11468,\n      \"##pped\": 11469,\n      \"humanitarian\": 11470,\n      \"bored\": 11471,\n      \"oz\": 11472,\n      \"whip\": 11473,\n      \"##lene\": 11474,\n      \"##ali\": 11475,\n      \"legitimate\": 11476,\n      \"alter\": 11477,\n      \"grinning\": 11478,\n      \"spelled\": 11479,\n      \"anxious\": 11480,\n      \"oriental\": 11481,\n      \"wesley\": 11482,\n      \"##nin\": 11483,\n      \"##hole\": 11484,\n      \"carnival\": 11485,\n      \"controller\": 11486,\n      \"detect\": 11487,\n      \"##ssa\": 11488,\n      \"bowed\": 11489,\n      \"educator\": 11490,\n      \"kosovo\": 11491,\n      \"macedonia\": 11492,\n      \"##sin\": 11493,\n      \"occupy\": 11494,\n      \"mastering\": 11495,\n      \"stephanie\": 11496,\n      \"janeiro\": 11497,\n      \"para\": 11498,\n      \"unaware\": 11499,\n      \"nurses\": 11500,\n      \"noon\": 11501,\n      \"135\": 11502,\n      \"cam\": 11503,\n      \"hopefully\": 11504,\n      \"ranger\": 11505,\n      \"combine\": 11506,\n      \"sociology\": 11507,\n      \"polar\": 11508,\n      \"rica\": 11509,\n      \"##eer\": 11510,\n      \"neill\": 11511,\n      \"##sman\": 11512,\n      \"holocaust\": 11513,\n      \"##ip\": 11514,\n      \"doubled\": 11515,\n      \"lust\": 11516,\n      \"1828\": 11517,\n      \"109\": 11518,\n      \"decent\": 11519,\n      \"cooling\": 11520,\n      \"unveiled\": 11521,\n      \"##card\": 11522,\n      \"1829\": 11523,\n      \"nsw\": 11524,\n      \"homer\": 11525,\n      \"chapman\": 11526,\n      \"meyer\": 11527,\n      \"##gin\": 11528,\n      \"dive\": 11529,\n      \"mae\": 11530,\n      \"reagan\": 11531,\n      \"expertise\": 11532,\n      \"##gled\": 11533,\n      \"darwin\": 11534,\n      \"brooke\": 11535,\n      \"sided\": 11536,\n      \"prosecution\": 11537,\n      \"investigating\": 11538,\n      \"comprised\": 11539,\n      \"petroleum\": 11540,\n      \"genres\": 11541,\n      \"reluctant\": 11542,\n      \"differently\": 11543,\n      \"trilogy\": 11544,\n      \"johns\": 11545,\n      \"vegetables\": 11546,\n      \"corpse\": 11547,\n      \"highlighted\": 11548,\n      \"lounge\": 11549,\n      \"pension\": 11550,\n      \"unsuccessfully\": 11551,\n      \"elegant\": 11552,\n      \"aided\": 11553,\n      \"ivory\": 11554,\n      \"beatles\": 11555,\n      \"amelia\": 11556,\n      \"cain\": 11557,\n      \"dubai\": 11558,\n      \"sunny\": 11559,\n      \"immigrant\": 11560,\n      \"babe\": 11561,\n      \"click\": 11562,\n      \"##nder\": 11563,\n      \"underwater\": 11564,\n      \"pepper\": 11565,\n      \"combining\": 11566,\n      \"mumbled\": 11567,\n      \"atlas\": 11568,\n      \"horns\": 11569,\n      \"accessed\": 11570,\n      \"ballad\": 11571,\n      \"physicians\": 11572,\n      \"homeless\": 11573,\n      \"gestured\": 11574,\n      \"rpm\": 11575,\n      \"freak\": 11576,\n      \"louisville\": 11577,\n      \"corporations\": 11578,\n      \"patriots\": 11579,\n      \"prizes\": 11580,\n      \"rational\": 11581,\n      \"warn\": 11582,\n      \"modes\": 11583,\n      \"decorative\": 11584,\n      \"overnight\": 11585,\n      \"din\": 11586,\n      \"troubled\": 11587,\n      \"phantom\": 11588,\n      \"##ort\": 11589,\n      \"monarch\": 11590,\n      \"sheer\": 11591,\n      \"##dorf\": 11592,\n      \"generals\": 11593,\n      \"guidelines\": 11594,\n      \"organs\": 11595,\n      \"addresses\": 11596,\n      \"##zon\": 11597,\n      \"enhance\": 11598,\n      \"curling\": 11599,\n      \"parishes\": 11600,\n      \"cord\": 11601,\n      \"##kie\": 11602,\n      \"linux\": 11603,\n      \"caesar\": 11604,\n      \"deutsche\": 11605,\n      \"bavaria\": 11606,\n      \"##bia\": 11607,\n      \"coleman\": 11608,\n      \"cyclone\": 11609,\n      \"##eria\": 11610,\n      \"bacon\": 11611,\n      \"petty\": 11612,\n      \"##yama\": 11613,\n      \"##old\": 11614,\n      \"hampton\": 11615,\n      \"diagnosis\": 11616,\n      \"1824\": 11617,\n      \"throws\": 11618,\n      \"complexity\": 11619,\n      \"rita\": 11620,\n      \"disputed\": 11621,\n      \"##₃\": 11622,\n      \"pablo\": 11623,\n      \"##sch\": 11624,\n      \"marketed\": 11625,\n      \"trafficking\": 11626,\n      \"##ulus\": 11627,\n      \"examine\": 11628,\n      \"plague\": 11629,\n      \"formats\": 11630,\n      \"##oh\": 11631,\n      \"vault\": 11632,\n      \"faithful\": 11633,\n      \"##bourne\": 11634,\n      \"webster\": 11635,\n      \"##ox\": 11636,\n      \"highlights\": 11637,\n      \"##ient\": 11638,\n      \"##ann\": 11639,\n      \"phones\": 11640,\n      \"vacuum\": 11641,\n      \"sandwich\": 11642,\n      \"modeling\": 11643,\n      \"##gated\": 11644,\n      \"bolivia\": 11645,\n      \"clergy\": 11646,\n      \"qualities\": 11647,\n      \"isabel\": 11648,\n      \"##nas\": 11649,\n      \"##ars\": 11650,\n      \"wears\": 11651,\n      \"screams\": 11652,\n      \"reunited\": 11653,\n      \"annoyed\": 11654,\n      \"bra\": 11655,\n      \"##ancy\": 11656,\n      \"##rate\": 11657,\n      \"differential\": 11658,\n      \"transmitter\": 11659,\n      \"tattoo\": 11660,\n      \"container\": 11661,\n      \"poker\": 11662,\n      \"##och\": 11663,\n      \"excessive\": 11664,\n      \"resides\": 11665,\n      \"cowboys\": 11666,\n      \"##tum\": 11667,\n      \"augustus\": 11668,\n      \"trash\": 11669,\n      \"providers\": 11670,\n      \"statute\": 11671,\n      \"retreated\": 11672,\n      \"balcony\": 11673,\n      \"reversed\": 11674,\n      \"void\": 11675,\n      \"storey\": 11676,\n      \"preceded\": 11677,\n      \"masses\": 11678,\n      \"leap\": 11679,\n      \"laughs\": 11680,\n      \"neighborhoods\": 11681,\n      \"wards\": 11682,\n      \"schemes\": 11683,\n      \"falcon\": 11684,\n      \"santo\": 11685,\n      \"battlefield\": 11686,\n      \"pad\": 11687,\n      \"ronnie\": 11688,\n      \"thread\": 11689,\n      \"lesbian\": 11690,\n      \"venus\": 11691,\n      \"##dian\": 11692,\n      \"beg\": 11693,\n      \"sandstone\": 11694,\n      \"daylight\": 11695,\n      \"punched\": 11696,\n      \"gwen\": 11697,\n      \"analog\": 11698,\n      \"stroked\": 11699,\n      \"wwe\": 11700,\n      \"acceptable\": 11701,\n      \"measurements\": 11702,\n      \"dec\": 11703,\n      \"toxic\": 11704,\n      \"##kel\": 11705,\n      \"adequate\": 11706,\n      \"surgical\": 11707,\n      \"economist\": 11708,\n      \"parameters\": 11709,\n      \"varsity\": 11710,\n      \"##sberg\": 11711,\n      \"quantity\": 11712,\n      \"ella\": 11713,\n      \"##chy\": 11714,\n      \"##rton\": 11715,\n      \"countess\": 11716,\n      \"generating\": 11717,\n      \"precision\": 11718,\n      \"diamonds\": 11719,\n      \"expressway\": 11720,\n      \"ga\": 11721,\n      \"##ı\": 11722,\n      \"1821\": 11723,\n      \"uruguay\": 11724,\n      \"talents\": 11725,\n      \"galleries\": 11726,\n      \"expenses\": 11727,\n      \"scanned\": 11728,\n      \"colleague\": 11729,\n      \"outlets\": 11730,\n      \"ryder\": 11731,\n      \"lucien\": 11732,\n      \"##ila\": 11733,\n      \"paramount\": 11734,\n      \"##bon\": 11735,\n      \"syracuse\": 11736,\n      \"dim\": 11737,\n      \"fangs\": 11738,\n      \"gown\": 11739,\n      \"sweep\": 11740,\n      \"##sie\": 11741,\n      \"toyota\": 11742,\n      \"missionaries\": 11743,\n      \"websites\": 11744,\n      \"##nsis\": 11745,\n      \"sentences\": 11746,\n      \"adviser\": 11747,\n      \"val\": 11748,\n      \"trademark\": 11749,\n      \"spells\": 11750,\n      \"##plane\": 11751,\n      \"patience\": 11752,\n      \"starter\": 11753,\n      \"slim\": 11754,\n      \"##borg\": 11755,\n      \"toe\": 11756,\n      \"incredibly\": 11757,\n      \"shoots\": 11758,\n      \"elliot\": 11759,\n      \"nobility\": 11760,\n      \"##wyn\": 11761,\n      \"cowboy\": 11762,\n      \"endorsed\": 11763,\n      \"gardner\": 11764,\n      \"tendency\": 11765,\n      \"persuaded\": 11766,\n      \"organisms\": 11767,\n      \"emissions\": 11768,\n      \"kazakhstan\": 11769,\n      \"amused\": 11770,\n      \"boring\": 11771,\n      \"chips\": 11772,\n      \"themed\": 11773,\n      \"##hand\": 11774,\n      \"llc\": 11775,\n      \"constantinople\": 11776,\n      \"chasing\": 11777,\n      \"systematic\": 11778,\n      \"guatemala\": 11779,\n      \"borrowed\": 11780,\n      \"erin\": 11781,\n      \"carey\": 11782,\n      \"##hard\": 11783,\n      \"highlands\": 11784,\n      \"struggles\": 11785,\n      \"1810\": 11786,\n      \"##ifying\": 11787,\n      \"##ced\": 11788,\n      \"wong\": 11789,\n      \"exceptions\": 11790,\n      \"develops\": 11791,\n      \"enlarged\": 11792,\n      \"kindergarten\": 11793,\n      \"castro\": 11794,\n      \"##ern\": 11795,\n      \"##rina\": 11796,\n      \"leigh\": 11797,\n      \"zombie\": 11798,\n      \"juvenile\": 11799,\n      \"##most\": 11800,\n      \"consul\": 11801,\n      \"##nar\": 11802,\n      \"sailor\": 11803,\n      \"hyde\": 11804,\n      \"clarence\": 11805,\n      \"intensive\": 11806,\n      \"pinned\": 11807,\n      \"nasty\": 11808,\n      \"useless\": 11809,\n      \"jung\": 11810,\n      \"clayton\": 11811,\n      \"stuffed\": 11812,\n      \"exceptional\": 11813,\n      \"ix\": 11814,\n      \"apostolic\": 11815,\n      \"230\": 11816,\n      \"transactions\": 11817,\n      \"##dge\": 11818,\n      \"exempt\": 11819,\n      \"swinging\": 11820,\n      \"cove\": 11821,\n      \"religions\": 11822,\n      \"##ash\": 11823,\n      \"shields\": 11824,\n      \"dairy\": 11825,\n      \"bypass\": 11826,\n      \"190\": 11827,\n      \"pursuing\": 11828,\n      \"bug\": 11829,\n      \"joyce\": 11830,\n      \"bombay\": 11831,\n      \"chassis\": 11832,\n      \"southampton\": 11833,\n      \"chat\": 11834,\n      \"interact\": 11835,\n      \"redesignated\": 11836,\n      \"##pen\": 11837,\n      \"nascar\": 11838,\n      \"pray\": 11839,\n      \"salmon\": 11840,\n      \"rigid\": 11841,\n      \"regained\": 11842,\n      \"malaysian\": 11843,\n      \"grim\": 11844,\n      \"publicity\": 11845,\n      \"constituted\": 11846,\n      \"capturing\": 11847,\n      \"toilet\": 11848,\n      \"delegate\": 11849,\n      \"purely\": 11850,\n      \"tray\": 11851,\n      \"drift\": 11852,\n      \"loosely\": 11853,\n      \"striker\": 11854,\n      \"weakened\": 11855,\n      \"trinidad\": 11856,\n      \"mitch\": 11857,\n      \"itv\": 11858,\n      \"defines\": 11859,\n      \"transmitted\": 11860,\n      \"ming\": 11861,\n      \"scarlet\": 11862,\n      \"nodding\": 11863,\n      \"fitzgerald\": 11864,\n      \"fu\": 11865,\n      \"narrowly\": 11866,\n      \"sp\": 11867,\n      \"tooth\": 11868,\n      \"standings\": 11869,\n      \"virtue\": 11870,\n      \"##₁\": 11871,\n      \"##wara\": 11872,\n      \"##cting\": 11873,\n      \"chateau\": 11874,\n      \"gloves\": 11875,\n      \"lid\": 11876,\n      \"##nel\": 11877,\n      \"hurting\": 11878,\n      \"conservatory\": 11879,\n      \"##pel\": 11880,\n      \"sinclair\": 11881,\n      \"reopened\": 11882,\n      \"sympathy\": 11883,\n      \"nigerian\": 11884,\n      \"strode\": 11885,\n      \"advocated\": 11886,\n      \"optional\": 11887,\n      \"chronic\": 11888,\n      \"discharge\": 11889,\n      \"##rc\": 11890,\n      \"suck\": 11891,\n      \"compatible\": 11892,\n      \"laurel\": 11893,\n      \"stella\": 11894,\n      \"shi\": 11895,\n      \"fails\": 11896,\n      \"wage\": 11897,\n      \"dodge\": 11898,\n      \"128\": 11899,\n      \"informal\": 11900,\n      \"sorts\": 11901,\n      \"levi\": 11902,\n      \"buddha\": 11903,\n      \"villagers\": 11904,\n      \"##aka\": 11905,\n      \"chronicles\": 11906,\n      \"heavier\": 11907,\n      \"summoned\": 11908,\n      \"gateway\": 11909,\n      \"3000\": 11910,\n      \"eleventh\": 11911,\n      \"jewelry\": 11912,\n      \"translations\": 11913,\n      \"accordingly\": 11914,\n      \"seas\": 11915,\n      \"##ency\": 11916,\n      \"fiber\": 11917,\n      \"pyramid\": 11918,\n      \"cubic\": 11919,\n      \"dragging\": 11920,\n      \"##ista\": 11921,\n      \"caring\": 11922,\n      \"##ops\": 11923,\n      \"android\": 11924,\n      \"contacted\": 11925,\n      \"lunar\": 11926,\n      \"##dt\": 11927,\n      \"kai\": 11928,\n      \"lisbon\": 11929,\n      \"patted\": 11930,\n      \"1826\": 11931,\n      \"sacramento\": 11932,\n      \"theft\": 11933,\n      \"madagascar\": 11934,\n      \"subtropical\": 11935,\n      \"disputes\": 11936,\n      \"ta\": 11937,\n      \"holidays\": 11938,\n      \"piper\": 11939,\n      \"willow\": 11940,\n      \"mare\": 11941,\n      \"cane\": 11942,\n      \"itunes\": 11943,\n      \"newfoundland\": 11944,\n      \"benny\": 11945,\n      \"companions\": 11946,\n      \"dong\": 11947,\n      \"raj\": 11948,\n      \"observe\": 11949,\n      \"roar\": 11950,\n      \"charming\": 11951,\n      \"plaque\": 11952,\n      \"tibetan\": 11953,\n      \"fossils\": 11954,\n      \"enacted\": 11955,\n      \"manning\": 11956,\n      \"bubble\": 11957,\n      \"tina\": 11958,\n      \"tanzania\": 11959,\n      \"##eda\": 11960,\n      \"##hir\": 11961,\n      \"funk\": 11962,\n      \"swamp\": 11963,\n      \"deputies\": 11964,\n      \"cloak\": 11965,\n      \"ufc\": 11966,\n      \"scenario\": 11967,\n      \"par\": 11968,\n      \"scratch\": 11969,\n      \"metals\": 11970,\n      \"anthem\": 11971,\n      \"guru\": 11972,\n      \"engaging\": 11973,\n      \"specially\": 11974,\n      \"##boat\": 11975,\n      \"dialects\": 11976,\n      \"nineteen\": 11977,\n      \"cecil\": 11978,\n      \"duet\": 11979,\n      \"disability\": 11980,\n      \"messenger\": 11981,\n      \"unofficial\": 11982,\n      \"##lies\": 11983,\n      \"defunct\": 11984,\n      \"eds\": 11985,\n      \"moonlight\": 11986,\n      \"drainage\": 11987,\n      \"surname\": 11988,\n      \"puzzle\": 11989,\n      \"honda\": 11990,\n      \"switching\": 11991,\n      \"conservatives\": 11992,\n      \"mammals\": 11993,\n      \"knox\": 11994,\n      \"broadcaster\": 11995,\n      \"sidewalk\": 11996,\n      \"cope\": 11997,\n      \"##ried\": 11998,\n      \"benson\": 11999,\n      \"princes\": 12000,\n      \"peterson\": 12001,\n      \"##sal\": 12002,\n      \"bedford\": 12003,\n      \"sharks\": 12004,\n      \"eli\": 12005,\n      \"wreck\": 12006,\n      \"alberto\": 12007,\n      \"gasp\": 12008,\n      \"archaeology\": 12009,\n      \"lgbt\": 12010,\n      \"teaches\": 12011,\n      \"securities\": 12012,\n      \"madness\": 12013,\n      \"compromise\": 12014,\n      \"waving\": 12015,\n      \"coordination\": 12016,\n      \"davidson\": 12017,\n      \"visions\": 12018,\n      \"leased\": 12019,\n      \"possibilities\": 12020,\n      \"eighty\": 12021,\n      \"jun\": 12022,\n      \"fernandez\": 12023,\n      \"enthusiasm\": 12024,\n      \"assassin\": 12025,\n      \"sponsorship\": 12026,\n      \"reviewer\": 12027,\n      \"kingdoms\": 12028,\n      \"estonian\": 12029,\n      \"laboratories\": 12030,\n      \"##fy\": 12031,\n      \"##nal\": 12032,\n      \"applies\": 12033,\n      \"verb\": 12034,\n      \"celebrations\": 12035,\n      \"##zzo\": 12036,\n      \"rowing\": 12037,\n      \"lightweight\": 12038,\n      \"sadness\": 12039,\n      \"submit\": 12040,\n      \"mvp\": 12041,\n      \"balanced\": 12042,\n      \"dude\": 12043,\n      \"##vas\": 12044,\n      \"explicitly\": 12045,\n      \"metric\": 12046,\n      \"magnificent\": 12047,\n      \"mound\": 12048,\n      \"brett\": 12049,\n      \"mohammad\": 12050,\n      \"mistakes\": 12051,\n      \"irregular\": 12052,\n      \"##hing\": 12053,\n      \"##ass\": 12054,\n      \"sanders\": 12055,\n      \"betrayed\": 12056,\n      \"shipped\": 12057,\n      \"surge\": 12058,\n      \"##enburg\": 12059,\n      \"reporters\": 12060,\n      \"termed\": 12061,\n      \"georg\": 12062,\n      \"pity\": 12063,\n      \"verbal\": 12064,\n      \"bulls\": 12065,\n      \"abbreviated\": 12066,\n      \"enabling\": 12067,\n      \"appealed\": 12068,\n      \"##are\": 12069,\n      \"##atic\": 12070,\n      \"sicily\": 12071,\n      \"sting\": 12072,\n      \"heel\": 12073,\n      \"sweetheart\": 12074,\n      \"bart\": 12075,\n      \"spacecraft\": 12076,\n      \"brutal\": 12077,\n      \"monarchy\": 12078,\n      \"##tter\": 12079,\n      \"aberdeen\": 12080,\n      \"cameo\": 12081,\n      \"diane\": 12082,\n      \"##ub\": 12083,\n      \"survivor\": 12084,\n      \"clyde\": 12085,\n      \"##aries\": 12086,\n      \"complaint\": 12087,\n      \"##makers\": 12088,\n      \"clarinet\": 12089,\n      \"delicious\": 12090,\n      \"chilean\": 12091,\n      \"karnataka\": 12092,\n      \"coordinates\": 12093,\n      \"1818\": 12094,\n      \"panties\": 12095,\n      \"##rst\": 12096,\n      \"pretending\": 12097,\n      \"ar\": 12098,\n      \"dramatically\": 12099,\n      \"kiev\": 12100,\n      \"bella\": 12101,\n      \"tends\": 12102,\n      \"distances\": 12103,\n      \"113\": 12104,\n      \"catalog\": 12105,\n      \"launching\": 12106,\n      \"instances\": 12107,\n      \"telecommunications\": 12108,\n      \"portable\": 12109,\n      \"lindsay\": 12110,\n      \"vatican\": 12111,\n      \"##eim\": 12112,\n      \"angles\": 12113,\n      \"aliens\": 12114,\n      \"marker\": 12115,\n      \"stint\": 12116,\n      \"screens\": 12117,\n      \"bolton\": 12118,\n      \"##rne\": 12119,\n      \"judy\": 12120,\n      \"wool\": 12121,\n      \"benedict\": 12122,\n      \"plasma\": 12123,\n      \"europa\": 12124,\n      \"spark\": 12125,\n      \"imaging\": 12126,\n      \"filmmaker\": 12127,\n      \"swiftly\": 12128,\n      \"##een\": 12129,\n      \"contributor\": 12130,\n      \"##nor\": 12131,\n      \"opted\": 12132,\n      \"stamps\": 12133,\n      \"apologize\": 12134,\n      \"financing\": 12135,\n      \"butter\": 12136,\n      \"gideon\": 12137,\n      \"sophisticated\": 12138,\n      \"alignment\": 12139,\n      \"avery\": 12140,\n      \"chemicals\": 12141,\n      \"yearly\": 12142,\n      \"speculation\": 12143,\n      \"prominence\": 12144,\n      \"professionally\": 12145,\n      \"##ils\": 12146,\n      \"immortal\": 12147,\n      \"institutional\": 12148,\n      \"inception\": 12149,\n      \"wrists\": 12150,\n      \"identifying\": 12151,\n      \"tribunal\": 12152,\n      \"derives\": 12153,\n      \"gains\": 12154,\n      \"##wo\": 12155,\n      \"papal\": 12156,\n      \"preference\": 12157,\n      \"linguistic\": 12158,\n      \"vince\": 12159,\n      \"operative\": 12160,\n      \"brewery\": 12161,\n      \"##ont\": 12162,\n      \"unemployment\": 12163,\n      \"boyd\": 12164,\n      \"##ured\": 12165,\n      \"##outs\": 12166,\n      \"albeit\": 12167,\n      \"prophet\": 12168,\n      \"1813\": 12169,\n      \"bi\": 12170,\n      \"##rr\": 12171,\n      \"##face\": 12172,\n      \"##rad\": 12173,\n      \"quarterly\": 12174,\n      \"asteroid\": 12175,\n      \"cleaned\": 12176,\n      \"radius\": 12177,\n      \"temper\": 12178,\n      \"##llen\": 12179,\n      \"telugu\": 12180,\n      \"jerk\": 12181,\n      \"viscount\": 12182,\n      \"menu\": 12183,\n      \"##ote\": 12184,\n      \"glimpse\": 12185,\n      \"##aya\": 12186,\n      \"yacht\": 12187,\n      \"hawaiian\": 12188,\n      \"baden\": 12189,\n      \"##rl\": 12190,\n      \"laptop\": 12191,\n      \"readily\": 12192,\n      \"##gu\": 12193,\n      \"monetary\": 12194,\n      \"offshore\": 12195,\n      \"scots\": 12196,\n      \"watches\": 12197,\n      \"##yang\": 12198,\n      \"##arian\": 12199,\n      \"upgrade\": 12200,\n      \"needle\": 12201,\n      \"xbox\": 12202,\n      \"lea\": 12203,\n      \"encyclopedia\": 12204,\n      \"flank\": 12205,\n      \"fingertips\": 12206,\n      \"##pus\": 12207,\n      \"delight\": 12208,\n      \"teachings\": 12209,\n      \"confirm\": 12210,\n      \"roth\": 12211,\n      \"beaches\": 12212,\n      \"midway\": 12213,\n      \"winters\": 12214,\n      \"##iah\": 12215,\n      \"teasing\": 12216,\n      \"daytime\": 12217,\n      \"beverly\": 12218,\n      \"gambling\": 12219,\n      \"bonnie\": 12220,\n      \"##backs\": 12221,\n      \"regulated\": 12222,\n      \"clement\": 12223,\n      \"hermann\": 12224,\n      \"tricks\": 12225,\n      \"knot\": 12226,\n      \"##shing\": 12227,\n      \"##uring\": 12228,\n      \"##vre\": 12229,\n      \"detached\": 12230,\n      \"ecological\": 12231,\n      \"owed\": 12232,\n      \"specialty\": 12233,\n      \"byron\": 12234,\n      \"inventor\": 12235,\n      \"bats\": 12236,\n      \"stays\": 12237,\n      \"screened\": 12238,\n      \"unesco\": 12239,\n      \"midland\": 12240,\n      \"trim\": 12241,\n      \"affection\": 12242,\n      \"##ander\": 12243,\n      \"##rry\": 12244,\n      \"jess\": 12245,\n      \"thoroughly\": 12246,\n      \"feedback\": 12247,\n      \"##uma\": 12248,\n      \"chennai\": 12249,\n      \"strained\": 12250,\n      \"heartbeat\": 12251,\n      \"wrapping\": 12252,\n      \"overtime\": 12253,\n      \"pleaded\": 12254,\n      \"##sworth\": 12255,\n      \"mon\": 12256,\n      \"leisure\": 12257,\n      \"oclc\": 12258,\n      \"##tate\": 12259,\n      \"##ele\": 12260,\n      \"feathers\": 12261,\n      \"angelo\": 12262,\n      \"thirds\": 12263,\n      \"nuts\": 12264,\n      \"surveys\": 12265,\n      \"clever\": 12266,\n      \"gill\": 12267,\n      \"commentator\": 12268,\n      \"##dos\": 12269,\n      \"darren\": 12270,\n      \"rides\": 12271,\n      \"gibraltar\": 12272,\n      \"##nc\": 12273,\n      \"##mu\": 12274,\n      \"dissolution\": 12275,\n      \"dedication\": 12276,\n      \"shin\": 12277,\n      \"meals\": 12278,\n      \"saddle\": 12279,\n      \"elvis\": 12280,\n      \"reds\": 12281,\n      \"chaired\": 12282,\n      \"taller\": 12283,\n      \"appreciation\": 12284,\n      \"functioning\": 12285,\n      \"niece\": 12286,\n      \"favored\": 12287,\n      \"advocacy\": 12288,\n      \"robbie\": 12289,\n      \"criminals\": 12290,\n      \"suffolk\": 12291,\n      \"yugoslav\": 12292,\n      \"passport\": 12293,\n      \"constable\": 12294,\n      \"congressman\": 12295,\n      \"hastings\": 12296,\n      \"vera\": 12297,\n      \"##rov\": 12298,\n      \"consecrated\": 12299,\n      \"sparks\": 12300,\n      \"ecclesiastical\": 12301,\n      \"confined\": 12302,\n      \"##ovich\": 12303,\n      \"muller\": 12304,\n      \"floyd\": 12305,\n      \"nora\": 12306,\n      \"1822\": 12307,\n      \"paved\": 12308,\n      \"1827\": 12309,\n      \"cumberland\": 12310,\n      \"ned\": 12311,\n      \"saga\": 12312,\n      \"spiral\": 12313,\n      \"##flow\": 12314,\n      \"appreciated\": 12315,\n      \"yi\": 12316,\n      \"collaborative\": 12317,\n      \"treating\": 12318,\n      \"similarities\": 12319,\n      \"feminine\": 12320,\n      \"finishes\": 12321,\n      \"##ib\": 12322,\n      \"jade\": 12323,\n      \"import\": 12324,\n      \"##nse\": 12325,\n      \"##hot\": 12326,\n      \"champagne\": 12327,\n      \"mice\": 12328,\n      \"securing\": 12329,\n      \"celebrities\": 12330,\n      \"helsinki\": 12331,\n      \"attributes\": 12332,\n      \"##gos\": 12333,\n      \"cousins\": 12334,\n      \"phases\": 12335,\n      \"ache\": 12336,\n      \"lucia\": 12337,\n      \"gandhi\": 12338,\n      \"submission\": 12339,\n      \"vicar\": 12340,\n      \"spear\": 12341,\n      \"shine\": 12342,\n      \"tasmania\": 12343,\n      \"biting\": 12344,\n      \"detention\": 12345,\n      \"constitute\": 12346,\n      \"tighter\": 12347,\n      \"seasonal\": 12348,\n      \"##gus\": 12349,\n      \"terrestrial\": 12350,\n      \"matthews\": 12351,\n      \"##oka\": 12352,\n      \"effectiveness\": 12353,\n      \"parody\": 12354,\n      \"philharmonic\": 12355,\n      \"##onic\": 12356,\n      \"1816\": 12357,\n      \"strangers\": 12358,\n      \"encoded\": 12359,\n      \"consortium\": 12360,\n      \"guaranteed\": 12361,\n      \"regards\": 12362,\n      \"shifts\": 12363,\n      \"tortured\": 12364,\n      \"collision\": 12365,\n      \"supervisor\": 12366,\n      \"inform\": 12367,\n      \"broader\": 12368,\n      \"insight\": 12369,\n      \"theaters\": 12370,\n      \"armour\": 12371,\n      \"emeritus\": 12372,\n      \"blink\": 12373,\n      \"incorporates\": 12374,\n      \"mapping\": 12375,\n      \"##50\": 12376,\n      \"##ein\": 12377,\n      \"handball\": 12378,\n      \"flexible\": 12379,\n      \"##nta\": 12380,\n      \"substantially\": 12381,\n      \"generous\": 12382,\n      \"thief\": 12383,\n      \"##own\": 12384,\n      \"carr\": 12385,\n      \"loses\": 12386,\n      \"1793\": 12387,\n      \"prose\": 12388,\n      \"ucla\": 12389,\n      \"romeo\": 12390,\n      \"generic\": 12391,\n      \"metallic\": 12392,\n      \"realization\": 12393,\n      \"damages\": 12394,\n      \"mk\": 12395,\n      \"commissioners\": 12396,\n      \"zach\": 12397,\n      \"default\": 12398,\n      \"##ther\": 12399,\n      \"helicopters\": 12400,\n      \"lengthy\": 12401,\n      \"stems\": 12402,\n      \"spa\": 12403,\n      \"partnered\": 12404,\n      \"spectators\": 12405,\n      \"rogue\": 12406,\n      \"indication\": 12407,\n      \"penalties\": 12408,\n      \"teresa\": 12409,\n      \"1801\": 12410,\n      \"sen\": 12411,\n      \"##tric\": 12412,\n      \"dalton\": 12413,\n      \"##wich\": 12414,\n      \"irving\": 12415,\n      \"photographic\": 12416,\n      \"##vey\": 12417,\n      \"dell\": 12418,\n      \"deaf\": 12419,\n      \"peters\": 12420,\n      \"excluded\": 12421,\n      \"unsure\": 12422,\n      \"##vable\": 12423,\n      \"patterson\": 12424,\n      \"crawled\": 12425,\n      \"##zio\": 12426,\n      \"resided\": 12427,\n      \"whipped\": 12428,\n      \"latvia\": 12429,\n      \"slower\": 12430,\n      \"ecole\": 12431,\n      \"pipes\": 12432,\n      \"employers\": 12433,\n      \"maharashtra\": 12434,\n      \"comparable\": 12435,\n      \"va\": 12436,\n      \"textile\": 12437,\n      \"pageant\": 12438,\n      \"##gel\": 12439,\n      \"alphabet\": 12440,\n      \"binary\": 12441,\n      \"irrigation\": 12442,\n      \"chartered\": 12443,\n      \"choked\": 12444,\n      \"antoine\": 12445,\n      \"offs\": 12446,\n      \"waking\": 12447,\n      \"supplement\": 12448,\n      \"##wen\": 12449,\n      \"quantities\": 12450,\n      \"demolition\": 12451,\n      \"regain\": 12452,\n      \"locate\": 12453,\n      \"urdu\": 12454,\n      \"folks\": 12455,\n      \"alt\": 12456,\n      \"114\": 12457,\n      \"##mc\": 12458,\n      \"scary\": 12459,\n      \"andreas\": 12460,\n      \"whites\": 12461,\n      \"##ava\": 12462,\n      \"classrooms\": 12463,\n      \"mw\": 12464,\n      \"aesthetic\": 12465,\n      \"publishes\": 12466,\n      \"valleys\": 12467,\n      \"guides\": 12468,\n      \"cubs\": 12469,\n      \"johannes\": 12470,\n      \"bryant\": 12471,\n      \"conventions\": 12472,\n      \"affecting\": 12473,\n      \"##itt\": 12474,\n      \"drain\": 12475,\n      \"awesome\": 12476,\n      \"isolation\": 12477,\n      \"prosecutor\": 12478,\n      \"ambitious\": 12479,\n      \"apology\": 12480,\n      \"captive\": 12481,\n      \"downs\": 12482,\n      \"atmospheric\": 12483,\n      \"lorenzo\": 12484,\n      \"aisle\": 12485,\n      \"beef\": 12486,\n      \"foul\": 12487,\n      \"##onia\": 12488,\n      \"kidding\": 12489,\n      \"composite\": 12490,\n      \"disturbed\": 12491,\n      \"illusion\": 12492,\n      \"natives\": 12493,\n      \"##ffer\": 12494,\n      \"emi\": 12495,\n      \"rockets\": 12496,\n      \"riverside\": 12497,\n      \"wartime\": 12498,\n      \"painters\": 12499,\n      \"adolf\": 12500,\n      \"melted\": 12501,\n      \"##ail\": 12502,\n      \"uncertainty\": 12503,\n      \"simulation\": 12504,\n      \"hawks\": 12505,\n      \"progressed\": 12506,\n      \"meantime\": 12507,\n      \"builder\": 12508,\n      \"spray\": 12509,\n      \"breach\": 12510,\n      \"unhappy\": 12511,\n      \"regina\": 12512,\n      \"russians\": 12513,\n      \"##urg\": 12514,\n      \"determining\": 12515,\n      \"##tation\": 12516,\n      \"tram\": 12517,\n      \"1806\": 12518,\n      \"##quin\": 12519,\n      \"aging\": 12520,\n      \"##12\": 12521,\n      \"1823\": 12522,\n      \"garion\": 12523,\n      \"rented\": 12524,\n      \"mister\": 12525,\n      \"diaz\": 12526,\n      \"terminated\": 12527,\n      \"clip\": 12528,\n      \"1817\": 12529,\n      \"depend\": 12530,\n      \"nervously\": 12531,\n      \"disco\": 12532,\n      \"owe\": 12533,\n      \"defenders\": 12534,\n      \"shiva\": 12535,\n      \"notorious\": 12536,\n      \"disbelief\": 12537,\n      \"shiny\": 12538,\n      \"worcester\": 12539,\n      \"##gation\": 12540,\n      \"##yr\": 12541,\n      \"trailing\": 12542,\n      \"undertook\": 12543,\n      \"islander\": 12544,\n      \"belarus\": 12545,\n      \"limitations\": 12546,\n      \"watershed\": 12547,\n      \"fuller\": 12548,\n      \"overlooking\": 12549,\n      \"utilized\": 12550,\n      \"raphael\": 12551,\n      \"1819\": 12552,\n      \"synthetic\": 12553,\n      \"breakdown\": 12554,\n      \"klein\": 12555,\n      \"##nate\": 12556,\n      \"moaned\": 12557,\n      \"memoir\": 12558,\n      \"lamb\": 12559,\n      \"practicing\": 12560,\n      \"##erly\": 12561,\n      \"cellular\": 12562,\n      \"arrows\": 12563,\n      \"exotic\": 12564,\n      \"##graphy\": 12565,\n      \"witches\": 12566,\n      \"117\": 12567,\n      \"charted\": 12568,\n      \"rey\": 12569,\n      \"hut\": 12570,\n      \"hierarchy\": 12571,\n      \"subdivision\": 12572,\n      \"freshwater\": 12573,\n      \"giuseppe\": 12574,\n      \"aloud\": 12575,\n      \"reyes\": 12576,\n      \"qatar\": 12577,\n      \"marty\": 12578,\n      \"sideways\": 12579,\n      \"utterly\": 12580,\n      \"sexually\": 12581,\n      \"jude\": 12582,\n      \"prayers\": 12583,\n      \"mccarthy\": 12584,\n      \"softball\": 12585,\n      \"blend\": 12586,\n      \"damien\": 12587,\n      \"##gging\": 12588,\n      \"##metric\": 12589,\n      \"wholly\": 12590,\n      \"erupted\": 12591,\n      \"lebanese\": 12592,\n      \"negro\": 12593,\n      \"revenues\": 12594,\n      \"tasted\": 12595,\n      \"comparative\": 12596,\n      \"teamed\": 12597,\n      \"transaction\": 12598,\n      \"labeled\": 12599,\n      \"maori\": 12600,\n      \"sovereignty\": 12601,\n      \"parkway\": 12602,\n      \"trauma\": 12603,\n      \"gran\": 12604,\n      \"malay\": 12605,\n      \"121\": 12606,\n      \"advancement\": 12607,\n      \"descendant\": 12608,\n      \"2020\": 12609,\n      \"buzz\": 12610,\n      \"salvation\": 12611,\n      \"inventory\": 12612,\n      \"symbolic\": 12613,\n      \"##making\": 12614,\n      \"antarctica\": 12615,\n      \"mps\": 12616,\n      \"##gas\": 12617,\n      \"##bro\": 12618,\n      \"mohammed\": 12619,\n      \"myanmar\": 12620,\n      \"holt\": 12621,\n      \"submarines\": 12622,\n      \"tones\": 12623,\n      \"##lman\": 12624,\n      \"locker\": 12625,\n      \"patriarch\": 12626,\n      \"bangkok\": 12627,\n      \"emerson\": 12628,\n      \"remarks\": 12629,\n      \"predators\": 12630,\n      \"kin\": 12631,\n      \"afghan\": 12632,\n      \"confession\": 12633,\n      \"norwich\": 12634,\n      \"rental\": 12635,\n      \"emerge\": 12636,\n      \"advantages\": 12637,\n      \"##zel\": 12638,\n      \"rca\": 12639,\n      \"##hold\": 12640,\n      \"shortened\": 12641,\n      \"storms\": 12642,\n      \"aidan\": 12643,\n      \"##matic\": 12644,\n      \"autonomy\": 12645,\n      \"compliance\": 12646,\n      \"##quet\": 12647,\n      \"dudley\": 12648,\n      \"atp\": 12649,\n      \"##osis\": 12650,\n      \"1803\": 12651,\n      \"motto\": 12652,\n      \"documentation\": 12653,\n      \"summary\": 12654,\n      \"professors\": 12655,\n      \"spectacular\": 12656,\n      \"christina\": 12657,\n      \"archdiocese\": 12658,\n      \"flashing\": 12659,\n      \"innocence\": 12660,\n      \"remake\": 12661,\n      \"##dell\": 12662,\n      \"psychic\": 12663,\n      \"reef\": 12664,\n      \"scare\": 12665,\n      \"employ\": 12666,\n      \"rs\": 12667,\n      \"sticks\": 12668,\n      \"meg\": 12669,\n      \"gus\": 12670,\n      \"leans\": 12671,\n      \"##ude\": 12672,\n      \"accompany\": 12673,\n      \"bergen\": 12674,\n      \"tomas\": 12675,\n      \"##iko\": 12676,\n      \"doom\": 12677,\n      \"wages\": 12678,\n      \"pools\": 12679,\n      \"##nch\": 12680,\n      \"##bes\": 12681,\n      \"breasts\": 12682,\n      \"scholarly\": 12683,\n      \"alison\": 12684,\n      \"outline\": 12685,\n      \"brittany\": 12686,\n      \"breakthrough\": 12687,\n      \"willis\": 12688,\n      \"realistic\": 12689,\n      \"##cut\": 12690,\n      \"##boro\": 12691,\n      \"competitor\": 12692,\n      \"##stan\": 12693,\n      \"pike\": 12694,\n      \"picnic\": 12695,\n      \"icon\": 12696,\n      \"designing\": 12697,\n      \"commercials\": 12698,\n      \"washing\": 12699,\n      \"villain\": 12700,\n      \"skiing\": 12701,\n      \"micro\": 12702,\n      \"costumes\": 12703,\n      \"auburn\": 12704,\n      \"halted\": 12705,\n      \"executives\": 12706,\n      \"##hat\": 12707,\n      \"logistics\": 12708,\n      \"cycles\": 12709,\n      \"vowel\": 12710,\n      \"applicable\": 12711,\n      \"barrett\": 12712,\n      \"exclaimed\": 12713,\n      \"eurovision\": 12714,\n      \"eternity\": 12715,\n      \"ramon\": 12716,\n      \"##umi\": 12717,\n      \"##lls\": 12718,\n      \"modifications\": 12719,\n      \"sweeping\": 12720,\n      \"disgust\": 12721,\n      \"##uck\": 12722,\n      \"torch\": 12723,\n      \"aviv\": 12724,\n      \"ensuring\": 12725,\n      \"rude\": 12726,\n      \"dusty\": 12727,\n      \"sonic\": 12728,\n      \"donovan\": 12729,\n      \"outskirts\": 12730,\n      \"cu\": 12731,\n      \"pathway\": 12732,\n      \"##band\": 12733,\n      \"##gun\": 12734,\n      \"##lines\": 12735,\n      \"disciplines\": 12736,\n      \"acids\": 12737,\n      \"cadet\": 12738,\n      \"paired\": 12739,\n      \"##40\": 12740,\n      \"sketches\": 12741,\n      \"##sive\": 12742,\n      \"marriages\": 12743,\n      \"##⁺\": 12744,\n      \"folding\": 12745,\n      \"peers\": 12746,\n      \"slovak\": 12747,\n      \"implies\": 12748,\n      \"admired\": 12749,\n      \"##beck\": 12750,\n      \"1880s\": 12751,\n      \"leopold\": 12752,\n      \"instinct\": 12753,\n      \"attained\": 12754,\n      \"weston\": 12755,\n      \"megan\": 12756,\n      \"horace\": 12757,\n      \"##ination\": 12758,\n      \"dorsal\": 12759,\n      \"ingredients\": 12760,\n      \"evolutionary\": 12761,\n      \"##its\": 12762,\n      \"complications\": 12763,\n      \"deity\": 12764,\n      \"lethal\": 12765,\n      \"brushing\": 12766,\n      \"levy\": 12767,\n      \"deserted\": 12768,\n      \"institutes\": 12769,\n      \"posthumously\": 12770,\n      \"delivering\": 12771,\n      \"telescope\": 12772,\n      \"coronation\": 12773,\n      \"motivated\": 12774,\n      \"rapids\": 12775,\n      \"luc\": 12776,\n      \"flicked\": 12777,\n      \"pays\": 12778,\n      \"volcano\": 12779,\n      \"tanner\": 12780,\n      \"weighed\": 12781,\n      \"##nica\": 12782,\n      \"crowds\": 12783,\n      \"frankie\": 12784,\n      \"gifted\": 12785,\n      \"addressing\": 12786,\n      \"granddaughter\": 12787,\n      \"winding\": 12788,\n      \"##rna\": 12789,\n      \"constantine\": 12790,\n      \"gomez\": 12791,\n      \"##front\": 12792,\n      \"landscapes\": 12793,\n      \"rudolf\": 12794,\n      \"anthropology\": 12795,\n      \"slate\": 12796,\n      \"werewolf\": 12797,\n      \"##lio\": 12798,\n      \"astronomy\": 12799,\n      \"circa\": 12800,\n      \"rouge\": 12801,\n      \"dreaming\": 12802,\n      \"sack\": 12803,\n      \"knelt\": 12804,\n      \"drowned\": 12805,\n      \"naomi\": 12806,\n      \"prolific\": 12807,\n      \"tracked\": 12808,\n      \"freezing\": 12809,\n      \"herb\": 12810,\n      \"##dium\": 12811,\n      \"agony\": 12812,\n      \"randall\": 12813,\n      \"twisting\": 12814,\n      \"wendy\": 12815,\n      \"deposit\": 12816,\n      \"touches\": 12817,\n      \"vein\": 12818,\n      \"wheeler\": 12819,\n      \"##bbled\": 12820,\n      \"##bor\": 12821,\n      \"batted\": 12822,\n      \"retaining\": 12823,\n      \"tire\": 12824,\n      \"presently\": 12825,\n      \"compare\": 12826,\n      \"specification\": 12827,\n      \"daemon\": 12828,\n      \"nigel\": 12829,\n      \"##grave\": 12830,\n      \"merry\": 12831,\n      \"recommendation\": 12832,\n      \"czechoslovakia\": 12833,\n      \"sandra\": 12834,\n      \"ng\": 12835,\n      \"roma\": 12836,\n      \"##sts\": 12837,\n      \"lambert\": 12838,\n      \"inheritance\": 12839,\n      \"sheikh\": 12840,\n      \"winchester\": 12841,\n      \"cries\": 12842,\n      \"examining\": 12843,\n      \"##yle\": 12844,\n      \"comeback\": 12845,\n      \"cuisine\": 12846,\n      \"nave\": 12847,\n      \"##iv\": 12848,\n      \"ko\": 12849,\n      \"retrieve\": 12850,\n      \"tomatoes\": 12851,\n      \"barker\": 12852,\n      \"polished\": 12853,\n      \"defining\": 12854,\n      \"irene\": 12855,\n      \"lantern\": 12856,\n      \"personalities\": 12857,\n      \"begging\": 12858,\n      \"tract\": 12859,\n      \"swore\": 12860,\n      \"1809\": 12861,\n      \"175\": 12862,\n      \"##gic\": 12863,\n      \"omaha\": 12864,\n      \"brotherhood\": 12865,\n      \"##rley\": 12866,\n      \"haiti\": 12867,\n      \"##ots\": 12868,\n      \"exeter\": 12869,\n      \"##ete\": 12870,\n      \"##zia\": 12871,\n      \"steele\": 12872,\n      \"dumb\": 12873,\n      \"pearson\": 12874,\n      \"210\": 12875,\n      \"surveyed\": 12876,\n      \"elisabeth\": 12877,\n      \"trends\": 12878,\n      \"##ef\": 12879,\n      \"fritz\": 12880,\n      \"##rf\": 12881,\n      \"premium\": 12882,\n      \"bugs\": 12883,\n      \"fraction\": 12884,\n      \"calmly\": 12885,\n      \"viking\": 12886,\n      \"##birds\": 12887,\n      \"tug\": 12888,\n      \"inserted\": 12889,\n      \"unusually\": 12890,\n      \"##ield\": 12891,\n      \"confronted\": 12892,\n      \"distress\": 12893,\n      \"crashing\": 12894,\n      \"brent\": 12895,\n      \"turks\": 12896,\n      \"resign\": 12897,\n      \"##olo\": 12898,\n      \"cambodia\": 12899,\n      \"gabe\": 12900,\n      \"sauce\": 12901,\n      \"##kal\": 12902,\n      \"evelyn\": 12903,\n      \"116\": 12904,\n      \"extant\": 12905,\n      \"clusters\": 12906,\n      \"quarry\": 12907,\n      \"teenagers\": 12908,\n      \"luna\": 12909,\n      \"##lers\": 12910,\n      \"##ister\": 12911,\n      \"affiliation\": 12912,\n      \"drill\": 12913,\n      \"##ashi\": 12914,\n      \"panthers\": 12915,\n      \"scenic\": 12916,\n      \"libya\": 12917,\n      \"anita\": 12918,\n      \"strengthen\": 12919,\n      \"inscriptions\": 12920,\n      \"##cated\": 12921,\n      \"lace\": 12922,\n      \"sued\": 12923,\n      \"judith\": 12924,\n      \"riots\": 12925,\n      \"##uted\": 12926,\n      \"mint\": 12927,\n      \"##eta\": 12928,\n      \"preparations\": 12929,\n      \"midst\": 12930,\n      \"dub\": 12931,\n      \"challenger\": 12932,\n      \"##vich\": 12933,\n      \"mock\": 12934,\n      \"cf\": 12935,\n      \"displaced\": 12936,\n      \"wicket\": 12937,\n      \"breaths\": 12938,\n      \"enables\": 12939,\n      \"schmidt\": 12940,\n      \"analyst\": 12941,\n      \"##lum\": 12942,\n      \"ag\": 12943,\n      \"highlight\": 12944,\n      \"automotive\": 12945,\n      \"axe\": 12946,\n      \"josef\": 12947,\n      \"newark\": 12948,\n      \"sufficiently\": 12949,\n      \"resembles\": 12950,\n      \"50th\": 12951,\n      \"##pal\": 12952,\n      \"flushed\": 12953,\n      \"mum\": 12954,\n      \"traits\": 12955,\n      \"##ante\": 12956,\n      \"commodore\": 12957,\n      \"incomplete\": 12958,\n      \"warming\": 12959,\n      \"titular\": 12960,\n      \"ceremonial\": 12961,\n      \"ethical\": 12962,\n      \"118\": 12963,\n      \"celebrating\": 12964,\n      \"eighteenth\": 12965,\n      \"cao\": 12966,\n      \"lima\": 12967,\n      \"medalist\": 12968,\n      \"mobility\": 12969,\n      \"strips\": 12970,\n      \"snakes\": 12971,\n      \"##city\": 12972,\n      \"miniature\": 12973,\n      \"zagreb\": 12974,\n      \"barton\": 12975,\n      \"escapes\": 12976,\n      \"umbrella\": 12977,\n      \"automated\": 12978,\n      \"doubted\": 12979,\n      \"differs\": 12980,\n      \"cooled\": 12981,\n      \"georgetown\": 12982,\n      \"dresden\": 12983,\n      \"cooked\": 12984,\n      \"fade\": 12985,\n      \"wyatt\": 12986,\n      \"rna\": 12987,\n      \"jacobs\": 12988,\n      \"carlton\": 12989,\n      \"abundant\": 12990,\n      \"stereo\": 12991,\n      \"boost\": 12992,\n      \"madras\": 12993,\n      \"inning\": 12994,\n      \"##hia\": 12995,\n      \"spur\": 12996,\n      \"ip\": 12997,\n      \"malayalam\": 12998,\n      \"begged\": 12999,\n      \"osaka\": 13000,\n      \"groan\": 13001,\n      \"escaping\": 13002,\n      \"charging\": 13003,\n      \"dose\": 13004,\n      \"vista\": 13005,\n      \"##aj\": 13006,\n      \"bud\": 13007,\n      \"papa\": 13008,\n      \"communists\": 13009,\n      \"advocates\": 13010,\n      \"edged\": 13011,\n      \"tri\": 13012,\n      \"##cent\": 13013,\n      \"resemble\": 13014,\n      \"peaking\": 13015,\n      \"necklace\": 13016,\n      \"fried\": 13017,\n      \"montenegro\": 13018,\n      \"saxony\": 13019,\n      \"goose\": 13020,\n      \"glances\": 13021,\n      \"stuttgart\": 13022,\n      \"curator\": 13023,\n      \"recruit\": 13024,\n      \"grocery\": 13025,\n      \"sympathetic\": 13026,\n      \"##tting\": 13027,\n      \"##fort\": 13028,\n      \"127\": 13029,\n      \"lotus\": 13030,\n      \"randolph\": 13031,\n      \"ancestor\": 13032,\n      \"##rand\": 13033,\n      \"succeeding\": 13034,\n      \"jupiter\": 13035,\n      \"1798\": 13036,\n      \"macedonian\": 13037,\n      \"##heads\": 13038,\n      \"hiking\": 13039,\n      \"1808\": 13040,\n      \"handing\": 13041,\n      \"fischer\": 13042,\n      \"##itive\": 13043,\n      \"garbage\": 13044,\n      \"node\": 13045,\n      \"##pies\": 13046,\n      \"prone\": 13047,\n      \"singular\": 13048,\n      \"papua\": 13049,\n      \"inclined\": 13050,\n      \"attractions\": 13051,\n      \"italia\": 13052,\n      \"pouring\": 13053,\n      \"motioned\": 13054,\n      \"grandma\": 13055,\n      \"garnered\": 13056,\n      \"jacksonville\": 13057,\n      \"corp\": 13058,\n      \"ego\": 13059,\n      \"ringing\": 13060,\n      \"aluminum\": 13061,\n      \"##hausen\": 13062,\n      \"ordering\": 13063,\n      \"##foot\": 13064,\n      \"drawer\": 13065,\n      \"traders\": 13066,\n      \"synagogue\": 13067,\n      \"##play\": 13068,\n      \"##kawa\": 13069,\n      \"resistant\": 13070,\n      \"wandering\": 13071,\n      \"fragile\": 13072,\n      \"fiona\": 13073,\n      \"teased\": 13074,\n      \"var\": 13075,\n      \"hardcore\": 13076,\n      \"soaked\": 13077,\n      \"jubilee\": 13078,\n      \"decisive\": 13079,\n      \"exposition\": 13080,\n      \"mercer\": 13081,\n      \"poster\": 13082,\n      \"valencia\": 13083,\n      \"hale\": 13084,\n      \"kuwait\": 13085,\n      \"1811\": 13086,\n      \"##ises\": 13087,\n      \"##wr\": 13088,\n      \"##eed\": 13089,\n      \"tavern\": 13090,\n      \"gamma\": 13091,\n      \"122\": 13092,\n      \"johan\": 13093,\n      \"##uer\": 13094,\n      \"airways\": 13095,\n      \"amino\": 13096,\n      \"gil\": 13097,\n      \"##ury\": 13098,\n      \"vocational\": 13099,\n      \"domains\": 13100,\n      \"torres\": 13101,\n      \"##sp\": 13102,\n      \"generator\": 13103,\n      \"folklore\": 13104,\n      \"outcomes\": 13105,\n      \"##keeper\": 13106,\n      \"canberra\": 13107,\n      \"shooter\": 13108,\n      \"fl\": 13109,\n      \"beams\": 13110,\n      \"confrontation\": 13111,\n      \"##lling\": 13112,\n      \"##gram\": 13113,\n      \"feb\": 13114,\n      \"aligned\": 13115,\n      \"forestry\": 13116,\n      \"pipeline\": 13117,\n      \"jax\": 13118,\n      \"motorway\": 13119,\n      \"conception\": 13120,\n      \"decay\": 13121,\n      \"##tos\": 13122,\n      \"coffin\": 13123,\n      \"##cott\": 13124,\n      \"stalin\": 13125,\n      \"1805\": 13126,\n      \"escorted\": 13127,\n      \"minded\": 13128,\n      \"##nam\": 13129,\n      \"sitcom\": 13130,\n      \"purchasing\": 13131,\n      \"twilight\": 13132,\n      \"veronica\": 13133,\n      \"additions\": 13134,\n      \"passive\": 13135,\n      \"tensions\": 13136,\n      \"straw\": 13137,\n      \"123\": 13138,\n      \"frequencies\": 13139,\n      \"1804\": 13140,\n      \"refugee\": 13141,\n      \"cultivation\": 13142,\n      \"##iate\": 13143,\n      \"christie\": 13144,\n      \"clary\": 13145,\n      \"bulletin\": 13146,\n      \"crept\": 13147,\n      \"disposal\": 13148,\n      \"##rich\": 13149,\n      \"##zong\": 13150,\n      \"processor\": 13151,\n      \"crescent\": 13152,\n      \"##rol\": 13153,\n      \"bmw\": 13154,\n      \"emphasized\": 13155,\n      \"whale\": 13156,\n      \"nazis\": 13157,\n      \"aurora\": 13158,\n      \"##eng\": 13159,\n      \"dwelling\": 13160,\n      \"hauled\": 13161,\n      \"sponsors\": 13162,\n      \"toledo\": 13163,\n      \"mega\": 13164,\n      \"ideology\": 13165,\n      \"theatres\": 13166,\n      \"tessa\": 13167,\n      \"cerambycidae\": 13168,\n      \"saves\": 13169,\n      \"turtle\": 13170,\n      \"cone\": 13171,\n      \"suspects\": 13172,\n      \"kara\": 13173,\n      \"rusty\": 13174,\n      \"yelling\": 13175,\n      \"greeks\": 13176,\n      \"mozart\": 13177,\n      \"shades\": 13178,\n      \"cocked\": 13179,\n      \"participant\": 13180,\n      \"##tro\": 13181,\n      \"shire\": 13182,\n      \"spit\": 13183,\n      \"freeze\": 13184,\n      \"necessity\": 13185,\n      \"##cos\": 13186,\n      \"inmates\": 13187,\n      \"nielsen\": 13188,\n      \"councillors\": 13189,\n      \"loaned\": 13190,\n      \"uncommon\": 13191,\n      \"omar\": 13192,\n      \"peasants\": 13193,\n      \"botanical\": 13194,\n      \"offspring\": 13195,\n      \"daniels\": 13196,\n      \"formations\": 13197,\n      \"jokes\": 13198,\n      \"1794\": 13199,\n      \"pioneers\": 13200,\n      \"sigma\": 13201,\n      \"licensing\": 13202,\n      \"##sus\": 13203,\n      \"wheelchair\": 13204,\n      \"polite\": 13205,\n      \"1807\": 13206,\n      \"liquor\": 13207,\n      \"pratt\": 13208,\n      \"trustee\": 13209,\n      \"##uta\": 13210,\n      \"forewings\": 13211,\n      \"balloon\": 13212,\n      \"##zz\": 13213,\n      \"kilometre\": 13214,\n      \"camping\": 13215,\n      \"explicit\": 13216,\n      \"casually\": 13217,\n      \"shawn\": 13218,\n      \"foolish\": 13219,\n      \"teammates\": 13220,\n      \"nm\": 13221,\n      \"hassan\": 13222,\n      \"carrie\": 13223,\n      \"judged\": 13224,\n      \"satisfy\": 13225,\n      \"vanessa\": 13226,\n      \"knives\": 13227,\n      \"selective\": 13228,\n      \"cnn\": 13229,\n      \"flowed\": 13230,\n      \"##lice\": 13231,\n      \"eclipse\": 13232,\n      \"stressed\": 13233,\n      \"eliza\": 13234,\n      \"mathematician\": 13235,\n      \"cease\": 13236,\n      \"cultivated\": 13237,\n      \"##roy\": 13238,\n      \"commissions\": 13239,\n      \"browns\": 13240,\n      \"##ania\": 13241,\n      \"destroyers\": 13242,\n      \"sheridan\": 13243,\n      \"meadow\": 13244,\n      \"##rius\": 13245,\n      \"minerals\": 13246,\n      \"##cial\": 13247,\n      \"downstream\": 13248,\n      \"clash\": 13249,\n      \"gram\": 13250,\n      \"memoirs\": 13251,\n      \"ventures\": 13252,\n      \"baha\": 13253,\n      \"seymour\": 13254,\n      \"archie\": 13255,\n      \"midlands\": 13256,\n      \"edith\": 13257,\n      \"fare\": 13258,\n      \"flynn\": 13259,\n      \"invite\": 13260,\n      \"canceled\": 13261,\n      \"tiles\": 13262,\n      \"stabbed\": 13263,\n      \"boulder\": 13264,\n      \"incorporate\": 13265,\n      \"amended\": 13266,\n      \"camden\": 13267,\n      \"facial\": 13268,\n      \"mollusk\": 13269,\n      \"unreleased\": 13270,\n      \"descriptions\": 13271,\n      \"yoga\": 13272,\n      \"grabs\": 13273,\n      \"550\": 13274,\n      \"raises\": 13275,\n      \"ramp\": 13276,\n      \"shiver\": 13277,\n      \"##rose\": 13278,\n      \"coined\": 13279,\n      \"pioneering\": 13280,\n      \"tunes\": 13281,\n      \"qing\": 13282,\n      \"warwick\": 13283,\n      \"tops\": 13284,\n      \"119\": 13285,\n      \"melanie\": 13286,\n      \"giles\": 13287,\n      \"##rous\": 13288,\n      \"wandered\": 13289,\n      \"##inal\": 13290,\n      \"annexed\": 13291,\n      \"nov\": 13292,\n      \"30th\": 13293,\n      \"unnamed\": 13294,\n      \"##ished\": 13295,\n      \"organizational\": 13296,\n      \"airplane\": 13297,\n      \"normandy\": 13298,\n      \"stoke\": 13299,\n      \"whistle\": 13300,\n      \"blessing\": 13301,\n      \"violations\": 13302,\n      \"chased\": 13303,\n      \"holders\": 13304,\n      \"shotgun\": 13305,\n      \"##ctic\": 13306,\n      \"outlet\": 13307,\n      \"reactor\": 13308,\n      \"##vik\": 13309,\n      \"tires\": 13310,\n      \"tearing\": 13311,\n      \"shores\": 13312,\n      \"fortified\": 13313,\n      \"mascot\": 13314,\n      \"constituencies\": 13315,\n      \"nc\": 13316,\n      \"columnist\": 13317,\n      \"productive\": 13318,\n      \"tibet\": 13319,\n      \"##rta\": 13320,\n      \"lineage\": 13321,\n      \"hooked\": 13322,\n      \"oct\": 13323,\n      \"tapes\": 13324,\n      \"judging\": 13325,\n      \"cody\": 13326,\n      \"##gger\": 13327,\n      \"hansen\": 13328,\n      \"kashmir\": 13329,\n      \"triggered\": 13330,\n      \"##eva\": 13331,\n      \"solved\": 13332,\n      \"cliffs\": 13333,\n      \"##tree\": 13334,\n      \"resisted\": 13335,\n      \"anatomy\": 13336,\n      \"protesters\": 13337,\n      \"transparent\": 13338,\n      \"implied\": 13339,\n      \"##iga\": 13340,\n      \"injection\": 13341,\n      \"mattress\": 13342,\n      \"excluding\": 13343,\n      \"##mbo\": 13344,\n      \"defenses\": 13345,\n      \"helpless\": 13346,\n      \"devotion\": 13347,\n      \"##elli\": 13348,\n      \"growl\": 13349,\n      \"liberals\": 13350,\n      \"weber\": 13351,\n      \"phenomena\": 13352,\n      \"atoms\": 13353,\n      \"plug\": 13354,\n      \"##iff\": 13355,\n      \"mortality\": 13356,\n      \"apprentice\": 13357,\n      \"howe\": 13358,\n      \"convincing\": 13359,\n      \"aaa\": 13360,\n      \"swimmer\": 13361,\n      \"barber\": 13362,\n      \"leone\": 13363,\n      \"promptly\": 13364,\n      \"sodium\": 13365,\n      \"def\": 13366,\n      \"nowadays\": 13367,\n      \"arise\": 13368,\n      \"##oning\": 13369,\n      \"gloucester\": 13370,\n      \"corrected\": 13371,\n      \"dignity\": 13372,\n      \"norm\": 13373,\n      \"erie\": 13374,\n      \"##ders\": 13375,\n      \"elders\": 13376,\n      \"evacuated\": 13377,\n      \"sylvia\": 13378,\n      \"compression\": 13379,\n      \"##yar\": 13380,\n      \"hartford\": 13381,\n      \"pose\": 13382,\n      \"backpack\": 13383,\n      \"reasoning\": 13384,\n      \"accepts\": 13385,\n      \"24th\": 13386,\n      \"wipe\": 13387,\n      \"millimetres\": 13388,\n      \"marcel\": 13389,\n      \"##oda\": 13390,\n      \"dodgers\": 13391,\n      \"albion\": 13392,\n      \"1790\": 13393,\n      \"overwhelmed\": 13394,\n      \"aerospace\": 13395,\n      \"oaks\": 13396,\n      \"1795\": 13397,\n      \"showcase\": 13398,\n      \"acknowledge\": 13399,\n      \"recovering\": 13400,\n      \"nolan\": 13401,\n      \"ashe\": 13402,\n      \"hurts\": 13403,\n      \"geology\": 13404,\n      \"fashioned\": 13405,\n      \"disappearance\": 13406,\n      \"farewell\": 13407,\n      \"swollen\": 13408,\n      \"shrug\": 13409,\n      \"marquis\": 13410,\n      \"wimbledon\": 13411,\n      \"124\": 13412,\n      \"rue\": 13413,\n      \"1792\": 13414,\n      \"commemorate\": 13415,\n      \"reduces\": 13416,\n      \"experiencing\": 13417,\n      \"inevitable\": 13418,\n      \"calcutta\": 13419,\n      \"intel\": 13420,\n      \"##court\": 13421,\n      \"murderer\": 13422,\n      \"sticking\": 13423,\n      \"fisheries\": 13424,\n      \"imagery\": 13425,\n      \"bloom\": 13426,\n      \"280\": 13427,\n      \"brake\": 13428,\n      \"##inus\": 13429,\n      \"gustav\": 13430,\n      \"hesitation\": 13431,\n      \"memorable\": 13432,\n      \"po\": 13433,\n      \"viral\": 13434,\n      \"beans\": 13435,\n      \"accidents\": 13436,\n      \"tunisia\": 13437,\n      \"antenna\": 13438,\n      \"spilled\": 13439,\n      \"consort\": 13440,\n      \"treatments\": 13441,\n      \"aye\": 13442,\n      \"perimeter\": 13443,\n      \"##gard\": 13444,\n      \"donation\": 13445,\n      \"hostage\": 13446,\n      \"migrated\": 13447,\n      \"banker\": 13448,\n      \"addiction\": 13449,\n      \"apex\": 13450,\n      \"lil\": 13451,\n      \"trout\": 13452,\n      \"##ously\": 13453,\n      \"conscience\": 13454,\n      \"##nova\": 13455,\n      \"rams\": 13456,\n      \"sands\": 13457,\n      \"genome\": 13458,\n      \"passionate\": 13459,\n      \"troubles\": 13460,\n      \"##lets\": 13461,\n      \"##set\": 13462,\n      \"amid\": 13463,\n      \"##ibility\": 13464,\n      \"##ret\": 13465,\n      \"higgins\": 13466,\n      \"exceed\": 13467,\n      \"vikings\": 13468,\n      \"##vie\": 13469,\n      \"payne\": 13470,\n      \"##zan\": 13471,\n      \"muscular\": 13472,\n      \"##ste\": 13473,\n      \"defendant\": 13474,\n      \"sucking\": 13475,\n      \"##wal\": 13476,\n      \"ibrahim\": 13477,\n      \"fuselage\": 13478,\n      \"claudia\": 13479,\n      \"vfl\": 13480,\n      \"europeans\": 13481,\n      \"snails\": 13482,\n      \"interval\": 13483,\n      \"##garh\": 13484,\n      \"preparatory\": 13485,\n      \"statewide\": 13486,\n      \"tasked\": 13487,\n      \"lacrosse\": 13488,\n      \"viktor\": 13489,\n      \"##lation\": 13490,\n      \"angola\": 13491,\n      \"##hra\": 13492,\n      \"flint\": 13493,\n      \"implications\": 13494,\n      \"employs\": 13495,\n      \"teens\": 13496,\n      \"patrons\": 13497,\n      \"stall\": 13498,\n      \"weekends\": 13499,\n      \"barriers\": 13500,\n      \"scrambled\": 13501,\n      \"nucleus\": 13502,\n      \"tehran\": 13503,\n      \"jenna\": 13504,\n      \"parsons\": 13505,\n      \"lifelong\": 13506,\n      \"robots\": 13507,\n      \"displacement\": 13508,\n      \"5000\": 13509,\n      \"##bles\": 13510,\n      \"precipitation\": 13511,\n      \"##gt\": 13512,\n      \"knuckles\": 13513,\n      \"clutched\": 13514,\n      \"1802\": 13515,\n      \"marrying\": 13516,\n      \"ecology\": 13517,\n      \"marx\": 13518,\n      \"accusations\": 13519,\n      \"declare\": 13520,\n      \"scars\": 13521,\n      \"kolkata\": 13522,\n      \"mat\": 13523,\n      \"meadows\": 13524,\n      \"bermuda\": 13525,\n      \"skeleton\": 13526,\n      \"finalists\": 13527,\n      \"vintage\": 13528,\n      \"crawl\": 13529,\n      \"coordinate\": 13530,\n      \"affects\": 13531,\n      \"subjected\": 13532,\n      \"orchestral\": 13533,\n      \"mistaken\": 13534,\n      \"##tc\": 13535,\n      \"mirrors\": 13536,\n      \"dipped\": 13537,\n      \"relied\": 13538,\n      \"260\": 13539,\n      \"arches\": 13540,\n      \"candle\": 13541,\n      \"##nick\": 13542,\n      \"incorporating\": 13543,\n      \"wildly\": 13544,\n      \"fond\": 13545,\n      \"basilica\": 13546,\n      \"owl\": 13547,\n      \"fringe\": 13548,\n      \"rituals\": 13549,\n      \"whispering\": 13550,\n      \"stirred\": 13551,\n      \"feud\": 13552,\n      \"tertiary\": 13553,\n      \"slick\": 13554,\n      \"goat\": 13555,\n      \"honorable\": 13556,\n      \"whereby\": 13557,\n      \"skip\": 13558,\n      \"ricardo\": 13559,\n      \"stripes\": 13560,\n      \"parachute\": 13561,\n      \"adjoining\": 13562,\n      \"submerged\": 13563,\n      \"synthesizer\": 13564,\n      \"##gren\": 13565,\n      \"intend\": 13566,\n      \"positively\": 13567,\n      \"ninety\": 13568,\n      \"phi\": 13569,\n      \"beaver\": 13570,\n      \"partition\": 13571,\n      \"fellows\": 13572,\n      \"alexis\": 13573,\n      \"prohibition\": 13574,\n      \"carlisle\": 13575,\n      \"bizarre\": 13576,\n      \"fraternity\": 13577,\n      \"##bre\": 13578,\n      \"doubts\": 13579,\n      \"icy\": 13580,\n      \"cbc\": 13581,\n      \"aquatic\": 13582,\n      \"sneak\": 13583,\n      \"sonny\": 13584,\n      \"combines\": 13585,\n      \"airports\": 13586,\n      \"crude\": 13587,\n      \"supervised\": 13588,\n      \"spatial\": 13589,\n      \"merge\": 13590,\n      \"alfonso\": 13591,\n      \"##bic\": 13592,\n      \"corrupt\": 13593,\n      \"scan\": 13594,\n      \"undergo\": 13595,\n      \"##ams\": 13596,\n      \"disabilities\": 13597,\n      \"colombian\": 13598,\n      \"comparing\": 13599,\n      \"dolphins\": 13600,\n      \"perkins\": 13601,\n      \"##lish\": 13602,\n      \"reprinted\": 13603,\n      \"unanimous\": 13604,\n      \"bounced\": 13605,\n      \"hairs\": 13606,\n      \"underworld\": 13607,\n      \"midwest\": 13608,\n      \"semester\": 13609,\n      \"bucket\": 13610,\n      \"paperback\": 13611,\n      \"miniseries\": 13612,\n      \"coventry\": 13613,\n      \"demise\": 13614,\n      \"##leigh\": 13615,\n      \"demonstrations\": 13616,\n      \"sensor\": 13617,\n      \"rotating\": 13618,\n      \"yan\": 13619,\n      \"##hler\": 13620,\n      \"arrange\": 13621,\n      \"soils\": 13622,\n      \"##idge\": 13623,\n      \"hyderabad\": 13624,\n      \"labs\": 13625,\n      \"##dr\": 13626,\n      \"brakes\": 13627,\n      \"grandchildren\": 13628,\n      \"##nde\": 13629,\n      \"negotiated\": 13630,\n      \"rover\": 13631,\n      \"ferrari\": 13632,\n      \"continuation\": 13633,\n      \"directorate\": 13634,\n      \"augusta\": 13635,\n      \"stevenson\": 13636,\n      \"counterpart\": 13637,\n      \"gore\": 13638,\n      \"##rda\": 13639,\n      \"nursery\": 13640,\n      \"rican\": 13641,\n      \"ave\": 13642,\n      \"collectively\": 13643,\n      \"broadly\": 13644,\n      \"pastoral\": 13645,\n      \"repertoire\": 13646,\n      \"asserted\": 13647,\n      \"discovering\": 13648,\n      \"nordic\": 13649,\n      \"styled\": 13650,\n      \"fiba\": 13651,\n      \"cunningham\": 13652,\n      \"harley\": 13653,\n      \"middlesex\": 13654,\n      \"survives\": 13655,\n      \"tumor\": 13656,\n      \"tempo\": 13657,\n      \"zack\": 13658,\n      \"aiming\": 13659,\n      \"lok\": 13660,\n      \"urgent\": 13661,\n      \"##rade\": 13662,\n      \"##nto\": 13663,\n      \"devils\": 13664,\n      \"##ement\": 13665,\n      \"contractor\": 13666,\n      \"turin\": 13667,\n      \"##wl\": 13668,\n      \"##ool\": 13669,\n      \"bliss\": 13670,\n      \"repaired\": 13671,\n      \"simmons\": 13672,\n      \"moan\": 13673,\n      \"astronomical\": 13674,\n      \"cr\": 13675,\n      \"negotiate\": 13676,\n      \"lyric\": 13677,\n      \"1890s\": 13678,\n      \"lara\": 13679,\n      \"bred\": 13680,\n      \"clad\": 13681,\n      \"angus\": 13682,\n      \"pbs\": 13683,\n      \"##ience\": 13684,\n      \"engineered\": 13685,\n      \"posed\": 13686,\n      \"##lk\": 13687,\n      \"hernandez\": 13688,\n      \"possessions\": 13689,\n      \"elbows\": 13690,\n      \"psychiatric\": 13691,\n      \"strokes\": 13692,\n      \"confluence\": 13693,\n      \"electorate\": 13694,\n      \"lifts\": 13695,\n      \"campuses\": 13696,\n      \"lava\": 13697,\n      \"alps\": 13698,\n      \"##ep\": 13699,\n      \"##ution\": 13700,\n      \"##date\": 13701,\n      \"physicist\": 13702,\n      \"woody\": 13703,\n      \"##page\": 13704,\n      \"##ographic\": 13705,\n      \"##itis\": 13706,\n      \"juliet\": 13707,\n      \"reformation\": 13708,\n      \"sparhawk\": 13709,\n      \"320\": 13710,\n      \"complement\": 13711,\n      \"suppressed\": 13712,\n      \"jewel\": 13713,\n      \"##½\": 13714,\n      \"floated\": 13715,\n      \"##kas\": 13716,\n      \"continuity\": 13717,\n      \"sadly\": 13718,\n      \"##ische\": 13719,\n      \"inability\": 13720,\n      \"melting\": 13721,\n      \"scanning\": 13722,\n      \"paula\": 13723,\n      \"flour\": 13724,\n      \"judaism\": 13725,\n      \"safer\": 13726,\n      \"vague\": 13727,\n      \"##lm\": 13728,\n      \"solving\": 13729,\n      \"curb\": 13730,\n      \"##stown\": 13731,\n      \"financially\": 13732,\n      \"gable\": 13733,\n      \"bees\": 13734,\n      \"expired\": 13735,\n      \"miserable\": 13736,\n      \"cassidy\": 13737,\n      \"dominion\": 13738,\n      \"1789\": 13739,\n      \"cupped\": 13740,\n      \"145\": 13741,\n      \"robbery\": 13742,\n      \"facto\": 13743,\n      \"amos\": 13744,\n      \"warden\": 13745,\n      \"resume\": 13746,\n      \"tallest\": 13747,\n      \"marvin\": 13748,\n      \"ing\": 13749,\n      \"pounded\": 13750,\n      \"usd\": 13751,\n      \"declaring\": 13752,\n      \"gasoline\": 13753,\n      \"##aux\": 13754,\n      \"darkened\": 13755,\n      \"270\": 13756,\n      \"650\": 13757,\n      \"sophomore\": 13758,\n      \"##mere\": 13759,\n      \"erection\": 13760,\n      \"gossip\": 13761,\n      \"televised\": 13762,\n      \"risen\": 13763,\n      \"dial\": 13764,\n      \"##eu\": 13765,\n      \"pillars\": 13766,\n      \"##link\": 13767,\n      \"passages\": 13768,\n      \"profound\": 13769,\n      \"##tina\": 13770,\n      \"arabian\": 13771,\n      \"ashton\": 13772,\n      \"silicon\": 13773,\n      \"nail\": 13774,\n      \"##ead\": 13775,\n      \"##lated\": 13776,\n      \"##wer\": 13777,\n      \"##hardt\": 13778,\n      \"fleming\": 13779,\n      \"firearms\": 13780,\n      \"ducked\": 13781,\n      \"circuits\": 13782,\n      \"blows\": 13783,\n      \"waterloo\": 13784,\n      \"titans\": 13785,\n      \"##lina\": 13786,\n      \"atom\": 13787,\n      \"fireplace\": 13788,\n      \"cheshire\": 13789,\n      \"financed\": 13790,\n      \"activation\": 13791,\n      \"algorithms\": 13792,\n      \"##zzi\": 13793,\n      \"constituent\": 13794,\n      \"catcher\": 13795,\n      \"cherokee\": 13796,\n      \"partnerships\": 13797,\n      \"sexuality\": 13798,\n      \"platoon\": 13799,\n      \"tragic\": 13800,\n      \"vivian\": 13801,\n      \"guarded\": 13802,\n      \"whiskey\": 13803,\n      \"meditation\": 13804,\n      \"poetic\": 13805,\n      \"##late\": 13806,\n      \"##nga\": 13807,\n      \"##ake\": 13808,\n      \"porto\": 13809,\n      \"listeners\": 13810,\n      \"dominance\": 13811,\n      \"kendra\": 13812,\n      \"mona\": 13813,\n      \"chandler\": 13814,\n      \"factions\": 13815,\n      \"22nd\": 13816,\n      \"salisbury\": 13817,\n      \"attitudes\": 13818,\n      \"derivative\": 13819,\n      \"##ido\": 13820,\n      \"##haus\": 13821,\n      \"intake\": 13822,\n      \"paced\": 13823,\n      \"javier\": 13824,\n      \"illustrator\": 13825,\n      \"barrels\": 13826,\n      \"bias\": 13827,\n      \"cockpit\": 13828,\n      \"burnett\": 13829,\n      \"dreamed\": 13830,\n      \"ensuing\": 13831,\n      \"##anda\": 13832,\n      \"receptors\": 13833,\n      \"someday\": 13834,\n      \"hawkins\": 13835,\n      \"mattered\": 13836,\n      \"##lal\": 13837,\n      \"slavic\": 13838,\n      \"1799\": 13839,\n      \"jesuit\": 13840,\n      \"cameroon\": 13841,\n      \"wasted\": 13842,\n      \"tai\": 13843,\n      \"wax\": 13844,\n      \"lowering\": 13845,\n      \"victorious\": 13846,\n      \"freaking\": 13847,\n      \"outright\": 13848,\n      \"hancock\": 13849,\n      \"librarian\": 13850,\n      \"sensing\": 13851,\n      \"bald\": 13852,\n      \"calcium\": 13853,\n      \"myers\": 13854,\n      \"tablet\": 13855,\n      \"announcing\": 13856,\n      \"barack\": 13857,\n      \"shipyard\": 13858,\n      \"pharmaceutical\": 13859,\n      \"##uan\": 13860,\n      \"greenwich\": 13861,\n      \"flush\": 13862,\n      \"medley\": 13863,\n      \"patches\": 13864,\n      \"wolfgang\": 13865,\n      \"pt\": 13866,\n      \"speeches\": 13867,\n      \"acquiring\": 13868,\n      \"exams\": 13869,\n      \"nikolai\": 13870,\n      \"##gg\": 13871,\n      \"hayden\": 13872,\n      \"kannada\": 13873,\n      \"##type\": 13874,\n      \"reilly\": 13875,\n      \"##pt\": 13876,\n      \"waitress\": 13877,\n      \"abdomen\": 13878,\n      \"devastated\": 13879,\n      \"capped\": 13880,\n      \"pseudonym\": 13881,\n      \"pharmacy\": 13882,\n      \"fulfill\": 13883,\n      \"paraguay\": 13884,\n      \"1796\": 13885,\n      \"clicked\": 13886,\n      \"##trom\": 13887,\n      \"archipelago\": 13888,\n      \"syndicated\": 13889,\n      \"##hman\": 13890,\n      \"lumber\": 13891,\n      \"orgasm\": 13892,\n      \"rejection\": 13893,\n      \"clifford\": 13894,\n      \"lorraine\": 13895,\n      \"advent\": 13896,\n      \"mafia\": 13897,\n      \"rodney\": 13898,\n      \"brock\": 13899,\n      \"##ght\": 13900,\n      \"##used\": 13901,\n      \"##elia\": 13902,\n      \"cassette\": 13903,\n      \"chamberlain\": 13904,\n      \"despair\": 13905,\n      \"mongolia\": 13906,\n      \"sensors\": 13907,\n      \"developmental\": 13908,\n      \"upstream\": 13909,\n      \"##eg\": 13910,\n      \"##alis\": 13911,\n      \"spanning\": 13912,\n      \"165\": 13913,\n      \"trombone\": 13914,\n      \"basque\": 13915,\n      \"seeded\": 13916,\n      \"interred\": 13917,\n      \"renewable\": 13918,\n      \"rhys\": 13919,\n      \"leapt\": 13920,\n      \"revision\": 13921,\n      \"molecule\": 13922,\n      \"##ages\": 13923,\n      \"chord\": 13924,\n      \"vicious\": 13925,\n      \"nord\": 13926,\n      \"shivered\": 13927,\n      \"23rd\": 13928,\n      \"arlington\": 13929,\n      \"debts\": 13930,\n      \"corpus\": 13931,\n      \"sunrise\": 13932,\n      \"bays\": 13933,\n      \"blackburn\": 13934,\n      \"centimetres\": 13935,\n      \"##uded\": 13936,\n      \"shuddered\": 13937,\n      \"gm\": 13938,\n      \"strangely\": 13939,\n      \"gripping\": 13940,\n      \"cartoons\": 13941,\n      \"isabelle\": 13942,\n      \"orbital\": 13943,\n      \"##ppa\": 13944,\n      \"seals\": 13945,\n      \"proving\": 13946,\n      \"##lton\": 13947,\n      \"refusal\": 13948,\n      \"strengthened\": 13949,\n      \"bust\": 13950,\n      \"assisting\": 13951,\n      \"baghdad\": 13952,\n      \"batsman\": 13953,\n      \"portrayal\": 13954,\n      \"mara\": 13955,\n      \"pushes\": 13956,\n      \"spears\": 13957,\n      \"og\": 13958,\n      \"##cock\": 13959,\n      \"reside\": 13960,\n      \"nathaniel\": 13961,\n      \"brennan\": 13962,\n      \"1776\": 13963,\n      \"confirmation\": 13964,\n      \"caucus\": 13965,\n      \"##worthy\": 13966,\n      \"markings\": 13967,\n      \"yemen\": 13968,\n      \"nobles\": 13969,\n      \"ku\": 13970,\n      \"lazy\": 13971,\n      \"viewer\": 13972,\n      \"catalan\": 13973,\n      \"encompasses\": 13974,\n      \"sawyer\": 13975,\n      \"##fall\": 13976,\n      \"sparked\": 13977,\n      \"substances\": 13978,\n      \"patents\": 13979,\n      \"braves\": 13980,\n      \"arranger\": 13981,\n      \"evacuation\": 13982,\n      \"sergio\": 13983,\n      \"persuade\": 13984,\n      \"dover\": 13985,\n      \"tolerance\": 13986,\n      \"penguin\": 13987,\n      \"cum\": 13988,\n      \"jockey\": 13989,\n      \"insufficient\": 13990,\n      \"townships\": 13991,\n      \"occupying\": 13992,\n      \"declining\": 13993,\n      \"plural\": 13994,\n      \"processed\": 13995,\n      \"projection\": 13996,\n      \"puppet\": 13997,\n      \"flanders\": 13998,\n      \"introduces\": 13999,\n      \"liability\": 14000,\n      \"##yon\": 14001,\n      \"gymnastics\": 14002,\n      \"antwerp\": 14003,\n      \"taipei\": 14004,\n      \"hobart\": 14005,\n      \"candles\": 14006,\n      \"jeep\": 14007,\n      \"wes\": 14008,\n      \"observers\": 14009,\n      \"126\": 14010,\n      \"chaplain\": 14011,\n      \"bundle\": 14012,\n      \"glorious\": 14013,\n      \"##hine\": 14014,\n      \"hazel\": 14015,\n      \"flung\": 14016,\n      \"sol\": 14017,\n      \"excavations\": 14018,\n      \"dumped\": 14019,\n      \"stares\": 14020,\n      \"sh\": 14021,\n      \"bangalore\": 14022,\n      \"triangular\": 14023,\n      \"icelandic\": 14024,\n      \"intervals\": 14025,\n      \"expressing\": 14026,\n      \"turbine\": 14027,\n      \"##vers\": 14028,\n      \"songwriting\": 14029,\n      \"crafts\": 14030,\n      \"##igo\": 14031,\n      \"jasmine\": 14032,\n      \"ditch\": 14033,\n      \"rite\": 14034,\n      \"##ways\": 14035,\n      \"entertaining\": 14036,\n      \"comply\": 14037,\n      \"sorrow\": 14038,\n      \"wrestlers\": 14039,\n      \"basel\": 14040,\n      \"emirates\": 14041,\n      \"marian\": 14042,\n      \"rivera\": 14043,\n      \"helpful\": 14044,\n      \"##some\": 14045,\n      \"caution\": 14046,\n      \"downward\": 14047,\n      \"networking\": 14048,\n      \"##atory\": 14049,\n      \"##tered\": 14050,\n      \"darted\": 14051,\n      \"genocide\": 14052,\n      \"emergence\": 14053,\n      \"replies\": 14054,\n      \"specializing\": 14055,\n      \"spokesman\": 14056,\n      \"convenient\": 14057,\n      \"unlocked\": 14058,\n      \"fading\": 14059,\n      \"augustine\": 14060,\n      \"concentrations\": 14061,\n      \"resemblance\": 14062,\n      \"elijah\": 14063,\n      \"investigator\": 14064,\n      \"andhra\": 14065,\n      \"##uda\": 14066,\n      \"promotes\": 14067,\n      \"bean\": 14068,\n      \"##rrell\": 14069,\n      \"fleeing\": 14070,\n      \"wan\": 14071,\n      \"simone\": 14072,\n      \"announcer\": 14073,\n      \"##ame\": 14074,\n      \"##bby\": 14075,\n      \"lydia\": 14076,\n      \"weaver\": 14077,\n      \"132\": 14078,\n      \"residency\": 14079,\n      \"modification\": 14080,\n      \"##fest\": 14081,\n      \"stretches\": 14082,\n      \"##ast\": 14083,\n      \"alternatively\": 14084,\n      \"nat\": 14085,\n      \"lowe\": 14086,\n      \"lacks\": 14087,\n      \"##ented\": 14088,\n      \"pam\": 14089,\n      \"tile\": 14090,\n      \"concealed\": 14091,\n      \"inferior\": 14092,\n      \"abdullah\": 14093,\n      \"residences\": 14094,\n      \"tissues\": 14095,\n      \"vengeance\": 14096,\n      \"##ided\": 14097,\n      \"moisture\": 14098,\n      \"peculiar\": 14099,\n      \"groove\": 14100,\n      \"zip\": 14101,\n      \"bologna\": 14102,\n      \"jennings\": 14103,\n      \"ninja\": 14104,\n      \"oversaw\": 14105,\n      \"zombies\": 14106,\n      \"pumping\": 14107,\n      \"batch\": 14108,\n      \"livingston\": 14109,\n      \"emerald\": 14110,\n      \"installations\": 14111,\n      \"1797\": 14112,\n      \"peel\": 14113,\n      \"nitrogen\": 14114,\n      \"rama\": 14115,\n      \"##fying\": 14116,\n      \"##star\": 14117,\n      \"schooling\": 14118,\n      \"strands\": 14119,\n      \"responding\": 14120,\n      \"werner\": 14121,\n      \"##ost\": 14122,\n      \"lime\": 14123,\n      \"casa\": 14124,\n      \"accurately\": 14125,\n      \"targeting\": 14126,\n      \"##rod\": 14127,\n      \"underway\": 14128,\n      \"##uru\": 14129,\n      \"hemisphere\": 14130,\n      \"lester\": 14131,\n      \"##yard\": 14132,\n      \"occupies\": 14133,\n      \"2d\": 14134,\n      \"griffith\": 14135,\n      \"angrily\": 14136,\n      \"reorganized\": 14137,\n      \"##owing\": 14138,\n      \"courtney\": 14139,\n      \"deposited\": 14140,\n      \"##dd\": 14141,\n      \"##30\": 14142,\n      \"estadio\": 14143,\n      \"##ifies\": 14144,\n      \"dunn\": 14145,\n      \"exiled\": 14146,\n      \"##ying\": 14147,\n      \"checks\": 14148,\n      \"##combe\": 14149,\n      \"##о\": 14150,\n      \"##fly\": 14151,\n      \"successes\": 14152,\n      \"unexpectedly\": 14153,\n      \"blu\": 14154,\n      \"assessed\": 14155,\n      \"##flower\": 14156,\n      \"##ه\": 14157,\n      \"observing\": 14158,\n      \"sacked\": 14159,\n      \"spiders\": 14160,\n      \"kn\": 14161,\n      \"##tail\": 14162,\n      \"mu\": 14163,\n      \"nodes\": 14164,\n      \"prosperity\": 14165,\n      \"audrey\": 14166,\n      \"divisional\": 14167,\n      \"155\": 14168,\n      \"broncos\": 14169,\n      \"tangled\": 14170,\n      \"adjust\": 14171,\n      \"feeds\": 14172,\n      \"erosion\": 14173,\n      \"paolo\": 14174,\n      \"surf\": 14175,\n      \"directory\": 14176,\n      \"snatched\": 14177,\n      \"humid\": 14178,\n      \"admiralty\": 14179,\n      \"screwed\": 14180,\n      \"gt\": 14181,\n      \"reddish\": 14182,\n      \"##nese\": 14183,\n      \"modules\": 14184,\n      \"trench\": 14185,\n      \"lamps\": 14186,\n      \"bind\": 14187,\n      \"leah\": 14188,\n      \"bucks\": 14189,\n      \"competes\": 14190,\n      \"##nz\": 14191,\n      \"##form\": 14192,\n      \"transcription\": 14193,\n      \"##uc\": 14194,\n      \"isles\": 14195,\n      \"violently\": 14196,\n      \"clutching\": 14197,\n      \"pga\": 14198,\n      \"cyclist\": 14199,\n      \"inflation\": 14200,\n      \"flats\": 14201,\n      \"ragged\": 14202,\n      \"unnecessary\": 14203,\n      \"##hian\": 14204,\n      \"stubborn\": 14205,\n      \"coordinated\": 14206,\n      \"harriet\": 14207,\n      \"baba\": 14208,\n      \"disqualified\": 14209,\n      \"330\": 14210,\n      \"insect\": 14211,\n      \"wolfe\": 14212,\n      \"##fies\": 14213,\n      \"reinforcements\": 14214,\n      \"rocked\": 14215,\n      \"duel\": 14216,\n      \"winked\": 14217,\n      \"embraced\": 14218,\n      \"bricks\": 14219,\n      \"##raj\": 14220,\n      \"hiatus\": 14221,\n      \"defeats\": 14222,\n      \"pending\": 14223,\n      \"brightly\": 14224,\n      \"jealousy\": 14225,\n      \"##xton\": 14226,\n      \"##hm\": 14227,\n      \"##uki\": 14228,\n      \"lena\": 14229,\n      \"gdp\": 14230,\n      \"colorful\": 14231,\n      \"##dley\": 14232,\n      \"stein\": 14233,\n      \"kidney\": 14234,\n      \"##shu\": 14235,\n      \"underwear\": 14236,\n      \"wanderers\": 14237,\n      \"##haw\": 14238,\n      \"##icus\": 14239,\n      \"guardians\": 14240,\n      \"m³\": 14241,\n      \"roared\": 14242,\n      \"habits\": 14243,\n      \"##wise\": 14244,\n      \"permits\": 14245,\n      \"gp\": 14246,\n      \"uranium\": 14247,\n      \"punished\": 14248,\n      \"disguise\": 14249,\n      \"bundesliga\": 14250,\n      \"elise\": 14251,\n      \"dundee\": 14252,\n      \"erotic\": 14253,\n      \"partisan\": 14254,\n      \"pi\": 14255,\n      \"collectors\": 14256,\n      \"float\": 14257,\n      \"individually\": 14258,\n      \"rendering\": 14259,\n      \"behavioral\": 14260,\n      \"bucharest\": 14261,\n      \"ser\": 14262,\n      \"hare\": 14263,\n      \"valerie\": 14264,\n      \"corporal\": 14265,\n      \"nutrition\": 14266,\n      \"proportional\": 14267,\n      \"##isa\": 14268,\n      \"immense\": 14269,\n      \"##kis\": 14270,\n      \"pavement\": 14271,\n      \"##zie\": 14272,\n      \"##eld\": 14273,\n      \"sutherland\": 14274,\n      \"crouched\": 14275,\n      \"1775\": 14276,\n      \"##lp\": 14277,\n      \"suzuki\": 14278,\n      \"trades\": 14279,\n      \"endurance\": 14280,\n      \"operas\": 14281,\n      \"crosby\": 14282,\n      \"prayed\": 14283,\n      \"priory\": 14284,\n      \"rory\": 14285,\n      \"socially\": 14286,\n      \"##urn\": 14287,\n      \"gujarat\": 14288,\n      \"##pu\": 14289,\n      \"walton\": 14290,\n      \"cube\": 14291,\n      \"pasha\": 14292,\n      \"privilege\": 14293,\n      \"lennon\": 14294,\n      \"floods\": 14295,\n      \"thorne\": 14296,\n      \"waterfall\": 14297,\n      \"nipple\": 14298,\n      \"scouting\": 14299,\n      \"approve\": 14300,\n      \"##lov\": 14301,\n      \"minorities\": 14302,\n      \"voter\": 14303,\n      \"dwight\": 14304,\n      \"extensions\": 14305,\n      \"assure\": 14306,\n      \"ballroom\": 14307,\n      \"slap\": 14308,\n      \"dripping\": 14309,\n      \"privileges\": 14310,\n      \"rejoined\": 14311,\n      \"confessed\": 14312,\n      \"demonstrating\": 14313,\n      \"patriotic\": 14314,\n      \"yell\": 14315,\n      \"investor\": 14316,\n      \"##uth\": 14317,\n      \"pagan\": 14318,\n      \"slumped\": 14319,\n      \"squares\": 14320,\n      \"##cle\": 14321,\n      \"##kins\": 14322,\n      \"confront\": 14323,\n      \"bert\": 14324,\n      \"embarrassment\": 14325,\n      \"##aid\": 14326,\n      \"aston\": 14327,\n      \"urging\": 14328,\n      \"sweater\": 14329,\n      \"starr\": 14330,\n      \"yuri\": 14331,\n      \"brains\": 14332,\n      \"williamson\": 14333,\n      \"commuter\": 14334,\n      \"mortar\": 14335,\n      \"structured\": 14336,\n      \"selfish\": 14337,\n      \"exports\": 14338,\n      \"##jon\": 14339,\n      \"cds\": 14340,\n      \"##him\": 14341,\n      \"unfinished\": 14342,\n      \"##rre\": 14343,\n      \"mortgage\": 14344,\n      \"destinations\": 14345,\n      \"##nagar\": 14346,\n      \"canoe\": 14347,\n      \"solitary\": 14348,\n      \"buchanan\": 14349,\n      \"delays\": 14350,\n      \"magistrate\": 14351,\n      \"fk\": 14352,\n      \"##pling\": 14353,\n      \"motivation\": 14354,\n      \"##lier\": 14355,\n      \"##vier\": 14356,\n      \"recruiting\": 14357,\n      \"assess\": 14358,\n      \"##mouth\": 14359,\n      \"malik\": 14360,\n      \"antique\": 14361,\n      \"1791\": 14362,\n      \"pius\": 14363,\n      \"rahman\": 14364,\n      \"reich\": 14365,\n      \"tub\": 14366,\n      \"zhou\": 14367,\n      \"smashed\": 14368,\n      \"airs\": 14369,\n      \"galway\": 14370,\n      \"xii\": 14371,\n      \"conditioning\": 14372,\n      \"honduras\": 14373,\n      \"discharged\": 14374,\n      \"dexter\": 14375,\n      \"##pf\": 14376,\n      \"lionel\": 14377,\n      \"129\": 14378,\n      \"debates\": 14379,\n      \"lemon\": 14380,\n      \"tiffany\": 14381,\n      \"volunteered\": 14382,\n      \"dom\": 14383,\n      \"dioxide\": 14384,\n      \"procession\": 14385,\n      \"devi\": 14386,\n      \"sic\": 14387,\n      \"tremendous\": 14388,\n      \"advertisements\": 14389,\n      \"colts\": 14390,\n      \"transferring\": 14391,\n      \"verdict\": 14392,\n      \"hanover\": 14393,\n      \"decommissioned\": 14394,\n      \"utter\": 14395,\n      \"relate\": 14396,\n      \"pac\": 14397,\n      \"racism\": 14398,\n      \"##top\": 14399,\n      \"beacon\": 14400,\n      \"limp\": 14401,\n      \"similarity\": 14402,\n      \"terra\": 14403,\n      \"occurrence\": 14404,\n      \"ant\": 14405,\n      \"##how\": 14406,\n      \"becky\": 14407,\n      \"capt\": 14408,\n      \"updates\": 14409,\n      \"armament\": 14410,\n      \"richie\": 14411,\n      \"pal\": 14412,\n      \"##graph\": 14413,\n      \"halloween\": 14414,\n      \"mayo\": 14415,\n      \"##ssen\": 14416,\n      \"##bone\": 14417,\n      \"cara\": 14418,\n      \"serena\": 14419,\n      \"fcc\": 14420,\n      \"dolls\": 14421,\n      \"obligations\": 14422,\n      \"##dling\": 14423,\n      \"violated\": 14424,\n      \"lafayette\": 14425,\n      \"jakarta\": 14426,\n      \"exploitation\": 14427,\n      \"##ime\": 14428,\n      \"infamous\": 14429,\n      \"iconic\": 14430,\n      \"##lah\": 14431,\n      \"##park\": 14432,\n      \"kitty\": 14433,\n      \"moody\": 14434,\n      \"reginald\": 14435,\n      \"dread\": 14436,\n      \"spill\": 14437,\n      \"crystals\": 14438,\n      \"olivier\": 14439,\n      \"modeled\": 14440,\n      \"bluff\": 14441,\n      \"equilibrium\": 14442,\n      \"separating\": 14443,\n      \"notices\": 14444,\n      \"ordnance\": 14445,\n      \"extinction\": 14446,\n      \"onset\": 14447,\n      \"cosmic\": 14448,\n      \"attachment\": 14449,\n      \"sammy\": 14450,\n      \"expose\": 14451,\n      \"privy\": 14452,\n      \"anchored\": 14453,\n      \"##bil\": 14454,\n      \"abbott\": 14455,\n      \"admits\": 14456,\n      \"bending\": 14457,\n      \"baritone\": 14458,\n      \"emmanuel\": 14459,\n      \"policeman\": 14460,\n      \"vaughan\": 14461,\n      \"winged\": 14462,\n      \"climax\": 14463,\n      \"dresses\": 14464,\n      \"denny\": 14465,\n      \"polytechnic\": 14466,\n      \"mohamed\": 14467,\n      \"burmese\": 14468,\n      \"authentic\": 14469,\n      \"nikki\": 14470,\n      \"genetics\": 14471,\n      \"grandparents\": 14472,\n      \"homestead\": 14473,\n      \"gaza\": 14474,\n      \"postponed\": 14475,\n      \"metacritic\": 14476,\n      \"una\": 14477,\n      \"##sby\": 14478,\n      \"##bat\": 14479,\n      \"unstable\": 14480,\n      \"dissertation\": 14481,\n      \"##rial\": 14482,\n      \"##cian\": 14483,\n      \"curls\": 14484,\n      \"obscure\": 14485,\n      \"uncovered\": 14486,\n      \"bronx\": 14487,\n      \"praying\": 14488,\n      \"disappearing\": 14489,\n      \"##hoe\": 14490,\n      \"prehistoric\": 14491,\n      \"coke\": 14492,\n      \"turret\": 14493,\n      \"mutations\": 14494,\n      \"nonprofit\": 14495,\n      \"pits\": 14496,\n      \"monaco\": 14497,\n      \"##ي\": 14498,\n      \"##usion\": 14499,\n      \"prominently\": 14500,\n      \"dispatched\": 14501,\n      \"podium\": 14502,\n      \"##mir\": 14503,\n      \"uci\": 14504,\n      \"##uation\": 14505,\n      \"133\": 14506,\n      \"fortifications\": 14507,\n      \"birthplace\": 14508,\n      \"kendall\": 14509,\n      \"##lby\": 14510,\n      \"##oll\": 14511,\n      \"preacher\": 14512,\n      \"rack\": 14513,\n      \"goodman\": 14514,\n      \"##rman\": 14515,\n      \"persistent\": 14516,\n      \"##ott\": 14517,\n      \"countless\": 14518,\n      \"jaime\": 14519,\n      \"recorder\": 14520,\n      \"lexington\": 14521,\n      \"persecution\": 14522,\n      \"jumps\": 14523,\n      \"renewal\": 14524,\n      \"wagons\": 14525,\n      \"##11\": 14526,\n      \"crushing\": 14527,\n      \"##holder\": 14528,\n      \"decorations\": 14529,\n      \"##lake\": 14530,\n      \"abundance\": 14531,\n      \"wrath\": 14532,\n      \"laundry\": 14533,\n      \"£1\": 14534,\n      \"garde\": 14535,\n      \"##rp\": 14536,\n      \"jeanne\": 14537,\n      \"beetles\": 14538,\n      \"peasant\": 14539,\n      \"##sl\": 14540,\n      \"splitting\": 14541,\n      \"caste\": 14542,\n      \"sergei\": 14543,\n      \"##rer\": 14544,\n      \"##ema\": 14545,\n      \"scripts\": 14546,\n      \"##ively\": 14547,\n      \"rub\": 14548,\n      \"satellites\": 14549,\n      \"##vor\": 14550,\n      \"inscribed\": 14551,\n      \"verlag\": 14552,\n      \"scrapped\": 14553,\n      \"gale\": 14554,\n      \"packages\": 14555,\n      \"chick\": 14556,\n      \"potato\": 14557,\n      \"slogan\": 14558,\n      \"kathleen\": 14559,\n      \"arabs\": 14560,\n      \"##culture\": 14561,\n      \"counterparts\": 14562,\n      \"reminiscent\": 14563,\n      \"choral\": 14564,\n      \"##tead\": 14565,\n      \"rand\": 14566,\n      \"retains\": 14567,\n      \"bushes\": 14568,\n      \"dane\": 14569,\n      \"accomplish\": 14570,\n      \"courtesy\": 14571,\n      \"closes\": 14572,\n      \"##oth\": 14573,\n      \"slaughter\": 14574,\n      \"hague\": 14575,\n      \"krakow\": 14576,\n      \"lawson\": 14577,\n      \"tailed\": 14578,\n      \"elias\": 14579,\n      \"ginger\": 14580,\n      \"##ttes\": 14581,\n      \"canopy\": 14582,\n      \"betrayal\": 14583,\n      \"rebuilding\": 14584,\n      \"turf\": 14585,\n      \"##hof\": 14586,\n      \"frowning\": 14587,\n      \"allegiance\": 14588,\n      \"brigades\": 14589,\n      \"kicks\": 14590,\n      \"rebuild\": 14591,\n      \"polls\": 14592,\n      \"alias\": 14593,\n      \"nationalism\": 14594,\n      \"td\": 14595,\n      \"rowan\": 14596,\n      \"audition\": 14597,\n      \"bowie\": 14598,\n      \"fortunately\": 14599,\n      \"recognizes\": 14600,\n      \"harp\": 14601,\n      \"dillon\": 14602,\n      \"horrified\": 14603,\n      \"##oro\": 14604,\n      \"renault\": 14605,\n      \"##tics\": 14606,\n      \"ropes\": 14607,\n      \"##α\": 14608,\n      \"presumed\": 14609,\n      \"rewarded\": 14610,\n      \"infrared\": 14611,\n      \"wiping\": 14612,\n      \"accelerated\": 14613,\n      \"illustration\": 14614,\n      \"##rid\": 14615,\n      \"presses\": 14616,\n      \"practitioners\": 14617,\n      \"badminton\": 14618,\n      \"##iard\": 14619,\n      \"detained\": 14620,\n      \"##tera\": 14621,\n      \"recognizing\": 14622,\n      \"relates\": 14623,\n      \"misery\": 14624,\n      \"##sies\": 14625,\n      \"##tly\": 14626,\n      \"reproduction\": 14627,\n      \"piercing\": 14628,\n      \"potatoes\": 14629,\n      \"thornton\": 14630,\n      \"esther\": 14631,\n      \"manners\": 14632,\n      \"hbo\": 14633,\n      \"##aan\": 14634,\n      \"ours\": 14635,\n      \"bullshit\": 14636,\n      \"ernie\": 14637,\n      \"perennial\": 14638,\n      \"sensitivity\": 14639,\n      \"illuminated\": 14640,\n      \"rupert\": 14641,\n      \"##jin\": 14642,\n      \"##iss\": 14643,\n      \"##ear\": 14644,\n      \"rfc\": 14645,\n      \"nassau\": 14646,\n      \"##dock\": 14647,\n      \"staggered\": 14648,\n      \"socialism\": 14649,\n      \"##haven\": 14650,\n      \"appointments\": 14651,\n      \"nonsense\": 14652,\n      \"prestige\": 14653,\n      \"sharma\": 14654,\n      \"haul\": 14655,\n      \"##tical\": 14656,\n      \"solidarity\": 14657,\n      \"gps\": 14658,\n      \"##ook\": 14659,\n      \"##rata\": 14660,\n      \"igor\": 14661,\n      \"pedestrian\": 14662,\n      \"##uit\": 14663,\n      \"baxter\": 14664,\n      \"tenants\": 14665,\n      \"wires\": 14666,\n      \"medication\": 14667,\n      \"unlimited\": 14668,\n      \"guiding\": 14669,\n      \"impacts\": 14670,\n      \"diabetes\": 14671,\n      \"##rama\": 14672,\n      \"sasha\": 14673,\n      \"pas\": 14674,\n      \"clive\": 14675,\n      \"extraction\": 14676,\n      \"131\": 14677,\n      \"continually\": 14678,\n      \"constraints\": 14679,\n      \"##bilities\": 14680,\n      \"sonata\": 14681,\n      \"hunted\": 14682,\n      \"sixteenth\": 14683,\n      \"chu\": 14684,\n      \"planting\": 14685,\n      \"quote\": 14686,\n      \"mayer\": 14687,\n      \"pretended\": 14688,\n      \"abs\": 14689,\n      \"spat\": 14690,\n      \"##hua\": 14691,\n      \"ceramic\": 14692,\n      \"##cci\": 14693,\n      \"curtains\": 14694,\n      \"pigs\": 14695,\n      \"pitching\": 14696,\n      \"##dad\": 14697,\n      \"latvian\": 14698,\n      \"sore\": 14699,\n      \"dayton\": 14700,\n      \"##sted\": 14701,\n      \"##qi\": 14702,\n      \"patrols\": 14703,\n      \"slice\": 14704,\n      \"playground\": 14705,\n      \"##nted\": 14706,\n      \"shone\": 14707,\n      \"stool\": 14708,\n      \"apparatus\": 14709,\n      \"inadequate\": 14710,\n      \"mates\": 14711,\n      \"treason\": 14712,\n      \"##ija\": 14713,\n      \"desires\": 14714,\n      \"##liga\": 14715,\n      \"##croft\": 14716,\n      \"somalia\": 14717,\n      \"laurent\": 14718,\n      \"mir\": 14719,\n      \"leonardo\": 14720,\n      \"oracle\": 14721,\n      \"grape\": 14722,\n      \"obliged\": 14723,\n      \"chevrolet\": 14724,\n      \"thirteenth\": 14725,\n      \"stunning\": 14726,\n      \"enthusiastic\": 14727,\n      \"##ede\": 14728,\n      \"accounted\": 14729,\n      \"concludes\": 14730,\n      \"currents\": 14731,\n      \"basil\": 14732,\n      \"##kovic\": 14733,\n      \"drought\": 14734,\n      \"##rica\": 14735,\n      \"mai\": 14736,\n      \"##aire\": 14737,\n      \"shove\": 14738,\n      \"posting\": 14739,\n      \"##shed\": 14740,\n      \"pilgrimage\": 14741,\n      \"humorous\": 14742,\n      \"packing\": 14743,\n      \"fry\": 14744,\n      \"pencil\": 14745,\n      \"wines\": 14746,\n      \"smells\": 14747,\n      \"144\": 14748,\n      \"marilyn\": 14749,\n      \"aching\": 14750,\n      \"newest\": 14751,\n      \"clung\": 14752,\n      \"bon\": 14753,\n      \"neighbours\": 14754,\n      \"sanctioned\": 14755,\n      \"##pie\": 14756,\n      \"mug\": 14757,\n      \"##stock\": 14758,\n      \"drowning\": 14759,\n      \"##mma\": 14760,\n      \"hydraulic\": 14761,\n      \"##vil\": 14762,\n      \"hiring\": 14763,\n      \"reminder\": 14764,\n      \"lilly\": 14765,\n      \"investigators\": 14766,\n      \"##ncies\": 14767,\n      \"sour\": 14768,\n      \"##eous\": 14769,\n      \"compulsory\": 14770,\n      \"packet\": 14771,\n      \"##rion\": 14772,\n      \"##graphic\": 14773,\n      \"##elle\": 14774,\n      \"cannes\": 14775,\n      \"##inate\": 14776,\n      \"depressed\": 14777,\n      \"##rit\": 14778,\n      \"heroic\": 14779,\n      \"importantly\": 14780,\n      \"theresa\": 14781,\n      \"##tled\": 14782,\n      \"conway\": 14783,\n      \"saturn\": 14784,\n      \"marginal\": 14785,\n      \"rae\": 14786,\n      \"##xia\": 14787,\n      \"corresponds\": 14788,\n      \"royce\": 14789,\n      \"pact\": 14790,\n      \"jasper\": 14791,\n      \"explosives\": 14792,\n      \"packaging\": 14793,\n      \"aluminium\": 14794,\n      \"##ttered\": 14795,\n      \"denotes\": 14796,\n      \"rhythmic\": 14797,\n      \"spans\": 14798,\n      \"assignments\": 14799,\n      \"hereditary\": 14800,\n      \"outlined\": 14801,\n      \"originating\": 14802,\n      \"sundays\": 14803,\n      \"lad\": 14804,\n      \"reissued\": 14805,\n      \"greeting\": 14806,\n      \"beatrice\": 14807,\n      \"##dic\": 14808,\n      \"pillar\": 14809,\n      \"marcos\": 14810,\n      \"plots\": 14811,\n      \"handbook\": 14812,\n      \"alcoholic\": 14813,\n      \"judiciary\": 14814,\n      \"avant\": 14815,\n      \"slides\": 14816,\n      \"extract\": 14817,\n      \"masculine\": 14818,\n      \"blur\": 14819,\n      \"##eum\": 14820,\n      \"##force\": 14821,\n      \"homage\": 14822,\n      \"trembled\": 14823,\n      \"owens\": 14824,\n      \"hymn\": 14825,\n      \"trey\": 14826,\n      \"omega\": 14827,\n      \"signaling\": 14828,\n      \"socks\": 14829,\n      \"accumulated\": 14830,\n      \"reacted\": 14831,\n      \"attic\": 14832,\n      \"theo\": 14833,\n      \"lining\": 14834,\n      \"angie\": 14835,\n      \"distraction\": 14836,\n      \"primera\": 14837,\n      \"talbot\": 14838,\n      \"##key\": 14839,\n      \"1200\": 14840,\n      \"ti\": 14841,\n      \"creativity\": 14842,\n      \"billed\": 14843,\n      \"##hey\": 14844,\n      \"deacon\": 14845,\n      \"eduardo\": 14846,\n      \"identifies\": 14847,\n      \"proposition\": 14848,\n      \"dizzy\": 14849,\n      \"gunner\": 14850,\n      \"hogan\": 14851,\n      \"##yam\": 14852,\n      \"##pping\": 14853,\n      \"##hol\": 14854,\n      \"ja\": 14855,\n      \"##chan\": 14856,\n      \"jensen\": 14857,\n      \"reconstructed\": 14858,\n      \"##berger\": 14859,\n      \"clearance\": 14860,\n      \"darius\": 14861,\n      \"##nier\": 14862,\n      \"abe\": 14863,\n      \"harlem\": 14864,\n      \"plea\": 14865,\n      \"dei\": 14866,\n      \"circled\": 14867,\n      \"emotionally\": 14868,\n      \"notation\": 14869,\n      \"fascist\": 14870,\n      \"neville\": 14871,\n      \"exceeded\": 14872,\n      \"upwards\": 14873,\n      \"viable\": 14874,\n      \"ducks\": 14875,\n      \"##fo\": 14876,\n      \"workforce\": 14877,\n      \"racer\": 14878,\n      \"limiting\": 14879,\n      \"shri\": 14880,\n      \"##lson\": 14881,\n      \"possesses\": 14882,\n      \"1600\": 14883,\n      \"kerr\": 14884,\n      \"moths\": 14885,\n      \"devastating\": 14886,\n      \"laden\": 14887,\n      \"disturbing\": 14888,\n      \"locking\": 14889,\n      \"##cture\": 14890,\n      \"gal\": 14891,\n      \"fearing\": 14892,\n      \"accreditation\": 14893,\n      \"flavor\": 14894,\n      \"aide\": 14895,\n      \"1870s\": 14896,\n      \"mountainous\": 14897,\n      \"##baum\": 14898,\n      \"melt\": 14899,\n      \"##ures\": 14900,\n      \"motel\": 14901,\n      \"texture\": 14902,\n      \"servers\": 14903,\n      \"soda\": 14904,\n      \"##mb\": 14905,\n      \"herd\": 14906,\n      \"##nium\": 14907,\n      \"erect\": 14908,\n      \"puzzled\": 14909,\n      \"hum\": 14910,\n      \"peggy\": 14911,\n      \"examinations\": 14912,\n      \"gould\": 14913,\n      \"testified\": 14914,\n      \"geoff\": 14915,\n      \"ren\": 14916,\n      \"devised\": 14917,\n      \"sacks\": 14918,\n      \"##law\": 14919,\n      \"denial\": 14920,\n      \"posters\": 14921,\n      \"grunted\": 14922,\n      \"cesar\": 14923,\n      \"tutor\": 14924,\n      \"ec\": 14925,\n      \"gerry\": 14926,\n      \"offerings\": 14927,\n      \"byrne\": 14928,\n      \"falcons\": 14929,\n      \"combinations\": 14930,\n      \"ct\": 14931,\n      \"incoming\": 14932,\n      \"pardon\": 14933,\n      \"rocking\": 14934,\n      \"26th\": 14935,\n      \"avengers\": 14936,\n      \"flared\": 14937,\n      \"mankind\": 14938,\n      \"seller\": 14939,\n      \"uttar\": 14940,\n      \"loch\": 14941,\n      \"nadia\": 14942,\n      \"stroking\": 14943,\n      \"exposing\": 14944,\n      \"##hd\": 14945,\n      \"fertile\": 14946,\n      \"ancestral\": 14947,\n      \"instituted\": 14948,\n      \"##has\": 14949,\n      \"noises\": 14950,\n      \"prophecy\": 14951,\n      \"taxation\": 14952,\n      \"eminent\": 14953,\n      \"vivid\": 14954,\n      \"pol\": 14955,\n      \"##bol\": 14956,\n      \"dart\": 14957,\n      \"indirect\": 14958,\n      \"multimedia\": 14959,\n      \"notebook\": 14960,\n      \"upside\": 14961,\n      \"displaying\": 14962,\n      \"adrenaline\": 14963,\n      \"referenced\": 14964,\n      \"geometric\": 14965,\n      \"##iving\": 14966,\n      \"progression\": 14967,\n      \"##ddy\": 14968,\n      \"blunt\": 14969,\n      \"announce\": 14970,\n      \"##far\": 14971,\n      \"implementing\": 14972,\n      \"##lav\": 14973,\n      \"aggression\": 14974,\n      \"liaison\": 14975,\n      \"cooler\": 14976,\n      \"cares\": 14977,\n      \"headache\": 14978,\n      \"plantations\": 14979,\n      \"gorge\": 14980,\n      \"dots\": 14981,\n      \"impulse\": 14982,\n      \"thickness\": 14983,\n      \"ashamed\": 14984,\n      \"averaging\": 14985,\n      \"kathy\": 14986,\n      \"obligation\": 14987,\n      \"precursor\": 14988,\n      \"137\": 14989,\n      \"fowler\": 14990,\n      \"symmetry\": 14991,\n      \"thee\": 14992,\n      \"225\": 14993,\n      \"hears\": 14994,\n      \"##rai\": 14995,\n      \"undergoing\": 14996,\n      \"ads\": 14997,\n      \"butcher\": 14998,\n      \"bowler\": 14999,\n      \"##lip\": 15000,\n      \"cigarettes\": 15001,\n      \"subscription\": 15002,\n      \"goodness\": 15003,\n      \"##ically\": 15004,\n      \"browne\": 15005,\n      \"##hos\": 15006,\n      \"##tech\": 15007,\n      \"kyoto\": 15008,\n      \"donor\": 15009,\n      \"##erty\": 15010,\n      \"damaging\": 15011,\n      \"friction\": 15012,\n      \"drifting\": 15013,\n      \"expeditions\": 15014,\n      \"hardened\": 15015,\n      \"prostitution\": 15016,\n      \"152\": 15017,\n      \"fauna\": 15018,\n      \"blankets\": 15019,\n      \"claw\": 15020,\n      \"tossing\": 15021,\n      \"snarled\": 15022,\n      \"butterflies\": 15023,\n      \"recruits\": 15024,\n      \"investigative\": 15025,\n      \"coated\": 15026,\n      \"healed\": 15027,\n      \"138\": 15028,\n      \"communal\": 15029,\n      \"hai\": 15030,\n      \"xiii\": 15031,\n      \"academics\": 15032,\n      \"boone\": 15033,\n      \"psychologist\": 15034,\n      \"restless\": 15035,\n      \"lahore\": 15036,\n      \"stephens\": 15037,\n      \"mba\": 15038,\n      \"brendan\": 15039,\n      \"foreigners\": 15040,\n      \"printer\": 15041,\n      \"##pc\": 15042,\n      \"ached\": 15043,\n      \"explode\": 15044,\n      \"27th\": 15045,\n      \"deed\": 15046,\n      \"scratched\": 15047,\n      \"dared\": 15048,\n      \"##pole\": 15049,\n      \"cardiac\": 15050,\n      \"1780\": 15051,\n      \"okinawa\": 15052,\n      \"proto\": 15053,\n      \"commando\": 15054,\n      \"compelled\": 15055,\n      \"oddly\": 15056,\n      \"electrons\": 15057,\n      \"##base\": 15058,\n      \"replica\": 15059,\n      \"thanksgiving\": 15060,\n      \"##rist\": 15061,\n      \"sheila\": 15062,\n      \"deliberate\": 15063,\n      \"stafford\": 15064,\n      \"tidal\": 15065,\n      \"representations\": 15066,\n      \"hercules\": 15067,\n      \"ou\": 15068,\n      \"##path\": 15069,\n      \"##iated\": 15070,\n      \"kidnapping\": 15071,\n      \"lenses\": 15072,\n      \"##tling\": 15073,\n      \"deficit\": 15074,\n      \"samoa\": 15075,\n      \"mouths\": 15076,\n      \"consuming\": 15077,\n      \"computational\": 15078,\n      \"maze\": 15079,\n      \"granting\": 15080,\n      \"smirk\": 15081,\n      \"razor\": 15082,\n      \"fixture\": 15083,\n      \"ideals\": 15084,\n      \"inviting\": 15085,\n      \"aiden\": 15086,\n      \"nominal\": 15087,\n      \"##vs\": 15088,\n      \"issuing\": 15089,\n      \"julio\": 15090,\n      \"pitt\": 15091,\n      \"ramsey\": 15092,\n      \"docks\": 15093,\n      \"##oss\": 15094,\n      \"exhaust\": 15095,\n      \"##owed\": 15096,\n      \"bavarian\": 15097,\n      \"draped\": 15098,\n      \"anterior\": 15099,\n      \"mating\": 15100,\n      \"ethiopian\": 15101,\n      \"explores\": 15102,\n      \"noticing\": 15103,\n      \"##nton\": 15104,\n      \"discarded\": 15105,\n      \"convenience\": 15106,\n      \"hoffman\": 15107,\n      \"endowment\": 15108,\n      \"beasts\": 15109,\n      \"cartridge\": 15110,\n      \"mormon\": 15111,\n      \"paternal\": 15112,\n      \"probe\": 15113,\n      \"sleeves\": 15114,\n      \"interfere\": 15115,\n      \"lump\": 15116,\n      \"deadline\": 15117,\n      \"##rail\": 15118,\n      \"jenks\": 15119,\n      \"bulldogs\": 15120,\n      \"scrap\": 15121,\n      \"alternating\": 15122,\n      \"justified\": 15123,\n      \"reproductive\": 15124,\n      \"nam\": 15125,\n      \"seize\": 15126,\n      \"descending\": 15127,\n      \"secretariat\": 15128,\n      \"kirby\": 15129,\n      \"coupe\": 15130,\n      \"grouped\": 15131,\n      \"smash\": 15132,\n      \"panther\": 15133,\n      \"sedan\": 15134,\n      \"tapping\": 15135,\n      \"##18\": 15136,\n      \"lola\": 15137,\n      \"cheer\": 15138,\n      \"germanic\": 15139,\n      \"unfortunate\": 15140,\n      \"##eter\": 15141,\n      \"unrelated\": 15142,\n      \"##fan\": 15143,\n      \"subordinate\": 15144,\n      \"##sdale\": 15145,\n      \"suzanne\": 15146,\n      \"advertisement\": 15147,\n      \"##ility\": 15148,\n      \"horsepower\": 15149,\n      \"##lda\": 15150,\n      \"cautiously\": 15151,\n      \"discourse\": 15152,\n      \"luigi\": 15153,\n      \"##mans\": 15154,\n      \"##fields\": 15155,\n      \"noun\": 15156,\n      \"prevalent\": 15157,\n      \"mao\": 15158,\n      \"schneider\": 15159,\n      \"everett\": 15160,\n      \"surround\": 15161,\n      \"governorate\": 15162,\n      \"kira\": 15163,\n      \"##avia\": 15164,\n      \"westward\": 15165,\n      \"##take\": 15166,\n      \"misty\": 15167,\n      \"rails\": 15168,\n      \"sustainability\": 15169,\n      \"134\": 15170,\n      \"unused\": 15171,\n      \"##rating\": 15172,\n      \"packs\": 15173,\n      \"toast\": 15174,\n      \"unwilling\": 15175,\n      \"regulate\": 15176,\n      \"thy\": 15177,\n      \"suffrage\": 15178,\n      \"nile\": 15179,\n      \"awe\": 15180,\n      \"assam\": 15181,\n      \"definitions\": 15182,\n      \"travelers\": 15183,\n      \"affordable\": 15184,\n      \"##rb\": 15185,\n      \"conferred\": 15186,\n      \"sells\": 15187,\n      \"undefeated\": 15188,\n      \"beneficial\": 15189,\n      \"torso\": 15190,\n      \"basal\": 15191,\n      \"repeating\": 15192,\n      \"remixes\": 15193,\n      \"##pass\": 15194,\n      \"bahrain\": 15195,\n      \"cables\": 15196,\n      \"fang\": 15197,\n      \"##itated\": 15198,\n      \"excavated\": 15199,\n      \"numbering\": 15200,\n      \"statutory\": 15201,\n      \"##rey\": 15202,\n      \"deluxe\": 15203,\n      \"##lian\": 15204,\n      \"forested\": 15205,\n      \"ramirez\": 15206,\n      \"derbyshire\": 15207,\n      \"zeus\": 15208,\n      \"slamming\": 15209,\n      \"transfers\": 15210,\n      \"astronomer\": 15211,\n      \"banana\": 15212,\n      \"lottery\": 15213,\n      \"berg\": 15214,\n      \"histories\": 15215,\n      \"bamboo\": 15216,\n      \"##uchi\": 15217,\n      \"resurrection\": 15218,\n      \"posterior\": 15219,\n      \"bowls\": 15220,\n      \"vaguely\": 15221,\n      \"##thi\": 15222,\n      \"thou\": 15223,\n      \"preserving\": 15224,\n      \"tensed\": 15225,\n      \"offence\": 15226,\n      \"##inas\": 15227,\n      \"meyrick\": 15228,\n      \"callum\": 15229,\n      \"ridden\": 15230,\n      \"watt\": 15231,\n      \"langdon\": 15232,\n      \"tying\": 15233,\n      \"lowland\": 15234,\n      \"snorted\": 15235,\n      \"daring\": 15236,\n      \"truman\": 15237,\n      \"##hale\": 15238,\n      \"##girl\": 15239,\n      \"aura\": 15240,\n      \"overly\": 15241,\n      \"filing\": 15242,\n      \"weighing\": 15243,\n      \"goa\": 15244,\n      \"infections\": 15245,\n      \"philanthropist\": 15246,\n      \"saunders\": 15247,\n      \"eponymous\": 15248,\n      \"##owski\": 15249,\n      \"latitude\": 15250,\n      \"perspectives\": 15251,\n      \"reviewing\": 15252,\n      \"mets\": 15253,\n      \"commandant\": 15254,\n      \"radial\": 15255,\n      \"##kha\": 15256,\n      \"flashlight\": 15257,\n      \"reliability\": 15258,\n      \"koch\": 15259,\n      \"vowels\": 15260,\n      \"amazed\": 15261,\n      \"ada\": 15262,\n      \"elaine\": 15263,\n      \"supper\": 15264,\n      \"##rth\": 15265,\n      \"##encies\": 15266,\n      \"predator\": 15267,\n      \"debated\": 15268,\n      \"soviets\": 15269,\n      \"cola\": 15270,\n      \"##boards\": 15271,\n      \"##nah\": 15272,\n      \"compartment\": 15273,\n      \"crooked\": 15274,\n      \"arbitrary\": 15275,\n      \"fourteenth\": 15276,\n      \"##ctive\": 15277,\n      \"havana\": 15278,\n      \"majors\": 15279,\n      \"steelers\": 15280,\n      \"clips\": 15281,\n      \"profitable\": 15282,\n      \"ambush\": 15283,\n      \"exited\": 15284,\n      \"packers\": 15285,\n      \"##tile\": 15286,\n      \"nude\": 15287,\n      \"cracks\": 15288,\n      \"fungi\": 15289,\n      \"##е\": 15290,\n      \"limb\": 15291,\n      \"trousers\": 15292,\n      \"josie\": 15293,\n      \"shelby\": 15294,\n      \"tens\": 15295,\n      \"frederic\": 15296,\n      \"##ος\": 15297,\n      \"definite\": 15298,\n      \"smoothly\": 15299,\n      \"constellation\": 15300,\n      \"insult\": 15301,\n      \"baton\": 15302,\n      \"discs\": 15303,\n      \"lingering\": 15304,\n      \"##nco\": 15305,\n      \"conclusions\": 15306,\n      \"lent\": 15307,\n      \"staging\": 15308,\n      \"becker\": 15309,\n      \"grandpa\": 15310,\n      \"shaky\": 15311,\n      \"##tron\": 15312,\n      \"einstein\": 15313,\n      \"obstacles\": 15314,\n      \"sk\": 15315,\n      \"adverse\": 15316,\n      \"elle\": 15317,\n      \"economically\": 15318,\n      \"##moto\": 15319,\n      \"mccartney\": 15320,\n      \"thor\": 15321,\n      \"dismissal\": 15322,\n      \"motions\": 15323,\n      \"readings\": 15324,\n      \"nostrils\": 15325,\n      \"treatise\": 15326,\n      \"##pace\": 15327,\n      \"squeezing\": 15328,\n      \"evidently\": 15329,\n      \"prolonged\": 15330,\n      \"1783\": 15331,\n      \"venezuelan\": 15332,\n      \"je\": 15333,\n      \"marguerite\": 15334,\n      \"beirut\": 15335,\n      \"takeover\": 15336,\n      \"shareholders\": 15337,\n      \"##vent\": 15338,\n      \"denise\": 15339,\n      \"digit\": 15340,\n      \"airplay\": 15341,\n      \"norse\": 15342,\n      \"##bbling\": 15343,\n      \"imaginary\": 15344,\n      \"pills\": 15345,\n      \"hubert\": 15346,\n      \"blaze\": 15347,\n      \"vacated\": 15348,\n      \"eliminating\": 15349,\n      \"##ello\": 15350,\n      \"vine\": 15351,\n      \"mansfield\": 15352,\n      \"##tty\": 15353,\n      \"retrospective\": 15354,\n      \"barrow\": 15355,\n      \"borne\": 15356,\n      \"clutch\": 15357,\n      \"bail\": 15358,\n      \"forensic\": 15359,\n      \"weaving\": 15360,\n      \"##nett\": 15361,\n      \"##witz\": 15362,\n      \"desktop\": 15363,\n      \"citadel\": 15364,\n      \"promotions\": 15365,\n      \"worrying\": 15366,\n      \"dorset\": 15367,\n      \"ieee\": 15368,\n      \"subdivided\": 15369,\n      \"##iating\": 15370,\n      \"manned\": 15371,\n      \"expeditionary\": 15372,\n      \"pickup\": 15373,\n      \"synod\": 15374,\n      \"chuckle\": 15375,\n      \"185\": 15376,\n      \"barney\": 15377,\n      \"##rz\": 15378,\n      \"##ffin\": 15379,\n      \"functionality\": 15380,\n      \"karachi\": 15381,\n      \"litigation\": 15382,\n      \"meanings\": 15383,\n      \"uc\": 15384,\n      \"lick\": 15385,\n      \"turbo\": 15386,\n      \"anders\": 15387,\n      \"##ffed\": 15388,\n      \"execute\": 15389,\n      \"curl\": 15390,\n      \"oppose\": 15391,\n      \"ankles\": 15392,\n      \"typhoon\": 15393,\n      \"##د\": 15394,\n      \"##ache\": 15395,\n      \"##asia\": 15396,\n      \"linguistics\": 15397,\n      \"compassion\": 15398,\n      \"pressures\": 15399,\n      \"grazing\": 15400,\n      \"perfection\": 15401,\n      \"##iting\": 15402,\n      \"immunity\": 15403,\n      \"monopoly\": 15404,\n      \"muddy\": 15405,\n      \"backgrounds\": 15406,\n      \"136\": 15407,\n      \"namibia\": 15408,\n      \"francesca\": 15409,\n      \"monitors\": 15410,\n      \"attracting\": 15411,\n      \"stunt\": 15412,\n      \"tuition\": 15413,\n      \"##ии\": 15414,\n      \"vegetable\": 15415,\n      \"##mates\": 15416,\n      \"##quent\": 15417,\n      \"mgm\": 15418,\n      \"jen\": 15419,\n      \"complexes\": 15420,\n      \"forts\": 15421,\n      \"##ond\": 15422,\n      \"cellar\": 15423,\n      \"bites\": 15424,\n      \"seventeenth\": 15425,\n      \"royals\": 15426,\n      \"flemish\": 15427,\n      \"failures\": 15428,\n      \"mast\": 15429,\n      \"charities\": 15430,\n      \"##cular\": 15431,\n      \"peruvian\": 15432,\n      \"capitals\": 15433,\n      \"macmillan\": 15434,\n      \"ipswich\": 15435,\n      \"outward\": 15436,\n      \"frigate\": 15437,\n      \"postgraduate\": 15438,\n      \"folds\": 15439,\n      \"employing\": 15440,\n      \"##ouse\": 15441,\n      \"concurrently\": 15442,\n      \"fiery\": 15443,\n      \"##tai\": 15444,\n      \"contingent\": 15445,\n      \"nightmares\": 15446,\n      \"monumental\": 15447,\n      \"nicaragua\": 15448,\n      \"##kowski\": 15449,\n      \"lizard\": 15450,\n      \"mal\": 15451,\n      \"fielding\": 15452,\n      \"gig\": 15453,\n      \"reject\": 15454,\n      \"##pad\": 15455,\n      \"harding\": 15456,\n      \"##ipe\": 15457,\n      \"coastline\": 15458,\n      \"##cin\": 15459,\n      \"##nos\": 15460,\n      \"beethoven\": 15461,\n      \"humphrey\": 15462,\n      \"innovations\": 15463,\n      \"##tam\": 15464,\n      \"##nge\": 15465,\n      \"norris\": 15466,\n      \"doris\": 15467,\n      \"solicitor\": 15468,\n      \"huang\": 15469,\n      \"obey\": 15470,\n      \"141\": 15471,\n      \"##lc\": 15472,\n      \"niagara\": 15473,\n      \"##tton\": 15474,\n      \"shelves\": 15475,\n      \"aug\": 15476,\n      \"bourbon\": 15477,\n      \"curry\": 15478,\n      \"nightclub\": 15479,\n      \"specifications\": 15480,\n      \"hilton\": 15481,\n      \"##ndo\": 15482,\n      \"centennial\": 15483,\n      \"dispersed\": 15484,\n      \"worm\": 15485,\n      \"neglected\": 15486,\n      \"briggs\": 15487,\n      \"sm\": 15488,\n      \"font\": 15489,\n      \"kuala\": 15490,\n      \"uneasy\": 15491,\n      \"plc\": 15492,\n      \"##nstein\": 15493,\n      \"##bound\": 15494,\n      \"##aking\": 15495,\n      \"##burgh\": 15496,\n      \"awaiting\": 15497,\n      \"pronunciation\": 15498,\n      \"##bbed\": 15499,\n      \"##quest\": 15500,\n      \"eh\": 15501,\n      \"optimal\": 15502,\n      \"zhu\": 15503,\n      \"raped\": 15504,\n      \"greens\": 15505,\n      \"presided\": 15506,\n      \"brenda\": 15507,\n      \"worries\": 15508,\n      \"##life\": 15509,\n      \"venetian\": 15510,\n      \"marxist\": 15511,\n      \"turnout\": 15512,\n      \"##lius\": 15513,\n      \"refined\": 15514,\n      \"braced\": 15515,\n      \"sins\": 15516,\n      \"grasped\": 15517,\n      \"sunderland\": 15518,\n      \"nickel\": 15519,\n      \"speculated\": 15520,\n      \"lowell\": 15521,\n      \"cyrillic\": 15522,\n      \"communism\": 15523,\n      \"fundraising\": 15524,\n      \"resembling\": 15525,\n      \"colonists\": 15526,\n      \"mutant\": 15527,\n      \"freddie\": 15528,\n      \"usc\": 15529,\n      \"##mos\": 15530,\n      \"gratitude\": 15531,\n      \"##run\": 15532,\n      \"mural\": 15533,\n      \"##lous\": 15534,\n      \"chemist\": 15535,\n      \"wi\": 15536,\n      \"reminds\": 15537,\n      \"28th\": 15538,\n      \"steals\": 15539,\n      \"tess\": 15540,\n      \"pietro\": 15541,\n      \"##ingen\": 15542,\n      \"promoter\": 15543,\n      \"ri\": 15544,\n      \"microphone\": 15545,\n      \"honoured\": 15546,\n      \"rai\": 15547,\n      \"sant\": 15548,\n      \"##qui\": 15549,\n      \"feather\": 15550,\n      \"##nson\": 15551,\n      \"burlington\": 15552,\n      \"kurdish\": 15553,\n      \"terrorists\": 15554,\n      \"deborah\": 15555,\n      \"sickness\": 15556,\n      \"##wed\": 15557,\n      \"##eet\": 15558,\n      \"hazard\": 15559,\n      \"irritated\": 15560,\n      \"desperation\": 15561,\n      \"veil\": 15562,\n      \"clarity\": 15563,\n      \"##rik\": 15564,\n      \"jewels\": 15565,\n      \"xv\": 15566,\n      \"##gged\": 15567,\n      \"##ows\": 15568,\n      \"##cup\": 15569,\n      \"berkshire\": 15570,\n      \"unfair\": 15571,\n      \"mysteries\": 15572,\n      \"orchid\": 15573,\n      \"winced\": 15574,\n      \"exhaustion\": 15575,\n      \"renovations\": 15576,\n      \"stranded\": 15577,\n      \"obe\": 15578,\n      \"infinity\": 15579,\n      \"##nies\": 15580,\n      \"adapt\": 15581,\n      \"redevelopment\": 15582,\n      \"thanked\": 15583,\n      \"registry\": 15584,\n      \"olga\": 15585,\n      \"domingo\": 15586,\n      \"noir\": 15587,\n      \"tudor\": 15588,\n      \"ole\": 15589,\n      \"##atus\": 15590,\n      \"commenting\": 15591,\n      \"behaviors\": 15592,\n      \"##ais\": 15593,\n      \"crisp\": 15594,\n      \"pauline\": 15595,\n      \"probable\": 15596,\n      \"stirling\": 15597,\n      \"wigan\": 15598,\n      \"##bian\": 15599,\n      \"paralympics\": 15600,\n      \"panting\": 15601,\n      \"surpassed\": 15602,\n      \"##rew\": 15603,\n      \"luca\": 15604,\n      \"barred\": 15605,\n      \"pony\": 15606,\n      \"famed\": 15607,\n      \"##sters\": 15608,\n      \"cassandra\": 15609,\n      \"waiter\": 15610,\n      \"carolyn\": 15611,\n      \"exported\": 15612,\n      \"##orted\": 15613,\n      \"andres\": 15614,\n      \"destructive\": 15615,\n      \"deeds\": 15616,\n      \"jonah\": 15617,\n      \"castles\": 15618,\n      \"vacancy\": 15619,\n      \"suv\": 15620,\n      \"##glass\": 15621,\n      \"1788\": 15622,\n      \"orchard\": 15623,\n      \"yep\": 15624,\n      \"famine\": 15625,\n      \"belarusian\": 15626,\n      \"sprang\": 15627,\n      \"##forth\": 15628,\n      \"skinny\": 15629,\n      \"##mis\": 15630,\n      \"administrators\": 15631,\n      \"rotterdam\": 15632,\n      \"zambia\": 15633,\n      \"zhao\": 15634,\n      \"boiler\": 15635,\n      \"discoveries\": 15636,\n      \"##ride\": 15637,\n      \"##physics\": 15638,\n      \"lucius\": 15639,\n      \"disappointing\": 15640,\n      \"outreach\": 15641,\n      \"spoon\": 15642,\n      \"##frame\": 15643,\n      \"qualifications\": 15644,\n      \"unanimously\": 15645,\n      \"enjoys\": 15646,\n      \"regency\": 15647,\n      \"##iidae\": 15648,\n      \"stade\": 15649,\n      \"realism\": 15650,\n      \"veterinary\": 15651,\n      \"rodgers\": 15652,\n      \"dump\": 15653,\n      \"alain\": 15654,\n      \"chestnut\": 15655,\n      \"castile\": 15656,\n      \"censorship\": 15657,\n      \"rumble\": 15658,\n      \"gibbs\": 15659,\n      \"##itor\": 15660,\n      \"communion\": 15661,\n      \"reggae\": 15662,\n      \"inactivated\": 15663,\n      \"logs\": 15664,\n      \"loads\": 15665,\n      \"##houses\": 15666,\n      \"homosexual\": 15667,\n      \"##iano\": 15668,\n      \"ale\": 15669,\n      \"informs\": 15670,\n      \"##cas\": 15671,\n      \"phrases\": 15672,\n      \"plaster\": 15673,\n      \"linebacker\": 15674,\n      \"ambrose\": 15675,\n      \"kaiser\": 15676,\n      \"fascinated\": 15677,\n      \"850\": 15678,\n      \"limerick\": 15679,\n      \"recruitment\": 15680,\n      \"forge\": 15681,\n      \"mastered\": 15682,\n      \"##nding\": 15683,\n      \"leinster\": 15684,\n      \"rooted\": 15685,\n      \"threaten\": 15686,\n      \"##strom\": 15687,\n      \"borneo\": 15688,\n      \"##hes\": 15689,\n      \"suggestions\": 15690,\n      \"scholarships\": 15691,\n      \"propeller\": 15692,\n      \"documentaries\": 15693,\n      \"patronage\": 15694,\n      \"coats\": 15695,\n      \"constructing\": 15696,\n      \"invest\": 15697,\n      \"neurons\": 15698,\n      \"comet\": 15699,\n      \"entirety\": 15700,\n      \"shouts\": 15701,\n      \"identities\": 15702,\n      \"annoying\": 15703,\n      \"unchanged\": 15704,\n      \"wary\": 15705,\n      \"##antly\": 15706,\n      \"##ogy\": 15707,\n      \"neat\": 15708,\n      \"oversight\": 15709,\n      \"##kos\": 15710,\n      \"phillies\": 15711,\n      \"replay\": 15712,\n      \"constance\": 15713,\n      \"##kka\": 15714,\n      \"incarnation\": 15715,\n      \"humble\": 15716,\n      \"skies\": 15717,\n      \"minus\": 15718,\n      \"##acy\": 15719,\n      \"smithsonian\": 15720,\n      \"##chel\": 15721,\n      \"guerrilla\": 15722,\n      \"jar\": 15723,\n      \"cadets\": 15724,\n      \"##plate\": 15725,\n      \"surplus\": 15726,\n      \"audit\": 15727,\n      \"##aru\": 15728,\n      \"cracking\": 15729,\n      \"joanna\": 15730,\n      \"louisa\": 15731,\n      \"pacing\": 15732,\n      \"##lights\": 15733,\n      \"intentionally\": 15734,\n      \"##iri\": 15735,\n      \"diner\": 15736,\n      \"nwa\": 15737,\n      \"imprint\": 15738,\n      \"australians\": 15739,\n      \"tong\": 15740,\n      \"unprecedented\": 15741,\n      \"bunker\": 15742,\n      \"naive\": 15743,\n      \"specialists\": 15744,\n      \"ark\": 15745,\n      \"nichols\": 15746,\n      \"railing\": 15747,\n      \"leaked\": 15748,\n      \"pedal\": 15749,\n      \"##uka\": 15750,\n      \"shrub\": 15751,\n      \"longing\": 15752,\n      \"roofs\": 15753,\n      \"v8\": 15754,\n      \"captains\": 15755,\n      \"neural\": 15756,\n      \"tuned\": 15757,\n      \"##ntal\": 15758,\n      \"##jet\": 15759,\n      \"emission\": 15760,\n      \"medina\": 15761,\n      \"frantic\": 15762,\n      \"codex\": 15763,\n      \"definitive\": 15764,\n      \"sid\": 15765,\n      \"abolition\": 15766,\n      \"intensified\": 15767,\n      \"stocks\": 15768,\n      \"enrique\": 15769,\n      \"sustain\": 15770,\n      \"genoa\": 15771,\n      \"oxide\": 15772,\n      \"##written\": 15773,\n      \"clues\": 15774,\n      \"cha\": 15775,\n      \"##gers\": 15776,\n      \"tributaries\": 15777,\n      \"fragment\": 15778,\n      \"venom\": 15779,\n      \"##rity\": 15780,\n      \"##ente\": 15781,\n      \"##sca\": 15782,\n      \"muffled\": 15783,\n      \"vain\": 15784,\n      \"sire\": 15785,\n      \"laos\": 15786,\n      \"##ingly\": 15787,\n      \"##hana\": 15788,\n      \"hastily\": 15789,\n      \"snapping\": 15790,\n      \"surfaced\": 15791,\n      \"sentiment\": 15792,\n      \"motive\": 15793,\n      \"##oft\": 15794,\n      \"contests\": 15795,\n      \"approximate\": 15796,\n      \"mesa\": 15797,\n      \"luckily\": 15798,\n      \"dinosaur\": 15799,\n      \"exchanges\": 15800,\n      \"propelled\": 15801,\n      \"accord\": 15802,\n      \"bourne\": 15803,\n      \"relieve\": 15804,\n      \"tow\": 15805,\n      \"masks\": 15806,\n      \"offended\": 15807,\n      \"##ues\": 15808,\n      \"cynthia\": 15809,\n      \"##mmer\": 15810,\n      \"rains\": 15811,\n      \"bartender\": 15812,\n      \"zinc\": 15813,\n      \"reviewers\": 15814,\n      \"lois\": 15815,\n      \"##sai\": 15816,\n      \"legged\": 15817,\n      \"arrogant\": 15818,\n      \"rafe\": 15819,\n      \"rosie\": 15820,\n      \"comprise\": 15821,\n      \"handicap\": 15822,\n      \"blockade\": 15823,\n      \"inlet\": 15824,\n      \"lagoon\": 15825,\n      \"copied\": 15826,\n      \"drilling\": 15827,\n      \"shelley\": 15828,\n      \"petals\": 15829,\n      \"##inian\": 15830,\n      \"mandarin\": 15831,\n      \"obsolete\": 15832,\n      \"##inated\": 15833,\n      \"onward\": 15834,\n      \"arguably\": 15835,\n      \"productivity\": 15836,\n      \"cindy\": 15837,\n      \"praising\": 15838,\n      \"seldom\": 15839,\n      \"busch\": 15840,\n      \"discusses\": 15841,\n      \"raleigh\": 15842,\n      \"shortage\": 15843,\n      \"ranged\": 15844,\n      \"stanton\": 15845,\n      \"encouragement\": 15846,\n      \"firstly\": 15847,\n      \"conceded\": 15848,\n      \"overs\": 15849,\n      \"temporal\": 15850,\n      \"##uke\": 15851,\n      \"cbe\": 15852,\n      \"##bos\": 15853,\n      \"woo\": 15854,\n      \"certainty\": 15855,\n      \"pumps\": 15856,\n      \"##pton\": 15857,\n      \"stalked\": 15858,\n      \"##uli\": 15859,\n      \"lizzie\": 15860,\n      \"periodic\": 15861,\n      \"thieves\": 15862,\n      \"weaker\": 15863,\n      \"##night\": 15864,\n      \"gases\": 15865,\n      \"shoving\": 15866,\n      \"chooses\": 15867,\n      \"wc\": 15868,\n      \"##chemical\": 15869,\n      \"prompting\": 15870,\n      \"weights\": 15871,\n      \"##kill\": 15872,\n      \"robust\": 15873,\n      \"flanked\": 15874,\n      \"sticky\": 15875,\n      \"hu\": 15876,\n      \"tuberculosis\": 15877,\n      \"##eb\": 15878,\n      \"##eal\": 15879,\n      \"christchurch\": 15880,\n      \"resembled\": 15881,\n      \"wallet\": 15882,\n      \"reese\": 15883,\n      \"inappropriate\": 15884,\n      \"pictured\": 15885,\n      \"distract\": 15886,\n      \"fixing\": 15887,\n      \"fiddle\": 15888,\n      \"giggled\": 15889,\n      \"burger\": 15890,\n      \"heirs\": 15891,\n      \"hairy\": 15892,\n      \"mechanic\": 15893,\n      \"torque\": 15894,\n      \"apache\": 15895,\n      \"obsessed\": 15896,\n      \"chiefly\": 15897,\n      \"cheng\": 15898,\n      \"logging\": 15899,\n      \"##tag\": 15900,\n      \"extracted\": 15901,\n      \"meaningful\": 15902,\n      \"numb\": 15903,\n      \"##vsky\": 15904,\n      \"gloucestershire\": 15905,\n      \"reminding\": 15906,\n      \"##bay\": 15907,\n      \"unite\": 15908,\n      \"##lit\": 15909,\n      \"breeds\": 15910,\n      \"diminished\": 15911,\n      \"clown\": 15912,\n      \"glove\": 15913,\n      \"1860s\": 15914,\n      \"##ن\": 15915,\n      \"##ug\": 15916,\n      \"archibald\": 15917,\n      \"focal\": 15918,\n      \"freelance\": 15919,\n      \"sliced\": 15920,\n      \"depiction\": 15921,\n      \"##yk\": 15922,\n      \"organism\": 15923,\n      \"switches\": 15924,\n      \"sights\": 15925,\n      \"stray\": 15926,\n      \"crawling\": 15927,\n      \"##ril\": 15928,\n      \"lever\": 15929,\n      \"leningrad\": 15930,\n      \"interpretations\": 15931,\n      \"loops\": 15932,\n      \"anytime\": 15933,\n      \"reel\": 15934,\n      \"alicia\": 15935,\n      \"delighted\": 15936,\n      \"##ech\": 15937,\n      \"inhaled\": 15938,\n      \"xiv\": 15939,\n      \"suitcase\": 15940,\n      \"bernie\": 15941,\n      \"vega\": 15942,\n      \"licenses\": 15943,\n      \"northampton\": 15944,\n      \"exclusion\": 15945,\n      \"induction\": 15946,\n      \"monasteries\": 15947,\n      \"racecourse\": 15948,\n      \"homosexuality\": 15949,\n      \"##right\": 15950,\n      \"##sfield\": 15951,\n      \"##rky\": 15952,\n      \"dimitri\": 15953,\n      \"michele\": 15954,\n      \"alternatives\": 15955,\n      \"ions\": 15956,\n      \"commentators\": 15957,\n      \"genuinely\": 15958,\n      \"objected\": 15959,\n      \"pork\": 15960,\n      \"hospitality\": 15961,\n      \"fencing\": 15962,\n      \"stephan\": 15963,\n      \"warships\": 15964,\n      \"peripheral\": 15965,\n      \"wit\": 15966,\n      \"drunken\": 15967,\n      \"wrinkled\": 15968,\n      \"quentin\": 15969,\n      \"spends\": 15970,\n      \"departing\": 15971,\n      \"chung\": 15972,\n      \"numerical\": 15973,\n      \"spokesperson\": 15974,\n      \"##zone\": 15975,\n      \"johannesburg\": 15976,\n      \"caliber\": 15977,\n      \"killers\": 15978,\n      \"##udge\": 15979,\n      \"assumes\": 15980,\n      \"neatly\": 15981,\n      \"demographic\": 15982,\n      \"abigail\": 15983,\n      \"bloc\": 15984,\n      \"##vel\": 15985,\n      \"mounting\": 15986,\n      \"##lain\": 15987,\n      \"bentley\": 15988,\n      \"slightest\": 15989,\n      \"xu\": 15990,\n      \"recipients\": 15991,\n      \"##jk\": 15992,\n      \"merlin\": 15993,\n      \"##writer\": 15994,\n      \"seniors\": 15995,\n      \"prisons\": 15996,\n      \"blinking\": 15997,\n      \"hindwings\": 15998,\n      \"flickered\": 15999,\n      \"kappa\": 16000,\n      \"##hel\": 16001,\n      \"80s\": 16002,\n      \"strengthening\": 16003,\n      \"appealing\": 16004,\n      \"brewing\": 16005,\n      \"gypsy\": 16006,\n      \"mali\": 16007,\n      \"lashes\": 16008,\n      \"hulk\": 16009,\n      \"unpleasant\": 16010,\n      \"harassment\": 16011,\n      \"bio\": 16012,\n      \"treaties\": 16013,\n      \"predict\": 16014,\n      \"instrumentation\": 16015,\n      \"pulp\": 16016,\n      \"troupe\": 16017,\n      \"boiling\": 16018,\n      \"mantle\": 16019,\n      \"##ffe\": 16020,\n      \"ins\": 16021,\n      \"##vn\": 16022,\n      \"dividing\": 16023,\n      \"handles\": 16024,\n      \"verbs\": 16025,\n      \"##onal\": 16026,\n      \"coconut\": 16027,\n      \"senegal\": 16028,\n      \"340\": 16029,\n      \"thorough\": 16030,\n      \"gum\": 16031,\n      \"momentarily\": 16032,\n      \"##sto\": 16033,\n      \"cocaine\": 16034,\n      \"panicked\": 16035,\n      \"destined\": 16036,\n      \"##turing\": 16037,\n      \"teatro\": 16038,\n      \"denying\": 16039,\n      \"weary\": 16040,\n      \"captained\": 16041,\n      \"mans\": 16042,\n      \"##hawks\": 16043,\n      \"##code\": 16044,\n      \"wakefield\": 16045,\n      \"bollywood\": 16046,\n      \"thankfully\": 16047,\n      \"##16\": 16048,\n      \"cyril\": 16049,\n      \"##wu\": 16050,\n      \"amendments\": 16051,\n      \"##bahn\": 16052,\n      \"consultation\": 16053,\n      \"stud\": 16054,\n      \"reflections\": 16055,\n      \"kindness\": 16056,\n      \"1787\": 16057,\n      \"internally\": 16058,\n      \"##ovo\": 16059,\n      \"tex\": 16060,\n      \"mosaic\": 16061,\n      \"distribute\": 16062,\n      \"paddy\": 16063,\n      \"seeming\": 16064,\n      \"143\": 16065,\n      \"##hic\": 16066,\n      \"piers\": 16067,\n      \"##15\": 16068,\n      \"##mura\": 16069,\n      \"##verse\": 16070,\n      \"popularly\": 16071,\n      \"winger\": 16072,\n      \"kang\": 16073,\n      \"sentinel\": 16074,\n      \"mccoy\": 16075,\n      \"##anza\": 16076,\n      \"covenant\": 16077,\n      \"##bag\": 16078,\n      \"verge\": 16079,\n      \"fireworks\": 16080,\n      \"suppress\": 16081,\n      \"thrilled\": 16082,\n      \"dominate\": 16083,\n      \"##jar\": 16084,\n      \"swansea\": 16085,\n      \"##60\": 16086,\n      \"142\": 16087,\n      \"reconciliation\": 16088,\n      \"##ndi\": 16089,\n      \"stiffened\": 16090,\n      \"cue\": 16091,\n      \"dorian\": 16092,\n      \"##uf\": 16093,\n      \"damascus\": 16094,\n      \"amor\": 16095,\n      \"ida\": 16096,\n      \"foremost\": 16097,\n      \"##aga\": 16098,\n      \"porsche\": 16099,\n      \"unseen\": 16100,\n      \"dir\": 16101,\n      \"##had\": 16102,\n      \"##azi\": 16103,\n      \"stony\": 16104,\n      \"lexi\": 16105,\n      \"melodies\": 16106,\n      \"##nko\": 16107,\n      \"angular\": 16108,\n      \"integer\": 16109,\n      \"podcast\": 16110,\n      \"ants\": 16111,\n      \"inherent\": 16112,\n      \"jaws\": 16113,\n      \"justify\": 16114,\n      \"persona\": 16115,\n      \"##olved\": 16116,\n      \"josephine\": 16117,\n      \"##nr\": 16118,\n      \"##ressed\": 16119,\n      \"customary\": 16120,\n      \"flashes\": 16121,\n      \"gala\": 16122,\n      \"cyrus\": 16123,\n      \"glaring\": 16124,\n      \"backyard\": 16125,\n      \"ariel\": 16126,\n      \"physiology\": 16127,\n      \"greenland\": 16128,\n      \"html\": 16129,\n      \"stir\": 16130,\n      \"avon\": 16131,\n      \"atletico\": 16132,\n      \"finch\": 16133,\n      \"methodology\": 16134,\n      \"ked\": 16135,\n      \"##lent\": 16136,\n      \"mas\": 16137,\n      \"catholicism\": 16138,\n      \"townsend\": 16139,\n      \"branding\": 16140,\n      \"quincy\": 16141,\n      \"fits\": 16142,\n      \"containers\": 16143,\n      \"1777\": 16144,\n      \"ashore\": 16145,\n      \"aragon\": 16146,\n      \"##19\": 16147,\n      \"forearm\": 16148,\n      \"poisoning\": 16149,\n      \"##sd\": 16150,\n      \"adopting\": 16151,\n      \"conquer\": 16152,\n      \"grinding\": 16153,\n      \"amnesty\": 16154,\n      \"keller\": 16155,\n      \"finances\": 16156,\n      \"evaluate\": 16157,\n      \"forged\": 16158,\n      \"lankan\": 16159,\n      \"instincts\": 16160,\n      \"##uto\": 16161,\n      \"guam\": 16162,\n      \"bosnian\": 16163,\n      \"photographed\": 16164,\n      \"workplace\": 16165,\n      \"desirable\": 16166,\n      \"protector\": 16167,\n      \"##dog\": 16168,\n      \"allocation\": 16169,\n      \"intently\": 16170,\n      \"encourages\": 16171,\n      \"willy\": 16172,\n      \"##sten\": 16173,\n      \"bodyguard\": 16174,\n      \"electro\": 16175,\n      \"brighter\": 16176,\n      \"##ν\": 16177,\n      \"bihar\": 16178,\n      \"##chev\": 16179,\n      \"lasts\": 16180,\n      \"opener\": 16181,\n      \"amphibious\": 16182,\n      \"sal\": 16183,\n      \"verde\": 16184,\n      \"arte\": 16185,\n      \"##cope\": 16186,\n      \"captivity\": 16187,\n      \"vocabulary\": 16188,\n      \"yields\": 16189,\n      \"##tted\": 16190,\n      \"agreeing\": 16191,\n      \"desmond\": 16192,\n      \"pioneered\": 16193,\n      \"##chus\": 16194,\n      \"strap\": 16195,\n      \"campaigned\": 16196,\n      \"railroads\": 16197,\n      \"##ович\": 16198,\n      \"emblem\": 16199,\n      \"##dre\": 16200,\n      \"stormed\": 16201,\n      \"501\": 16202,\n      \"##ulous\": 16203,\n      \"marijuana\": 16204,\n      \"northumberland\": 16205,\n      \"##gn\": 16206,\n      \"##nath\": 16207,\n      \"bowen\": 16208,\n      \"landmarks\": 16209,\n      \"beaumont\": 16210,\n      \"##qua\": 16211,\n      \"danube\": 16212,\n      \"##bler\": 16213,\n      \"attorneys\": 16214,\n      \"th\": 16215,\n      \"ge\": 16216,\n      \"flyers\": 16217,\n      \"critique\": 16218,\n      \"villains\": 16219,\n      \"cass\": 16220,\n      \"mutation\": 16221,\n      \"acc\": 16222,\n      \"##0s\": 16223,\n      \"colombo\": 16224,\n      \"mckay\": 16225,\n      \"motif\": 16226,\n      \"sampling\": 16227,\n      \"concluding\": 16228,\n      \"syndicate\": 16229,\n      \"##rell\": 16230,\n      \"neon\": 16231,\n      \"stables\": 16232,\n      \"ds\": 16233,\n      \"warnings\": 16234,\n      \"clint\": 16235,\n      \"mourning\": 16236,\n      \"wilkinson\": 16237,\n      \"##tated\": 16238,\n      \"merrill\": 16239,\n      \"leopard\": 16240,\n      \"evenings\": 16241,\n      \"exhaled\": 16242,\n      \"emil\": 16243,\n      \"sonia\": 16244,\n      \"ezra\": 16245,\n      \"discrete\": 16246,\n      \"stove\": 16247,\n      \"farrell\": 16248,\n      \"fifteenth\": 16249,\n      \"prescribed\": 16250,\n      \"superhero\": 16251,\n      \"##rier\": 16252,\n      \"worms\": 16253,\n      \"helm\": 16254,\n      \"wren\": 16255,\n      \"##duction\": 16256,\n      \"##hc\": 16257,\n      \"expo\": 16258,\n      \"##rator\": 16259,\n      \"hq\": 16260,\n      \"unfamiliar\": 16261,\n      \"antony\": 16262,\n      \"prevents\": 16263,\n      \"acceleration\": 16264,\n      \"fiercely\": 16265,\n      \"mari\": 16266,\n      \"painfully\": 16267,\n      \"calculations\": 16268,\n      \"cheaper\": 16269,\n      \"ign\": 16270,\n      \"clifton\": 16271,\n      \"irvine\": 16272,\n      \"davenport\": 16273,\n      \"mozambique\": 16274,\n      \"##np\": 16275,\n      \"pierced\": 16276,\n      \"##evich\": 16277,\n      \"wonders\": 16278,\n      \"##wig\": 16279,\n      \"##cate\": 16280,\n      \"##iling\": 16281,\n      \"crusade\": 16282,\n      \"ware\": 16283,\n      \"##uel\": 16284,\n      \"enzymes\": 16285,\n      \"reasonably\": 16286,\n      \"mls\": 16287,\n      \"##coe\": 16288,\n      \"mater\": 16289,\n      \"ambition\": 16290,\n      \"bunny\": 16291,\n      \"eliot\": 16292,\n      \"kernel\": 16293,\n      \"##fin\": 16294,\n      \"asphalt\": 16295,\n      \"headmaster\": 16296,\n      \"torah\": 16297,\n      \"aden\": 16298,\n      \"lush\": 16299,\n      \"pins\": 16300,\n      \"waived\": 16301,\n      \"##care\": 16302,\n      \"##yas\": 16303,\n      \"joao\": 16304,\n      \"substrate\": 16305,\n      \"enforce\": 16306,\n      \"##grad\": 16307,\n      \"##ules\": 16308,\n      \"alvarez\": 16309,\n      \"selections\": 16310,\n      \"epidemic\": 16311,\n      \"tempted\": 16312,\n      \"##bit\": 16313,\n      \"bremen\": 16314,\n      \"translates\": 16315,\n      \"ensured\": 16316,\n      \"waterfront\": 16317,\n      \"29th\": 16318,\n      \"forrest\": 16319,\n      \"manny\": 16320,\n      \"malone\": 16321,\n      \"kramer\": 16322,\n      \"reigning\": 16323,\n      \"cookies\": 16324,\n      \"simpler\": 16325,\n      \"absorption\": 16326,\n      \"205\": 16327,\n      \"engraved\": 16328,\n      \"##ffy\": 16329,\n      \"evaluated\": 16330,\n      \"1778\": 16331,\n      \"haze\": 16332,\n      \"146\": 16333,\n      \"comforting\": 16334,\n      \"crossover\": 16335,\n      \"##abe\": 16336,\n      \"thorn\": 16337,\n      \"##rift\": 16338,\n      \"##imo\": 16339,\n      \"##pop\": 16340,\n      \"suppression\": 16341,\n      \"fatigue\": 16342,\n      \"cutter\": 16343,\n      \"##tr\": 16344,\n      \"201\": 16345,\n      \"wurttemberg\": 16346,\n      \"##orf\": 16347,\n      \"enforced\": 16348,\n      \"hovering\": 16349,\n      \"proprietary\": 16350,\n      \"gb\": 16351,\n      \"samurai\": 16352,\n      \"syllable\": 16353,\n      \"ascent\": 16354,\n      \"lacey\": 16355,\n      \"tick\": 16356,\n      \"lars\": 16357,\n      \"tractor\": 16358,\n      \"merchandise\": 16359,\n      \"rep\": 16360,\n      \"bouncing\": 16361,\n      \"defendants\": 16362,\n      \"##yre\": 16363,\n      \"huntington\": 16364,\n      \"##ground\": 16365,\n      \"##oko\": 16366,\n      \"standardized\": 16367,\n      \"##hor\": 16368,\n      \"##hima\": 16369,\n      \"assassinated\": 16370,\n      \"nu\": 16371,\n      \"predecessors\": 16372,\n      \"rainy\": 16373,\n      \"liar\": 16374,\n      \"assurance\": 16375,\n      \"lyrical\": 16376,\n      \"##uga\": 16377,\n      \"secondly\": 16378,\n      \"flattened\": 16379,\n      \"ios\": 16380,\n      \"parameter\": 16381,\n      \"undercover\": 16382,\n      \"##mity\": 16383,\n      \"bordeaux\": 16384,\n      \"punish\": 16385,\n      \"ridges\": 16386,\n      \"markers\": 16387,\n      \"exodus\": 16388,\n      \"inactive\": 16389,\n      \"hesitate\": 16390,\n      \"debbie\": 16391,\n      \"nyc\": 16392,\n      \"pledge\": 16393,\n      \"savoy\": 16394,\n      \"nagar\": 16395,\n      \"offset\": 16396,\n      \"organist\": 16397,\n      \"##tium\": 16398,\n      \"hesse\": 16399,\n      \"marin\": 16400,\n      \"converting\": 16401,\n      \"##iver\": 16402,\n      \"diagram\": 16403,\n      \"propulsion\": 16404,\n      \"pu\": 16405,\n      \"validity\": 16406,\n      \"reverted\": 16407,\n      \"supportive\": 16408,\n      \"##dc\": 16409,\n      \"ministries\": 16410,\n      \"clans\": 16411,\n      \"responds\": 16412,\n      \"proclamation\": 16413,\n      \"##inae\": 16414,\n      \"##ø\": 16415,\n      \"##rea\": 16416,\n      \"ein\": 16417,\n      \"pleading\": 16418,\n      \"patriot\": 16419,\n      \"sf\": 16420,\n      \"birch\": 16421,\n      \"islanders\": 16422,\n      \"strauss\": 16423,\n      \"hates\": 16424,\n      \"##dh\": 16425,\n      \"brandenburg\": 16426,\n      \"concession\": 16427,\n      \"rd\": 16428,\n      \"##ob\": 16429,\n      \"1900s\": 16430,\n      \"killings\": 16431,\n      \"textbook\": 16432,\n      \"antiquity\": 16433,\n      \"cinematography\": 16434,\n      \"wharf\": 16435,\n      \"embarrassing\": 16436,\n      \"setup\": 16437,\n      \"creed\": 16438,\n      \"farmland\": 16439,\n      \"inequality\": 16440,\n      \"centred\": 16441,\n      \"signatures\": 16442,\n      \"fallon\": 16443,\n      \"370\": 16444,\n      \"##ingham\": 16445,\n      \"##uts\": 16446,\n      \"ceylon\": 16447,\n      \"gazing\": 16448,\n      \"directive\": 16449,\n      \"laurie\": 16450,\n      \"##tern\": 16451,\n      \"globally\": 16452,\n      \"##uated\": 16453,\n      \"##dent\": 16454,\n      \"allah\": 16455,\n      \"excavation\": 16456,\n      \"threads\": 16457,\n      \"##cross\": 16458,\n      \"148\": 16459,\n      \"frantically\": 16460,\n      \"icc\": 16461,\n      \"utilize\": 16462,\n      \"determines\": 16463,\n      \"respiratory\": 16464,\n      \"thoughtful\": 16465,\n      \"receptions\": 16466,\n      \"##dicate\": 16467,\n      \"merging\": 16468,\n      \"chandra\": 16469,\n      \"seine\": 16470,\n      \"147\": 16471,\n      \"builders\": 16472,\n      \"builds\": 16473,\n      \"diagnostic\": 16474,\n      \"dev\": 16475,\n      \"visibility\": 16476,\n      \"goddamn\": 16477,\n      \"analyses\": 16478,\n      \"dhaka\": 16479,\n      \"cho\": 16480,\n      \"proves\": 16481,\n      \"chancel\": 16482,\n      \"concurrent\": 16483,\n      \"curiously\": 16484,\n      \"canadians\": 16485,\n      \"pumped\": 16486,\n      \"restoring\": 16487,\n      \"1850s\": 16488,\n      \"turtles\": 16489,\n      \"jaguar\": 16490,\n      \"sinister\": 16491,\n      \"spinal\": 16492,\n      \"traction\": 16493,\n      \"declan\": 16494,\n      \"vows\": 16495,\n      \"1784\": 16496,\n      \"glowed\": 16497,\n      \"capitalism\": 16498,\n      \"swirling\": 16499,\n      \"install\": 16500,\n      \"universidad\": 16501,\n      \"##lder\": 16502,\n      \"##oat\": 16503,\n      \"soloist\": 16504,\n      \"##genic\": 16505,\n      \"##oor\": 16506,\n      \"coincidence\": 16507,\n      \"beginnings\": 16508,\n      \"nissan\": 16509,\n      \"dip\": 16510,\n      \"resorts\": 16511,\n      \"caucasus\": 16512,\n      \"combustion\": 16513,\n      \"infectious\": 16514,\n      \"##eno\": 16515,\n      \"pigeon\": 16516,\n      \"serpent\": 16517,\n      \"##itating\": 16518,\n      \"conclude\": 16519,\n      \"masked\": 16520,\n      \"salad\": 16521,\n      \"jew\": 16522,\n      \"##gr\": 16523,\n      \"surreal\": 16524,\n      \"toni\": 16525,\n      \"##wc\": 16526,\n      \"harmonica\": 16527,\n      \"151\": 16528,\n      \"##gins\": 16529,\n      \"##etic\": 16530,\n      \"##coat\": 16531,\n      \"fishermen\": 16532,\n      \"intending\": 16533,\n      \"bravery\": 16534,\n      \"##wave\": 16535,\n      \"klaus\": 16536,\n      \"titan\": 16537,\n      \"wembley\": 16538,\n      \"taiwanese\": 16539,\n      \"ransom\": 16540,\n      \"40th\": 16541,\n      \"incorrect\": 16542,\n      \"hussein\": 16543,\n      \"eyelids\": 16544,\n      \"jp\": 16545,\n      \"cooke\": 16546,\n      \"dramas\": 16547,\n      \"utilities\": 16548,\n      \"##etta\": 16549,\n      \"##print\": 16550,\n      \"eisenhower\": 16551,\n      \"principally\": 16552,\n      \"granada\": 16553,\n      \"lana\": 16554,\n      \"##rak\": 16555,\n      \"openings\": 16556,\n      \"concord\": 16557,\n      \"##bl\": 16558,\n      \"bethany\": 16559,\n      \"connie\": 16560,\n      \"morality\": 16561,\n      \"sega\": 16562,\n      \"##mons\": 16563,\n      \"##nard\": 16564,\n      \"earnings\": 16565,\n      \"##kara\": 16566,\n      \"##cine\": 16567,\n      \"wii\": 16568,\n      \"communes\": 16569,\n      \"##rel\": 16570,\n      \"coma\": 16571,\n      \"composing\": 16572,\n      \"softened\": 16573,\n      \"severed\": 16574,\n      \"grapes\": 16575,\n      \"##17\": 16576,\n      \"nguyen\": 16577,\n      \"analyzed\": 16578,\n      \"warlord\": 16579,\n      \"hubbard\": 16580,\n      \"heavenly\": 16581,\n      \"behave\": 16582,\n      \"slovenian\": 16583,\n      \"##hit\": 16584,\n      \"##ony\": 16585,\n      \"hailed\": 16586,\n      \"filmmakers\": 16587,\n      \"trance\": 16588,\n      \"caldwell\": 16589,\n      \"skye\": 16590,\n      \"unrest\": 16591,\n      \"coward\": 16592,\n      \"likelihood\": 16593,\n      \"##aging\": 16594,\n      \"bern\": 16595,\n      \"sci\": 16596,\n      \"taliban\": 16597,\n      \"honolulu\": 16598,\n      \"propose\": 16599,\n      \"##wang\": 16600,\n      \"1700\": 16601,\n      \"browser\": 16602,\n      \"imagining\": 16603,\n      \"cobra\": 16604,\n      \"contributes\": 16605,\n      \"dukes\": 16606,\n      \"instinctively\": 16607,\n      \"conan\": 16608,\n      \"violinist\": 16609,\n      \"##ores\": 16610,\n      \"accessories\": 16611,\n      \"gradual\": 16612,\n      \"##amp\": 16613,\n      \"quotes\": 16614,\n      \"sioux\": 16615,\n      \"##dating\": 16616,\n      \"undertake\": 16617,\n      \"intercepted\": 16618,\n      \"sparkling\": 16619,\n      \"compressed\": 16620,\n      \"139\": 16621,\n      \"fungus\": 16622,\n      \"tombs\": 16623,\n      \"haley\": 16624,\n      \"imposing\": 16625,\n      \"rests\": 16626,\n      \"degradation\": 16627,\n      \"lincolnshire\": 16628,\n      \"retailers\": 16629,\n      \"wetlands\": 16630,\n      \"tulsa\": 16631,\n      \"distributor\": 16632,\n      \"dungeon\": 16633,\n      \"nun\": 16634,\n      \"greenhouse\": 16635,\n      \"convey\": 16636,\n      \"atlantis\": 16637,\n      \"aft\": 16638,\n      \"exits\": 16639,\n      \"oman\": 16640,\n      \"dresser\": 16641,\n      \"lyons\": 16642,\n      \"##sti\": 16643,\n      \"joking\": 16644,\n      \"eddy\": 16645,\n      \"judgement\": 16646,\n      \"omitted\": 16647,\n      \"digits\": 16648,\n      \"##cts\": 16649,\n      \"##game\": 16650,\n      \"juniors\": 16651,\n      \"##rae\": 16652,\n      \"cents\": 16653,\n      \"stricken\": 16654,\n      \"une\": 16655,\n      \"##ngo\": 16656,\n      \"wizards\": 16657,\n      \"weir\": 16658,\n      \"breton\": 16659,\n      \"nan\": 16660,\n      \"technician\": 16661,\n      \"fibers\": 16662,\n      \"liking\": 16663,\n      \"royalty\": 16664,\n      \"##cca\": 16665,\n      \"154\": 16666,\n      \"persia\": 16667,\n      \"terribly\": 16668,\n      \"magician\": 16669,\n      \"##rable\": 16670,\n      \"##unt\": 16671,\n      \"vance\": 16672,\n      \"cafeteria\": 16673,\n      \"booker\": 16674,\n      \"camille\": 16675,\n      \"warmer\": 16676,\n      \"##static\": 16677,\n      \"consume\": 16678,\n      \"cavern\": 16679,\n      \"gaps\": 16680,\n      \"compass\": 16681,\n      \"contemporaries\": 16682,\n      \"foyer\": 16683,\n      \"soothing\": 16684,\n      \"graveyard\": 16685,\n      \"maj\": 16686,\n      \"plunged\": 16687,\n      \"blush\": 16688,\n      \"##wear\": 16689,\n      \"cascade\": 16690,\n      \"demonstrates\": 16691,\n      \"ordinance\": 16692,\n      \"##nov\": 16693,\n      \"boyle\": 16694,\n      \"##lana\": 16695,\n      \"rockefeller\": 16696,\n      \"shaken\": 16697,\n      \"banjo\": 16698,\n      \"izzy\": 16699,\n      \"##ense\": 16700,\n      \"breathless\": 16701,\n      \"vines\": 16702,\n      \"##32\": 16703,\n      \"##eman\": 16704,\n      \"alterations\": 16705,\n      \"chromosome\": 16706,\n      \"dwellings\": 16707,\n      \"feudal\": 16708,\n      \"mole\": 16709,\n      \"153\": 16710,\n      \"catalonia\": 16711,\n      \"relics\": 16712,\n      \"tenant\": 16713,\n      \"mandated\": 16714,\n      \"##fm\": 16715,\n      \"fridge\": 16716,\n      \"hats\": 16717,\n      \"honesty\": 16718,\n      \"patented\": 16719,\n      \"raul\": 16720,\n      \"heap\": 16721,\n      \"cruisers\": 16722,\n      \"accusing\": 16723,\n      \"enlightenment\": 16724,\n      \"infants\": 16725,\n      \"wherein\": 16726,\n      \"chatham\": 16727,\n      \"contractors\": 16728,\n      \"zen\": 16729,\n      \"affinity\": 16730,\n      \"hc\": 16731,\n      \"osborne\": 16732,\n      \"piston\": 16733,\n      \"156\": 16734,\n      \"traps\": 16735,\n      \"maturity\": 16736,\n      \"##rana\": 16737,\n      \"lagos\": 16738,\n      \"##zal\": 16739,\n      \"peering\": 16740,\n      \"##nay\": 16741,\n      \"attendant\": 16742,\n      \"dealers\": 16743,\n      \"protocols\": 16744,\n      \"subset\": 16745,\n      \"prospects\": 16746,\n      \"biographical\": 16747,\n      \"##cre\": 16748,\n      \"artery\": 16749,\n      \"##zers\": 16750,\n      \"insignia\": 16751,\n      \"nuns\": 16752,\n      \"endured\": 16753,\n      \"##eration\": 16754,\n      \"recommend\": 16755,\n      \"schwartz\": 16756,\n      \"serbs\": 16757,\n      \"berger\": 16758,\n      \"cromwell\": 16759,\n      \"crossroads\": 16760,\n      \"##ctor\": 16761,\n      \"enduring\": 16762,\n      \"clasped\": 16763,\n      \"grounded\": 16764,\n      \"##bine\": 16765,\n      \"marseille\": 16766,\n      \"twitched\": 16767,\n      \"abel\": 16768,\n      \"choke\": 16769,\n      \"https\": 16770,\n      \"catalyst\": 16771,\n      \"moldova\": 16772,\n      \"italians\": 16773,\n      \"##tist\": 16774,\n      \"disastrous\": 16775,\n      \"wee\": 16776,\n      \"##oured\": 16777,\n      \"##nti\": 16778,\n      \"wwf\": 16779,\n      \"nope\": 16780,\n      \"##piration\": 16781,\n      \"##asa\": 16782,\n      \"expresses\": 16783,\n      \"thumbs\": 16784,\n      \"167\": 16785,\n      \"##nza\": 16786,\n      \"coca\": 16787,\n      \"1781\": 16788,\n      \"cheating\": 16789,\n      \"##ption\": 16790,\n      \"skipped\": 16791,\n      \"sensory\": 16792,\n      \"heidelberg\": 16793,\n      \"spies\": 16794,\n      \"satan\": 16795,\n      \"dangers\": 16796,\n      \"semifinal\": 16797,\n      \"202\": 16798,\n      \"bohemia\": 16799,\n      \"whitish\": 16800,\n      \"confusing\": 16801,\n      \"shipbuilding\": 16802,\n      \"relies\": 16803,\n      \"surgeons\": 16804,\n      \"landings\": 16805,\n      \"ravi\": 16806,\n      \"baku\": 16807,\n      \"moor\": 16808,\n      \"suffix\": 16809,\n      \"alejandro\": 16810,\n      \"##yana\": 16811,\n      \"litre\": 16812,\n      \"upheld\": 16813,\n      \"##unk\": 16814,\n      \"rajasthan\": 16815,\n      \"##rek\": 16816,\n      \"coaster\": 16817,\n      \"insists\": 16818,\n      \"posture\": 16819,\n      \"scenarios\": 16820,\n      \"etienne\": 16821,\n      \"favoured\": 16822,\n      \"appoint\": 16823,\n      \"transgender\": 16824,\n      \"elephants\": 16825,\n      \"poked\": 16826,\n      \"greenwood\": 16827,\n      \"defences\": 16828,\n      \"fulfilled\": 16829,\n      \"militant\": 16830,\n      \"somali\": 16831,\n      \"1758\": 16832,\n      \"chalk\": 16833,\n      \"potent\": 16834,\n      \"##ucci\": 16835,\n      \"migrants\": 16836,\n      \"wink\": 16837,\n      \"assistants\": 16838,\n      \"nos\": 16839,\n      \"restriction\": 16840,\n      \"activism\": 16841,\n      \"niger\": 16842,\n      \"##ario\": 16843,\n      \"colon\": 16844,\n      \"shaun\": 16845,\n      \"##sat\": 16846,\n      \"daphne\": 16847,\n      \"##erated\": 16848,\n      \"swam\": 16849,\n      \"congregations\": 16850,\n      \"reprise\": 16851,\n      \"considerations\": 16852,\n      \"magnet\": 16853,\n      \"playable\": 16854,\n      \"xvi\": 16855,\n      \"##р\": 16856,\n      \"overthrow\": 16857,\n      \"tobias\": 16858,\n      \"knob\": 16859,\n      \"chavez\": 16860,\n      \"coding\": 16861,\n      \"##mers\": 16862,\n      \"propped\": 16863,\n      \"katrina\": 16864,\n      \"orient\": 16865,\n      \"newcomer\": 16866,\n      \"##suke\": 16867,\n      \"temperate\": 16868,\n      \"##pool\": 16869,\n      \"farmhouse\": 16870,\n      \"interrogation\": 16871,\n      \"##vd\": 16872,\n      \"committing\": 16873,\n      \"##vert\": 16874,\n      \"forthcoming\": 16875,\n      \"strawberry\": 16876,\n      \"joaquin\": 16877,\n      \"macau\": 16878,\n      \"ponds\": 16879,\n      \"shocking\": 16880,\n      \"siberia\": 16881,\n      \"##cellular\": 16882,\n      \"chant\": 16883,\n      \"contributors\": 16884,\n      \"##nant\": 16885,\n      \"##ologists\": 16886,\n      \"sped\": 16887,\n      \"absorb\": 16888,\n      \"hail\": 16889,\n      \"1782\": 16890,\n      \"spared\": 16891,\n      \"##hore\": 16892,\n      \"barbados\": 16893,\n      \"karate\": 16894,\n      \"opus\": 16895,\n      \"originates\": 16896,\n      \"saul\": 16897,\n      \"##xie\": 16898,\n      \"evergreen\": 16899,\n      \"leaped\": 16900,\n      \"##rock\": 16901,\n      \"correlation\": 16902,\n      \"exaggerated\": 16903,\n      \"weekday\": 16904,\n      \"unification\": 16905,\n      \"bump\": 16906,\n      \"tracing\": 16907,\n      \"brig\": 16908,\n      \"afb\": 16909,\n      \"pathways\": 16910,\n      \"utilizing\": 16911,\n      \"##ners\": 16912,\n      \"mod\": 16913,\n      \"mb\": 16914,\n      \"disturbance\": 16915,\n      \"kneeling\": 16916,\n      \"##stad\": 16917,\n      \"##guchi\": 16918,\n      \"100th\": 16919,\n      \"pune\": 16920,\n      \"##thy\": 16921,\n      \"decreasing\": 16922,\n      \"168\": 16923,\n      \"manipulation\": 16924,\n      \"miriam\": 16925,\n      \"academia\": 16926,\n      \"ecosystem\": 16927,\n      \"occupational\": 16928,\n      \"rbi\": 16929,\n      \"##lem\": 16930,\n      \"rift\": 16931,\n      \"##14\": 16932,\n      \"rotary\": 16933,\n      \"stacked\": 16934,\n      \"incorporation\": 16935,\n      \"awakening\": 16936,\n      \"generators\": 16937,\n      \"guerrero\": 16938,\n      \"racist\": 16939,\n      \"##omy\": 16940,\n      \"cyber\": 16941,\n      \"derivatives\": 16942,\n      \"culminated\": 16943,\n      \"allie\": 16944,\n      \"annals\": 16945,\n      \"panzer\": 16946,\n      \"sainte\": 16947,\n      \"wikipedia\": 16948,\n      \"pops\": 16949,\n      \"zu\": 16950,\n      \"austro\": 16951,\n      \"##vate\": 16952,\n      \"algerian\": 16953,\n      \"politely\": 16954,\n      \"nicholson\": 16955,\n      \"mornings\": 16956,\n      \"educate\": 16957,\n      \"tastes\": 16958,\n      \"thrill\": 16959,\n      \"dartmouth\": 16960,\n      \"##gating\": 16961,\n      \"db\": 16962,\n      \"##jee\": 16963,\n      \"regan\": 16964,\n      \"differing\": 16965,\n      \"concentrating\": 16966,\n      \"choreography\": 16967,\n      \"divinity\": 16968,\n      \"##media\": 16969,\n      \"pledged\": 16970,\n      \"alexandre\": 16971,\n      \"routing\": 16972,\n      \"gregor\": 16973,\n      \"madeline\": 16974,\n      \"##idal\": 16975,\n      \"apocalypse\": 16976,\n      \"##hora\": 16977,\n      \"gunfire\": 16978,\n      \"culminating\": 16979,\n      \"elves\": 16980,\n      \"fined\": 16981,\n      \"liang\": 16982,\n      \"lam\": 16983,\n      \"programmed\": 16984,\n      \"tar\": 16985,\n      \"guessing\": 16986,\n      \"transparency\": 16987,\n      \"gabrielle\": 16988,\n      \"##gna\": 16989,\n      \"cancellation\": 16990,\n      \"flexibility\": 16991,\n      \"##lining\": 16992,\n      \"accession\": 16993,\n      \"shea\": 16994,\n      \"stronghold\": 16995,\n      \"nets\": 16996,\n      \"specializes\": 16997,\n      \"##rgan\": 16998,\n      \"abused\": 16999,\n      \"hasan\": 17000,\n      \"sgt\": 17001,\n      \"ling\": 17002,\n      \"exceeding\": 17003,\n      \"##₄\": 17004,\n      \"admiration\": 17005,\n      \"supermarket\": 17006,\n      \"##ark\": 17007,\n      \"photographers\": 17008,\n      \"specialised\": 17009,\n      \"tilt\": 17010,\n      \"resonance\": 17011,\n      \"hmm\": 17012,\n      \"perfume\": 17013,\n      \"380\": 17014,\n      \"sami\": 17015,\n      \"threatens\": 17016,\n      \"garland\": 17017,\n      \"botany\": 17018,\n      \"guarding\": 17019,\n      \"boiled\": 17020,\n      \"greet\": 17021,\n      \"puppy\": 17022,\n      \"russo\": 17023,\n      \"supplier\": 17024,\n      \"wilmington\": 17025,\n      \"vibrant\": 17026,\n      \"vijay\": 17027,\n      \"##bius\": 17028,\n      \"paralympic\": 17029,\n      \"grumbled\": 17030,\n      \"paige\": 17031,\n      \"faa\": 17032,\n      \"licking\": 17033,\n      \"margins\": 17034,\n      \"hurricanes\": 17035,\n      \"##gong\": 17036,\n      \"fest\": 17037,\n      \"grenade\": 17038,\n      \"ripping\": 17039,\n      \"##uz\": 17040,\n      \"counseling\": 17041,\n      \"weigh\": 17042,\n      \"##sian\": 17043,\n      \"needles\": 17044,\n      \"wiltshire\": 17045,\n      \"edison\": 17046,\n      \"costly\": 17047,\n      \"##not\": 17048,\n      \"fulton\": 17049,\n      \"tramway\": 17050,\n      \"redesigned\": 17051,\n      \"staffordshire\": 17052,\n      \"cache\": 17053,\n      \"gasping\": 17054,\n      \"watkins\": 17055,\n      \"sleepy\": 17056,\n      \"candidacy\": 17057,\n      \"##group\": 17058,\n      \"monkeys\": 17059,\n      \"timeline\": 17060,\n      \"throbbing\": 17061,\n      \"##bid\": 17062,\n      \"##sos\": 17063,\n      \"berth\": 17064,\n      \"uzbekistan\": 17065,\n      \"vanderbilt\": 17066,\n      \"bothering\": 17067,\n      \"overturned\": 17068,\n      \"ballots\": 17069,\n      \"gem\": 17070,\n      \"##iger\": 17071,\n      \"sunglasses\": 17072,\n      \"subscribers\": 17073,\n      \"hooker\": 17074,\n      \"compelling\": 17075,\n      \"ang\": 17076,\n      \"exceptionally\": 17077,\n      \"saloon\": 17078,\n      \"stab\": 17079,\n      \"##rdi\": 17080,\n      \"carla\": 17081,\n      \"terrifying\": 17082,\n      \"rom\": 17083,\n      \"##vision\": 17084,\n      \"coil\": 17085,\n      \"##oids\": 17086,\n      \"satisfying\": 17087,\n      \"vendors\": 17088,\n      \"31st\": 17089,\n      \"mackay\": 17090,\n      \"deities\": 17091,\n      \"overlooked\": 17092,\n      \"ambient\": 17093,\n      \"bahamas\": 17094,\n      \"felipe\": 17095,\n      \"olympia\": 17096,\n      \"whirled\": 17097,\n      \"botanist\": 17098,\n      \"advertised\": 17099,\n      \"tugging\": 17100,\n      \"##dden\": 17101,\n      \"disciples\": 17102,\n      \"morales\": 17103,\n      \"unionist\": 17104,\n      \"rites\": 17105,\n      \"foley\": 17106,\n      \"morse\": 17107,\n      \"motives\": 17108,\n      \"creepy\": 17109,\n      \"##₀\": 17110,\n      \"soo\": 17111,\n      \"##sz\": 17112,\n      \"bargain\": 17113,\n      \"highness\": 17114,\n      \"frightening\": 17115,\n      \"turnpike\": 17116,\n      \"tory\": 17117,\n      \"reorganization\": 17118,\n      \"##cer\": 17119,\n      \"depict\": 17120,\n      \"biographer\": 17121,\n      \"##walk\": 17122,\n      \"unopposed\": 17123,\n      \"manifesto\": 17124,\n      \"##gles\": 17125,\n      \"institut\": 17126,\n      \"emile\": 17127,\n      \"accidental\": 17128,\n      \"kapoor\": 17129,\n      \"##dam\": 17130,\n      \"kilkenny\": 17131,\n      \"cortex\": 17132,\n      \"lively\": 17133,\n      \"##13\": 17134,\n      \"romanesque\": 17135,\n      \"jain\": 17136,\n      \"shan\": 17137,\n      \"cannons\": 17138,\n      \"##ood\": 17139,\n      \"##ske\": 17140,\n      \"petrol\": 17141,\n      \"echoing\": 17142,\n      \"amalgamated\": 17143,\n      \"disappears\": 17144,\n      \"cautious\": 17145,\n      \"proposes\": 17146,\n      \"sanctions\": 17147,\n      \"trenton\": 17148,\n      \"##ر\": 17149,\n      \"flotilla\": 17150,\n      \"aus\": 17151,\n      \"contempt\": 17152,\n      \"tor\": 17153,\n      \"canary\": 17154,\n      \"cote\": 17155,\n      \"theirs\": 17156,\n      \"##hun\": 17157,\n      \"conceptual\": 17158,\n      \"deleted\": 17159,\n      \"fascinating\": 17160,\n      \"paso\": 17161,\n      \"blazing\": 17162,\n      \"elf\": 17163,\n      \"honourable\": 17164,\n      \"hutchinson\": 17165,\n      \"##eiro\": 17166,\n      \"##outh\": 17167,\n      \"##zin\": 17168,\n      \"surveyor\": 17169,\n      \"tee\": 17170,\n      \"amidst\": 17171,\n      \"wooded\": 17172,\n      \"reissue\": 17173,\n      \"intro\": 17174,\n      \"##ono\": 17175,\n      \"cobb\": 17176,\n      \"shelters\": 17177,\n      \"newsletter\": 17178,\n      \"hanson\": 17179,\n      \"brace\": 17180,\n      \"encoding\": 17181,\n      \"confiscated\": 17182,\n      \"dem\": 17183,\n      \"caravan\": 17184,\n      \"marino\": 17185,\n      \"scroll\": 17186,\n      \"melodic\": 17187,\n      \"cows\": 17188,\n      \"imam\": 17189,\n      \"##adi\": 17190,\n      \"##aneous\": 17191,\n      \"northward\": 17192,\n      \"searches\": 17193,\n      \"biodiversity\": 17194,\n      \"cora\": 17195,\n      \"310\": 17196,\n      \"roaring\": 17197,\n      \"##bers\": 17198,\n      \"connell\": 17199,\n      \"theologian\": 17200,\n      \"halo\": 17201,\n      \"compose\": 17202,\n      \"pathetic\": 17203,\n      \"unmarried\": 17204,\n      \"dynamo\": 17205,\n      \"##oot\": 17206,\n      \"az\": 17207,\n      \"calculation\": 17208,\n      \"toulouse\": 17209,\n      \"deserves\": 17210,\n      \"humour\": 17211,\n      \"nr\": 17212,\n      \"forgiveness\": 17213,\n      \"tam\": 17214,\n      \"undergone\": 17215,\n      \"martyr\": 17216,\n      \"pamela\": 17217,\n      \"myths\": 17218,\n      \"whore\": 17219,\n      \"counselor\": 17220,\n      \"hicks\": 17221,\n      \"290\": 17222,\n      \"heavens\": 17223,\n      \"battleship\": 17224,\n      \"electromagnetic\": 17225,\n      \"##bbs\": 17226,\n      \"stellar\": 17227,\n      \"establishments\": 17228,\n      \"presley\": 17229,\n      \"hopped\": 17230,\n      \"##chin\": 17231,\n      \"temptation\": 17232,\n      \"90s\": 17233,\n      \"wills\": 17234,\n      \"nas\": 17235,\n      \"##yuan\": 17236,\n      \"nhs\": 17237,\n      \"##nya\": 17238,\n      \"seminars\": 17239,\n      \"##yev\": 17240,\n      \"adaptations\": 17241,\n      \"gong\": 17242,\n      \"asher\": 17243,\n      \"lex\": 17244,\n      \"indicator\": 17245,\n      \"sikh\": 17246,\n      \"tobago\": 17247,\n      \"cites\": 17248,\n      \"goin\": 17249,\n      \"##yte\": 17250,\n      \"satirical\": 17251,\n      \"##gies\": 17252,\n      \"characterised\": 17253,\n      \"correspond\": 17254,\n      \"bubbles\": 17255,\n      \"lure\": 17256,\n      \"participates\": 17257,\n      \"##vid\": 17258,\n      \"eruption\": 17259,\n      \"skate\": 17260,\n      \"therapeutic\": 17261,\n      \"1785\": 17262,\n      \"canals\": 17263,\n      \"wholesale\": 17264,\n      \"defaulted\": 17265,\n      \"sac\": 17266,\n      \"460\": 17267,\n      \"petit\": 17268,\n      \"##zzled\": 17269,\n      \"virgil\": 17270,\n      \"leak\": 17271,\n      \"ravens\": 17272,\n      \"256\": 17273,\n      \"portraying\": 17274,\n      \"##yx\": 17275,\n      \"ghetto\": 17276,\n      \"creators\": 17277,\n      \"dams\": 17278,\n      \"portray\": 17279,\n      \"vicente\": 17280,\n      \"##rington\": 17281,\n      \"fae\": 17282,\n      \"namesake\": 17283,\n      \"bounty\": 17284,\n      \"##arium\": 17285,\n      \"joachim\": 17286,\n      \"##ota\": 17287,\n      \"##iser\": 17288,\n      \"aforementioned\": 17289,\n      \"axle\": 17290,\n      \"snout\": 17291,\n      \"depended\": 17292,\n      \"dismantled\": 17293,\n      \"reuben\": 17294,\n      \"480\": 17295,\n      \"##ibly\": 17296,\n      \"gallagher\": 17297,\n      \"##lau\": 17298,\n      \"##pd\": 17299,\n      \"earnest\": 17300,\n      \"##ieu\": 17301,\n      \"##iary\": 17302,\n      \"inflicted\": 17303,\n      \"objections\": 17304,\n      \"##llar\": 17305,\n      \"asa\": 17306,\n      \"gritted\": 17307,\n      \"##athy\": 17308,\n      \"jericho\": 17309,\n      \"##sea\": 17310,\n      \"##was\": 17311,\n      \"flick\": 17312,\n      \"underside\": 17313,\n      \"ceramics\": 17314,\n      \"undead\": 17315,\n      \"substituted\": 17316,\n      \"195\": 17317,\n      \"eastward\": 17318,\n      \"undoubtedly\": 17319,\n      \"wheeled\": 17320,\n      \"chimney\": 17321,\n      \"##iche\": 17322,\n      \"guinness\": 17323,\n      \"cb\": 17324,\n      \"##ager\": 17325,\n      \"siding\": 17326,\n      \"##bell\": 17327,\n      \"traitor\": 17328,\n      \"baptiste\": 17329,\n      \"disguised\": 17330,\n      \"inauguration\": 17331,\n      \"149\": 17332,\n      \"tipperary\": 17333,\n      \"choreographer\": 17334,\n      \"perched\": 17335,\n      \"warmed\": 17336,\n      \"stationary\": 17337,\n      \"eco\": 17338,\n      \"##ike\": 17339,\n      \"##ntes\": 17340,\n      \"bacterial\": 17341,\n      \"##aurus\": 17342,\n      \"flores\": 17343,\n      \"phosphate\": 17344,\n      \"##core\": 17345,\n      \"attacker\": 17346,\n      \"invaders\": 17347,\n      \"alvin\": 17348,\n      \"intersects\": 17349,\n      \"a1\": 17350,\n      \"indirectly\": 17351,\n      \"immigrated\": 17352,\n      \"businessmen\": 17353,\n      \"cornelius\": 17354,\n      \"valves\": 17355,\n      \"narrated\": 17356,\n      \"pill\": 17357,\n      \"sober\": 17358,\n      \"ul\": 17359,\n      \"nationale\": 17360,\n      \"monastic\": 17361,\n      \"applicants\": 17362,\n      \"scenery\": 17363,\n      \"##jack\": 17364,\n      \"161\": 17365,\n      \"motifs\": 17366,\n      \"constitutes\": 17367,\n      \"cpu\": 17368,\n      \"##osh\": 17369,\n      \"jurisdictions\": 17370,\n      \"sd\": 17371,\n      \"tuning\": 17372,\n      \"irritation\": 17373,\n      \"woven\": 17374,\n      \"##uddin\": 17375,\n      \"fertility\": 17376,\n      \"gao\": 17377,\n      \"##erie\": 17378,\n      \"antagonist\": 17379,\n      \"impatient\": 17380,\n      \"glacial\": 17381,\n      \"hides\": 17382,\n      \"boarded\": 17383,\n      \"denominations\": 17384,\n      \"interception\": 17385,\n      \"##jas\": 17386,\n      \"cookie\": 17387,\n      \"nicola\": 17388,\n      \"##tee\": 17389,\n      \"algebraic\": 17390,\n      \"marquess\": 17391,\n      \"bahn\": 17392,\n      \"parole\": 17393,\n      \"buyers\": 17394,\n      \"bait\": 17395,\n      \"turbines\": 17396,\n      \"paperwork\": 17397,\n      \"bestowed\": 17398,\n      \"natasha\": 17399,\n      \"renee\": 17400,\n      \"oceans\": 17401,\n      \"purchases\": 17402,\n      \"157\": 17403,\n      \"vaccine\": 17404,\n      \"215\": 17405,\n      \"##tock\": 17406,\n      \"fixtures\": 17407,\n      \"playhouse\": 17408,\n      \"integrate\": 17409,\n      \"jai\": 17410,\n      \"oswald\": 17411,\n      \"intellectuals\": 17412,\n      \"##cky\": 17413,\n      \"booked\": 17414,\n      \"nests\": 17415,\n      \"mortimer\": 17416,\n      \"##isi\": 17417,\n      \"obsession\": 17418,\n      \"sept\": 17419,\n      \"##gler\": 17420,\n      \"##sum\": 17421,\n      \"440\": 17422,\n      \"scrutiny\": 17423,\n      \"simultaneous\": 17424,\n      \"squinted\": 17425,\n      \"##shin\": 17426,\n      \"collects\": 17427,\n      \"oven\": 17428,\n      \"shankar\": 17429,\n      \"penned\": 17430,\n      \"remarkably\": 17431,\n      \"##я\": 17432,\n      \"slips\": 17433,\n      \"luggage\": 17434,\n      \"spectral\": 17435,\n      \"1786\": 17436,\n      \"collaborations\": 17437,\n      \"louie\": 17438,\n      \"consolidation\": 17439,\n      \"##ailed\": 17440,\n      \"##ivating\": 17441,\n      \"420\": 17442,\n      \"hoover\": 17443,\n      \"blackpool\": 17444,\n      \"harness\": 17445,\n      \"ignition\": 17446,\n      \"vest\": 17447,\n      \"tails\": 17448,\n      \"belmont\": 17449,\n      \"mongol\": 17450,\n      \"skinner\": 17451,\n      \"##nae\": 17452,\n      \"visually\": 17453,\n      \"mage\": 17454,\n      \"derry\": 17455,\n      \"##tism\": 17456,\n      \"##unce\": 17457,\n      \"stevie\": 17458,\n      \"transitional\": 17459,\n      \"##rdy\": 17460,\n      \"redskins\": 17461,\n      \"drying\": 17462,\n      \"prep\": 17463,\n      \"prospective\": 17464,\n      \"##21\": 17465,\n      \"annoyance\": 17466,\n      \"oversee\": 17467,\n      \"##loaded\": 17468,\n      \"fills\": 17469,\n      \"##books\": 17470,\n      \"##iki\": 17471,\n      \"announces\": 17472,\n      \"fda\": 17473,\n      \"scowled\": 17474,\n      \"respects\": 17475,\n      \"prasad\": 17476,\n      \"mystic\": 17477,\n      \"tucson\": 17478,\n      \"##vale\": 17479,\n      \"revue\": 17480,\n      \"springer\": 17481,\n      \"bankrupt\": 17482,\n      \"1772\": 17483,\n      \"aristotle\": 17484,\n      \"salvatore\": 17485,\n      \"habsburg\": 17486,\n      \"##geny\": 17487,\n      \"dal\": 17488,\n      \"natal\": 17489,\n      \"nut\": 17490,\n      \"pod\": 17491,\n      \"chewing\": 17492,\n      \"darts\": 17493,\n      \"moroccan\": 17494,\n      \"walkover\": 17495,\n      \"rosario\": 17496,\n      \"lenin\": 17497,\n      \"punjabi\": 17498,\n      \"##ße\": 17499,\n      \"grossed\": 17500,\n      \"scattering\": 17501,\n      \"wired\": 17502,\n      \"invasive\": 17503,\n      \"hui\": 17504,\n      \"polynomial\": 17505,\n      \"corridors\": 17506,\n      \"wakes\": 17507,\n      \"gina\": 17508,\n      \"portrays\": 17509,\n      \"##cratic\": 17510,\n      \"arid\": 17511,\n      \"retreating\": 17512,\n      \"erich\": 17513,\n      \"irwin\": 17514,\n      \"sniper\": 17515,\n      \"##dha\": 17516,\n      \"linen\": 17517,\n      \"lindsey\": 17518,\n      \"maneuver\": 17519,\n      \"butch\": 17520,\n      \"shutting\": 17521,\n      \"socio\": 17522,\n      \"bounce\": 17523,\n      \"commemorative\": 17524,\n      \"postseason\": 17525,\n      \"jeremiah\": 17526,\n      \"pines\": 17527,\n      \"275\": 17528,\n      \"mystical\": 17529,\n      \"beads\": 17530,\n      \"bp\": 17531,\n      \"abbas\": 17532,\n      \"furnace\": 17533,\n      \"bidding\": 17534,\n      \"consulted\": 17535,\n      \"assaulted\": 17536,\n      \"empirical\": 17537,\n      \"rubble\": 17538,\n      \"enclosure\": 17539,\n      \"sob\": 17540,\n      \"weakly\": 17541,\n      \"cancel\": 17542,\n      \"polly\": 17543,\n      \"yielded\": 17544,\n      \"##emann\": 17545,\n      \"curly\": 17546,\n      \"prediction\": 17547,\n      \"battered\": 17548,\n      \"70s\": 17549,\n      \"vhs\": 17550,\n      \"jacqueline\": 17551,\n      \"render\": 17552,\n      \"sails\": 17553,\n      \"barked\": 17554,\n      \"detailing\": 17555,\n      \"grayson\": 17556,\n      \"riga\": 17557,\n      \"sloane\": 17558,\n      \"raging\": 17559,\n      \"##yah\": 17560,\n      \"herbs\": 17561,\n      \"bravo\": 17562,\n      \"##athlon\": 17563,\n      \"alloy\": 17564,\n      \"giggle\": 17565,\n      \"imminent\": 17566,\n      \"suffers\": 17567,\n      \"assumptions\": 17568,\n      \"waltz\": 17569,\n      \"##itate\": 17570,\n      \"accomplishments\": 17571,\n      \"##ited\": 17572,\n      \"bathing\": 17573,\n      \"remixed\": 17574,\n      \"deception\": 17575,\n      \"prefix\": 17576,\n      \"##emia\": 17577,\n      \"deepest\": 17578,\n      \"##tier\": 17579,\n      \"##eis\": 17580,\n      \"balkan\": 17581,\n      \"frogs\": 17582,\n      \"##rong\": 17583,\n      \"slab\": 17584,\n      \"##pate\": 17585,\n      \"philosophers\": 17586,\n      \"peterborough\": 17587,\n      \"grains\": 17588,\n      \"imports\": 17589,\n      \"dickinson\": 17590,\n      \"rwanda\": 17591,\n      \"##atics\": 17592,\n      \"1774\": 17593,\n      \"dirk\": 17594,\n      \"lan\": 17595,\n      \"tablets\": 17596,\n      \"##rove\": 17597,\n      \"clone\": 17598,\n      \"##rice\": 17599,\n      \"caretaker\": 17600,\n      \"hostilities\": 17601,\n      \"mclean\": 17602,\n      \"##gre\": 17603,\n      \"regimental\": 17604,\n      \"treasures\": 17605,\n      \"norms\": 17606,\n      \"impose\": 17607,\n      \"tsar\": 17608,\n      \"tango\": 17609,\n      \"diplomacy\": 17610,\n      \"variously\": 17611,\n      \"complain\": 17612,\n      \"192\": 17613,\n      \"recognise\": 17614,\n      \"arrests\": 17615,\n      \"1779\": 17616,\n      \"celestial\": 17617,\n      \"pulitzer\": 17618,\n      \"##dus\": 17619,\n      \"bing\": 17620,\n      \"libretto\": 17621,\n      \"##moor\": 17622,\n      \"adele\": 17623,\n      \"splash\": 17624,\n      \"##rite\": 17625,\n      \"expectation\": 17626,\n      \"lds\": 17627,\n      \"confronts\": 17628,\n      \"##izer\": 17629,\n      \"spontaneous\": 17630,\n      \"harmful\": 17631,\n      \"wedge\": 17632,\n      \"entrepreneurs\": 17633,\n      \"buyer\": 17634,\n      \"##ope\": 17635,\n      \"bilingual\": 17636,\n      \"translate\": 17637,\n      \"rugged\": 17638,\n      \"conner\": 17639,\n      \"circulated\": 17640,\n      \"uae\": 17641,\n      \"eaton\": 17642,\n      \"##gra\": 17643,\n      \"##zzle\": 17644,\n      \"lingered\": 17645,\n      \"lockheed\": 17646,\n      \"vishnu\": 17647,\n      \"reelection\": 17648,\n      \"alonso\": 17649,\n      \"##oom\": 17650,\n      \"joints\": 17651,\n      \"yankee\": 17652,\n      \"headline\": 17653,\n      \"cooperate\": 17654,\n      \"heinz\": 17655,\n      \"laureate\": 17656,\n      \"invading\": 17657,\n      \"##sford\": 17658,\n      \"echoes\": 17659,\n      \"scandinavian\": 17660,\n      \"##dham\": 17661,\n      \"hugging\": 17662,\n      \"vitamin\": 17663,\n      \"salute\": 17664,\n      \"micah\": 17665,\n      \"hind\": 17666,\n      \"trader\": 17667,\n      \"##sper\": 17668,\n      \"radioactive\": 17669,\n      \"##ndra\": 17670,\n      \"militants\": 17671,\n      \"poisoned\": 17672,\n      \"ratified\": 17673,\n      \"remark\": 17674,\n      \"campeonato\": 17675,\n      \"deprived\": 17676,\n      \"wander\": 17677,\n      \"prop\": 17678,\n      \"##dong\": 17679,\n      \"outlook\": 17680,\n      \"##tani\": 17681,\n      \"##rix\": 17682,\n      \"##eye\": 17683,\n      \"chiang\": 17684,\n      \"darcy\": 17685,\n      \"##oping\": 17686,\n      \"mandolin\": 17687,\n      \"spice\": 17688,\n      \"statesman\": 17689,\n      \"babylon\": 17690,\n      \"182\": 17691,\n      \"walled\": 17692,\n      \"forgetting\": 17693,\n      \"afro\": 17694,\n      \"##cap\": 17695,\n      \"158\": 17696,\n      \"giorgio\": 17697,\n      \"buffer\": 17698,\n      \"##polis\": 17699,\n      \"planetary\": 17700,\n      \"##gis\": 17701,\n      \"overlap\": 17702,\n      \"terminals\": 17703,\n      \"kinda\": 17704,\n      \"centenary\": 17705,\n      \"##bir\": 17706,\n      \"arising\": 17707,\n      \"manipulate\": 17708,\n      \"elm\": 17709,\n      \"ke\": 17710,\n      \"1770\": 17711,\n      \"ak\": 17712,\n      \"##tad\": 17713,\n      \"chrysler\": 17714,\n      \"mapped\": 17715,\n      \"moose\": 17716,\n      \"pomeranian\": 17717,\n      \"quad\": 17718,\n      \"macarthur\": 17719,\n      \"assemblies\": 17720,\n      \"shoreline\": 17721,\n      \"recalls\": 17722,\n      \"stratford\": 17723,\n      \"##rted\": 17724,\n      \"noticeable\": 17725,\n      \"##evic\": 17726,\n      \"imp\": 17727,\n      \"##rita\": 17728,\n      \"##sque\": 17729,\n      \"accustomed\": 17730,\n      \"supplying\": 17731,\n      \"tents\": 17732,\n      \"disgusted\": 17733,\n      \"vogue\": 17734,\n      \"sipped\": 17735,\n      \"filters\": 17736,\n      \"khz\": 17737,\n      \"reno\": 17738,\n      \"selecting\": 17739,\n      \"luftwaffe\": 17740,\n      \"mcmahon\": 17741,\n      \"tyne\": 17742,\n      \"masterpiece\": 17743,\n      \"carriages\": 17744,\n      \"collided\": 17745,\n      \"dunes\": 17746,\n      \"exercised\": 17747,\n      \"flare\": 17748,\n      \"remembers\": 17749,\n      \"muzzle\": 17750,\n      \"##mobile\": 17751,\n      \"heck\": 17752,\n      \"##rson\": 17753,\n      \"burgess\": 17754,\n      \"lunged\": 17755,\n      \"middleton\": 17756,\n      \"boycott\": 17757,\n      \"bilateral\": 17758,\n      \"##sity\": 17759,\n      \"hazardous\": 17760,\n      \"lumpur\": 17761,\n      \"multiplayer\": 17762,\n      \"spotlight\": 17763,\n      \"jackets\": 17764,\n      \"goldman\": 17765,\n      \"liege\": 17766,\n      \"porcelain\": 17767,\n      \"rag\": 17768,\n      \"waterford\": 17769,\n      \"benz\": 17770,\n      \"attracts\": 17771,\n      \"hopeful\": 17772,\n      \"battling\": 17773,\n      \"ottomans\": 17774,\n      \"kensington\": 17775,\n      \"baked\": 17776,\n      \"hymns\": 17777,\n      \"cheyenne\": 17778,\n      \"lattice\": 17779,\n      \"levine\": 17780,\n      \"borrow\": 17781,\n      \"polymer\": 17782,\n      \"clashes\": 17783,\n      \"michaels\": 17784,\n      \"monitored\": 17785,\n      \"commitments\": 17786,\n      \"denounced\": 17787,\n      \"##25\": 17788,\n      \"##von\": 17789,\n      \"cavity\": 17790,\n      \"##oney\": 17791,\n      \"hobby\": 17792,\n      \"akin\": 17793,\n      \"##holders\": 17794,\n      \"futures\": 17795,\n      \"intricate\": 17796,\n      \"cornish\": 17797,\n      \"patty\": 17798,\n      \"##oned\": 17799,\n      \"illegally\": 17800,\n      \"dolphin\": 17801,\n      \"##lag\": 17802,\n      \"barlow\": 17803,\n      \"yellowish\": 17804,\n      \"maddie\": 17805,\n      \"apologized\": 17806,\n      \"luton\": 17807,\n      \"plagued\": 17808,\n      \"##puram\": 17809,\n      \"nana\": 17810,\n      \"##rds\": 17811,\n      \"sway\": 17812,\n      \"fanny\": 17813,\n      \"łodz\": 17814,\n      \"##rino\": 17815,\n      \"psi\": 17816,\n      \"suspicions\": 17817,\n      \"hanged\": 17818,\n      \"##eding\": 17819,\n      \"initiate\": 17820,\n      \"charlton\": 17821,\n      \"##por\": 17822,\n      \"nak\": 17823,\n      \"competent\": 17824,\n      \"235\": 17825,\n      \"analytical\": 17826,\n      \"annex\": 17827,\n      \"wardrobe\": 17828,\n      \"reservations\": 17829,\n      \"##rma\": 17830,\n      \"sect\": 17831,\n      \"162\": 17832,\n      \"fairfax\": 17833,\n      \"hedge\": 17834,\n      \"piled\": 17835,\n      \"buckingham\": 17836,\n      \"uneven\": 17837,\n      \"bauer\": 17838,\n      \"simplicity\": 17839,\n      \"snyder\": 17840,\n      \"interpret\": 17841,\n      \"accountability\": 17842,\n      \"donors\": 17843,\n      \"moderately\": 17844,\n      \"byrd\": 17845,\n      \"continents\": 17846,\n      \"##cite\": 17847,\n      \"##max\": 17848,\n      \"disciple\": 17849,\n      \"hr\": 17850,\n      \"jamaican\": 17851,\n      \"ping\": 17852,\n      \"nominees\": 17853,\n      \"##uss\": 17854,\n      \"mongolian\": 17855,\n      \"diver\": 17856,\n      \"attackers\": 17857,\n      \"eagerly\": 17858,\n      \"ideological\": 17859,\n      \"pillows\": 17860,\n      \"miracles\": 17861,\n      \"apartheid\": 17862,\n      \"revolver\": 17863,\n      \"sulfur\": 17864,\n      \"clinics\": 17865,\n      \"moran\": 17866,\n      \"163\": 17867,\n      \"##enko\": 17868,\n      \"ile\": 17869,\n      \"katy\": 17870,\n      \"rhetoric\": 17871,\n      \"##icated\": 17872,\n      \"chronology\": 17873,\n      \"recycling\": 17874,\n      \"##hrer\": 17875,\n      \"elongated\": 17876,\n      \"mughal\": 17877,\n      \"pascal\": 17878,\n      \"profiles\": 17879,\n      \"vibration\": 17880,\n      \"databases\": 17881,\n      \"domination\": 17882,\n      \"##fare\": 17883,\n      \"##rant\": 17884,\n      \"matthias\": 17885,\n      \"digest\": 17886,\n      \"rehearsal\": 17887,\n      \"polling\": 17888,\n      \"weiss\": 17889,\n      \"initiation\": 17890,\n      \"reeves\": 17891,\n      \"clinging\": 17892,\n      \"flourished\": 17893,\n      \"impress\": 17894,\n      \"ngo\": 17895,\n      \"##hoff\": 17896,\n      \"##ume\": 17897,\n      \"buckley\": 17898,\n      \"symposium\": 17899,\n      \"rhythms\": 17900,\n      \"weed\": 17901,\n      \"emphasize\": 17902,\n      \"transforming\": 17903,\n      \"##taking\": 17904,\n      \"##gence\": 17905,\n      \"##yman\": 17906,\n      \"accountant\": 17907,\n      \"analyze\": 17908,\n      \"flicker\": 17909,\n      \"foil\": 17910,\n      \"priesthood\": 17911,\n      \"voluntarily\": 17912,\n      \"decreases\": 17913,\n      \"##80\": 17914,\n      \"##hya\": 17915,\n      \"slater\": 17916,\n      \"sv\": 17917,\n      \"charting\": 17918,\n      \"mcgill\": 17919,\n      \"##lde\": 17920,\n      \"moreno\": 17921,\n      \"##iu\": 17922,\n      \"besieged\": 17923,\n      \"zur\": 17924,\n      \"robes\": 17925,\n      \"##phic\": 17926,\n      \"admitting\": 17927,\n      \"api\": 17928,\n      \"deported\": 17929,\n      \"turmoil\": 17930,\n      \"peyton\": 17931,\n      \"earthquakes\": 17932,\n      \"##ares\": 17933,\n      \"nationalists\": 17934,\n      \"beau\": 17935,\n      \"clair\": 17936,\n      \"brethren\": 17937,\n      \"interrupt\": 17938,\n      \"welch\": 17939,\n      \"curated\": 17940,\n      \"galerie\": 17941,\n      \"requesting\": 17942,\n      \"164\": 17943,\n      \"##ested\": 17944,\n      \"impending\": 17945,\n      \"steward\": 17946,\n      \"viper\": 17947,\n      \"##vina\": 17948,\n      \"complaining\": 17949,\n      \"beautifully\": 17950,\n      \"brandy\": 17951,\n      \"foam\": 17952,\n      \"nl\": 17953,\n      \"1660\": 17954,\n      \"##cake\": 17955,\n      \"alessandro\": 17956,\n      \"punches\": 17957,\n      \"laced\": 17958,\n      \"explanations\": 17959,\n      \"##lim\": 17960,\n      \"attribute\": 17961,\n      \"clit\": 17962,\n      \"reggie\": 17963,\n      \"discomfort\": 17964,\n      \"##cards\": 17965,\n      \"smoothed\": 17966,\n      \"whales\": 17967,\n      \"##cene\": 17968,\n      \"adler\": 17969,\n      \"countered\": 17970,\n      \"duffy\": 17971,\n      \"disciplinary\": 17972,\n      \"widening\": 17973,\n      \"recipe\": 17974,\n      \"reliance\": 17975,\n      \"conducts\": 17976,\n      \"goats\": 17977,\n      \"gradient\": 17978,\n      \"preaching\": 17979,\n      \"##shaw\": 17980,\n      \"matilda\": 17981,\n      \"quasi\": 17982,\n      \"striped\": 17983,\n      \"meridian\": 17984,\n      \"cannabis\": 17985,\n      \"cordoba\": 17986,\n      \"certificates\": 17987,\n      \"##agh\": 17988,\n      \"##tering\": 17989,\n      \"graffiti\": 17990,\n      \"hangs\": 17991,\n      \"pilgrims\": 17992,\n      \"repeats\": 17993,\n      \"##ych\": 17994,\n      \"revive\": 17995,\n      \"urine\": 17996,\n      \"etat\": 17997,\n      \"##hawk\": 17998,\n      \"fueled\": 17999,\n      \"belts\": 18000,\n      \"fuzzy\": 18001,\n      \"susceptible\": 18002,\n      \"##hang\": 18003,\n      \"mauritius\": 18004,\n      \"salle\": 18005,\n      \"sincere\": 18006,\n      \"beers\": 18007,\n      \"hooks\": 18008,\n      \"##cki\": 18009,\n      \"arbitration\": 18010,\n      \"entrusted\": 18011,\n      \"advise\": 18012,\n      \"sniffed\": 18013,\n      \"seminar\": 18014,\n      \"junk\": 18015,\n      \"donnell\": 18016,\n      \"processors\": 18017,\n      \"principality\": 18018,\n      \"strapped\": 18019,\n      \"celia\": 18020,\n      \"mendoza\": 18021,\n      \"everton\": 18022,\n      \"fortunes\": 18023,\n      \"prejudice\": 18024,\n      \"starving\": 18025,\n      \"reassigned\": 18026,\n      \"steamer\": 18027,\n      \"##lund\": 18028,\n      \"tuck\": 18029,\n      \"evenly\": 18030,\n      \"foreman\": 18031,\n      \"##ffen\": 18032,\n      \"dans\": 18033,\n      \"375\": 18034,\n      \"envisioned\": 18035,\n      \"slit\": 18036,\n      \"##xy\": 18037,\n      \"baseman\": 18038,\n      \"liberia\": 18039,\n      \"rosemary\": 18040,\n      \"##weed\": 18041,\n      \"electrified\": 18042,\n      \"periodically\": 18043,\n      \"potassium\": 18044,\n      \"stride\": 18045,\n      \"contexts\": 18046,\n      \"sperm\": 18047,\n      \"slade\": 18048,\n      \"mariners\": 18049,\n      \"influx\": 18050,\n      \"bianca\": 18051,\n      \"subcommittee\": 18052,\n      \"##rane\": 18053,\n      \"spilling\": 18054,\n      \"icao\": 18055,\n      \"estuary\": 18056,\n      \"##nock\": 18057,\n      \"delivers\": 18058,\n      \"iphone\": 18059,\n      \"##ulata\": 18060,\n      \"isa\": 18061,\n      \"mira\": 18062,\n      \"bohemian\": 18063,\n      \"dessert\": 18064,\n      \"##sbury\": 18065,\n      \"welcoming\": 18066,\n      \"proudly\": 18067,\n      \"slowing\": 18068,\n      \"##chs\": 18069,\n      \"musee\": 18070,\n      \"ascension\": 18071,\n      \"russ\": 18072,\n      \"##vian\": 18073,\n      \"waits\": 18074,\n      \"##psy\": 18075,\n      \"africans\": 18076,\n      \"exploit\": 18077,\n      \"##morphic\": 18078,\n      \"gov\": 18079,\n      \"eccentric\": 18080,\n      \"crab\": 18081,\n      \"peck\": 18082,\n      \"##ull\": 18083,\n      \"entrances\": 18084,\n      \"formidable\": 18085,\n      \"marketplace\": 18086,\n      \"groom\": 18087,\n      \"bolted\": 18088,\n      \"metabolism\": 18089,\n      \"patton\": 18090,\n      \"robbins\": 18091,\n      \"courier\": 18092,\n      \"payload\": 18093,\n      \"endure\": 18094,\n      \"##ifier\": 18095,\n      \"andes\": 18096,\n      \"refrigerator\": 18097,\n      \"##pr\": 18098,\n      \"ornate\": 18099,\n      \"##uca\": 18100,\n      \"ruthless\": 18101,\n      \"illegitimate\": 18102,\n      \"masonry\": 18103,\n      \"strasbourg\": 18104,\n      \"bikes\": 18105,\n      \"adobe\": 18106,\n      \"##³\": 18107,\n      \"apples\": 18108,\n      \"quintet\": 18109,\n      \"willingly\": 18110,\n      \"niche\": 18111,\n      \"bakery\": 18112,\n      \"corpses\": 18113,\n      \"energetic\": 18114,\n      \"##cliffe\": 18115,\n      \"##sser\": 18116,\n      \"##ards\": 18117,\n      \"177\": 18118,\n      \"centimeters\": 18119,\n      \"centro\": 18120,\n      \"fuscous\": 18121,\n      \"cretaceous\": 18122,\n      \"rancho\": 18123,\n      \"##yde\": 18124,\n      \"andrei\": 18125,\n      \"telecom\": 18126,\n      \"tottenham\": 18127,\n      \"oasis\": 18128,\n      \"ordination\": 18129,\n      \"vulnerability\": 18130,\n      \"presiding\": 18131,\n      \"corey\": 18132,\n      \"cp\": 18133,\n      \"penguins\": 18134,\n      \"sims\": 18135,\n      \"##pis\": 18136,\n      \"malawi\": 18137,\n      \"piss\": 18138,\n      \"##48\": 18139,\n      \"correction\": 18140,\n      \"##cked\": 18141,\n      \"##ffle\": 18142,\n      \"##ryn\": 18143,\n      \"countdown\": 18144,\n      \"detectives\": 18145,\n      \"psychiatrist\": 18146,\n      \"psychedelic\": 18147,\n      \"dinosaurs\": 18148,\n      \"blouse\": 18149,\n      \"##get\": 18150,\n      \"choi\": 18151,\n      \"vowed\": 18152,\n      \"##oz\": 18153,\n      \"randomly\": 18154,\n      \"##pol\": 18155,\n      \"49ers\": 18156,\n      \"scrub\": 18157,\n      \"blanche\": 18158,\n      \"bruins\": 18159,\n      \"dusseldorf\": 18160,\n      \"##using\": 18161,\n      \"unwanted\": 18162,\n      \"##ums\": 18163,\n      \"212\": 18164,\n      \"dominique\": 18165,\n      \"elevations\": 18166,\n      \"headlights\": 18167,\n      \"om\": 18168,\n      \"laguna\": 18169,\n      \"##oga\": 18170,\n      \"1750\": 18171,\n      \"famously\": 18172,\n      \"ignorance\": 18173,\n      \"shrewsbury\": 18174,\n      \"##aine\": 18175,\n      \"ajax\": 18176,\n      \"breuning\": 18177,\n      \"che\": 18178,\n      \"confederacy\": 18179,\n      \"greco\": 18180,\n      \"overhaul\": 18181,\n      \"##screen\": 18182,\n      \"paz\": 18183,\n      \"skirts\": 18184,\n      \"disagreement\": 18185,\n      \"cruelty\": 18186,\n      \"jagged\": 18187,\n      \"phoebe\": 18188,\n      \"shifter\": 18189,\n      \"hovered\": 18190,\n      \"viruses\": 18191,\n      \"##wes\": 18192,\n      \"mandy\": 18193,\n      \"##lined\": 18194,\n      \"##gc\": 18195,\n      \"landlord\": 18196,\n      \"squirrel\": 18197,\n      \"dashed\": 18198,\n      \"##ι\": 18199,\n      \"ornamental\": 18200,\n      \"gag\": 18201,\n      \"wally\": 18202,\n      \"grange\": 18203,\n      \"literal\": 18204,\n      \"spurs\": 18205,\n      \"undisclosed\": 18206,\n      \"proceeding\": 18207,\n      \"yin\": 18208,\n      \"##text\": 18209,\n      \"billie\": 18210,\n      \"orphan\": 18211,\n      \"spanned\": 18212,\n      \"humidity\": 18213,\n      \"indy\": 18214,\n      \"weighted\": 18215,\n      \"presentations\": 18216,\n      \"explosions\": 18217,\n      \"lucian\": 18218,\n      \"##tary\": 18219,\n      \"vaughn\": 18220,\n      \"hindus\": 18221,\n      \"##anga\": 18222,\n      \"##hell\": 18223,\n      \"psycho\": 18224,\n      \"171\": 18225,\n      \"daytona\": 18226,\n      \"protects\": 18227,\n      \"efficiently\": 18228,\n      \"rematch\": 18229,\n      \"sly\": 18230,\n      \"tandem\": 18231,\n      \"##oya\": 18232,\n      \"rebranded\": 18233,\n      \"impaired\": 18234,\n      \"hee\": 18235,\n      \"metropolis\": 18236,\n      \"peach\": 18237,\n      \"godfrey\": 18238,\n      \"diaspora\": 18239,\n      \"ethnicity\": 18240,\n      \"prosperous\": 18241,\n      \"gleaming\": 18242,\n      \"dar\": 18243,\n      \"grossing\": 18244,\n      \"playback\": 18245,\n      \"##rden\": 18246,\n      \"stripe\": 18247,\n      \"pistols\": 18248,\n      \"##tain\": 18249,\n      \"births\": 18250,\n      \"labelled\": 18251,\n      \"##cating\": 18252,\n      \"172\": 18253,\n      \"rudy\": 18254,\n      \"alba\": 18255,\n      \"##onne\": 18256,\n      \"aquarium\": 18257,\n      \"hostility\": 18258,\n      \"##gb\": 18259,\n      \"##tase\": 18260,\n      \"shudder\": 18261,\n      \"sumatra\": 18262,\n      \"hardest\": 18263,\n      \"lakers\": 18264,\n      \"consonant\": 18265,\n      \"creeping\": 18266,\n      \"demos\": 18267,\n      \"homicide\": 18268,\n      \"capsule\": 18269,\n      \"zeke\": 18270,\n      \"liberties\": 18271,\n      \"expulsion\": 18272,\n      \"pueblo\": 18273,\n      \"##comb\": 18274,\n      \"trait\": 18275,\n      \"transporting\": 18276,\n      \"##ddin\": 18277,\n      \"##neck\": 18278,\n      \"##yna\": 18279,\n      \"depart\": 18280,\n      \"gregg\": 18281,\n      \"mold\": 18282,\n      \"ledge\": 18283,\n      \"hangar\": 18284,\n      \"oldham\": 18285,\n      \"playboy\": 18286,\n      \"termination\": 18287,\n      \"analysts\": 18288,\n      \"gmbh\": 18289,\n      \"romero\": 18290,\n      \"##itic\": 18291,\n      \"insist\": 18292,\n      \"cradle\": 18293,\n      \"filthy\": 18294,\n      \"brightness\": 18295,\n      \"slash\": 18296,\n      \"shootout\": 18297,\n      \"deposed\": 18298,\n      \"bordering\": 18299,\n      \"##truct\": 18300,\n      \"isis\": 18301,\n      \"microwave\": 18302,\n      \"tumbled\": 18303,\n      \"sheltered\": 18304,\n      \"cathy\": 18305,\n      \"werewolves\": 18306,\n      \"messy\": 18307,\n      \"andersen\": 18308,\n      \"convex\": 18309,\n      \"clapped\": 18310,\n      \"clinched\": 18311,\n      \"satire\": 18312,\n      \"wasting\": 18313,\n      \"edo\": 18314,\n      \"vc\": 18315,\n      \"rufus\": 18316,\n      \"##jak\": 18317,\n      \"mont\": 18318,\n      \"##etti\": 18319,\n      \"poznan\": 18320,\n      \"##keeping\": 18321,\n      \"restructuring\": 18322,\n      \"transverse\": 18323,\n      \"##rland\": 18324,\n      \"azerbaijani\": 18325,\n      \"slovene\": 18326,\n      \"gestures\": 18327,\n      \"roommate\": 18328,\n      \"choking\": 18329,\n      \"shear\": 18330,\n      \"##quist\": 18331,\n      \"vanguard\": 18332,\n      \"oblivious\": 18333,\n      \"##hiro\": 18334,\n      \"disagreed\": 18335,\n      \"baptism\": 18336,\n      \"##lich\": 18337,\n      \"coliseum\": 18338,\n      \"##aceae\": 18339,\n      \"salvage\": 18340,\n      \"societe\": 18341,\n      \"cory\": 18342,\n      \"locke\": 18343,\n      \"relocation\": 18344,\n      \"relying\": 18345,\n      \"versailles\": 18346,\n      \"ahl\": 18347,\n      \"swelling\": 18348,\n      \"##elo\": 18349,\n      \"cheerful\": 18350,\n      \"##word\": 18351,\n      \"##edes\": 18352,\n      \"gin\": 18353,\n      \"sarajevo\": 18354,\n      \"obstacle\": 18355,\n      \"diverted\": 18356,\n      \"##nac\": 18357,\n      \"messed\": 18358,\n      \"thoroughbred\": 18359,\n      \"fluttered\": 18360,\n      \"utrecht\": 18361,\n      \"chewed\": 18362,\n      \"acquaintance\": 18363,\n      \"assassins\": 18364,\n      \"dispatch\": 18365,\n      \"mirza\": 18366,\n      \"##wart\": 18367,\n      \"nike\": 18368,\n      \"salzburg\": 18369,\n      \"swell\": 18370,\n      \"yen\": 18371,\n      \"##gee\": 18372,\n      \"idle\": 18373,\n      \"ligue\": 18374,\n      \"samson\": 18375,\n      \"##nds\": 18376,\n      \"##igh\": 18377,\n      \"playful\": 18378,\n      \"spawned\": 18379,\n      \"##cise\": 18380,\n      \"tease\": 18381,\n      \"##case\": 18382,\n      \"burgundy\": 18383,\n      \"##bot\": 18384,\n      \"stirring\": 18385,\n      \"skeptical\": 18386,\n      \"interceptions\": 18387,\n      \"marathi\": 18388,\n      \"##dies\": 18389,\n      \"bedrooms\": 18390,\n      \"aroused\": 18391,\n      \"pinch\": 18392,\n      \"##lik\": 18393,\n      \"preferences\": 18394,\n      \"tattoos\": 18395,\n      \"buster\": 18396,\n      \"digitally\": 18397,\n      \"projecting\": 18398,\n      \"rust\": 18399,\n      \"##ital\": 18400,\n      \"kitten\": 18401,\n      \"priorities\": 18402,\n      \"addison\": 18403,\n      \"pseudo\": 18404,\n      \"##guard\": 18405,\n      \"dusk\": 18406,\n      \"icons\": 18407,\n      \"sermon\": 18408,\n      \"##psis\": 18409,\n      \"##iba\": 18410,\n      \"bt\": 18411,\n      \"##lift\": 18412,\n      \"##xt\": 18413,\n      \"ju\": 18414,\n      \"truce\": 18415,\n      \"rink\": 18416,\n      \"##dah\": 18417,\n      \"##wy\": 18418,\n      \"defects\": 18419,\n      \"psychiatry\": 18420,\n      \"offences\": 18421,\n      \"calculate\": 18422,\n      \"glucose\": 18423,\n      \"##iful\": 18424,\n      \"##rized\": 18425,\n      \"##unda\": 18426,\n      \"francaise\": 18427,\n      \"##hari\": 18428,\n      \"richest\": 18429,\n      \"warwickshire\": 18430,\n      \"carly\": 18431,\n      \"1763\": 18432,\n      \"purity\": 18433,\n      \"redemption\": 18434,\n      \"lending\": 18435,\n      \"##cious\": 18436,\n      \"muse\": 18437,\n      \"bruises\": 18438,\n      \"cerebral\": 18439,\n      \"aero\": 18440,\n      \"carving\": 18441,\n      \"##name\": 18442,\n      \"preface\": 18443,\n      \"terminology\": 18444,\n      \"invade\": 18445,\n      \"monty\": 18446,\n      \"##int\": 18447,\n      \"anarchist\": 18448,\n      \"blurred\": 18449,\n      \"##iled\": 18450,\n      \"rossi\": 18451,\n      \"treats\": 18452,\n      \"guts\": 18453,\n      \"shu\": 18454,\n      \"foothills\": 18455,\n      \"ballads\": 18456,\n      \"undertaking\": 18457,\n      \"premise\": 18458,\n      \"cecilia\": 18459,\n      \"affiliates\": 18460,\n      \"blasted\": 18461,\n      \"conditional\": 18462,\n      \"wilder\": 18463,\n      \"minors\": 18464,\n      \"drone\": 18465,\n      \"rudolph\": 18466,\n      \"buffy\": 18467,\n      \"swallowing\": 18468,\n      \"horton\": 18469,\n      \"attested\": 18470,\n      \"##hop\": 18471,\n      \"rutherford\": 18472,\n      \"howell\": 18473,\n      \"primetime\": 18474,\n      \"livery\": 18475,\n      \"penal\": 18476,\n      \"##bis\": 18477,\n      \"minimize\": 18478,\n      \"hydro\": 18479,\n      \"wrecked\": 18480,\n      \"wrought\": 18481,\n      \"palazzo\": 18482,\n      \"##gling\": 18483,\n      \"cans\": 18484,\n      \"vernacular\": 18485,\n      \"friedman\": 18486,\n      \"nobleman\": 18487,\n      \"shale\": 18488,\n      \"walnut\": 18489,\n      \"danielle\": 18490,\n      \"##ection\": 18491,\n      \"##tley\": 18492,\n      \"sears\": 18493,\n      \"##kumar\": 18494,\n      \"chords\": 18495,\n      \"lend\": 18496,\n      \"flipping\": 18497,\n      \"streamed\": 18498,\n      \"por\": 18499,\n      \"dracula\": 18500,\n      \"gallons\": 18501,\n      \"sacrifices\": 18502,\n      \"gamble\": 18503,\n      \"orphanage\": 18504,\n      \"##iman\": 18505,\n      \"mckenzie\": 18506,\n      \"##gible\": 18507,\n      \"boxers\": 18508,\n      \"daly\": 18509,\n      \"##balls\": 18510,\n      \"##ان\": 18511,\n      \"208\": 18512,\n      \"##ific\": 18513,\n      \"##rative\": 18514,\n      \"##iq\": 18515,\n      \"exploited\": 18516,\n      \"slated\": 18517,\n      \"##uity\": 18518,\n      \"circling\": 18519,\n      \"hillary\": 18520,\n      \"pinched\": 18521,\n      \"goldberg\": 18522,\n      \"provost\": 18523,\n      \"campaigning\": 18524,\n      \"lim\": 18525,\n      \"piles\": 18526,\n      \"ironically\": 18527,\n      \"jong\": 18528,\n      \"mohan\": 18529,\n      \"successors\": 18530,\n      \"usaf\": 18531,\n      \"##tem\": 18532,\n      \"##ught\": 18533,\n      \"autobiographical\": 18534,\n      \"haute\": 18535,\n      \"preserves\": 18536,\n      \"##ending\": 18537,\n      \"acquitted\": 18538,\n      \"comparisons\": 18539,\n      \"203\": 18540,\n      \"hydroelectric\": 18541,\n      \"gangs\": 18542,\n      \"cypriot\": 18543,\n      \"torpedoes\": 18544,\n      \"rushes\": 18545,\n      \"chrome\": 18546,\n      \"derive\": 18547,\n      \"bumps\": 18548,\n      \"instability\": 18549,\n      \"fiat\": 18550,\n      \"pets\": 18551,\n      \"##mbe\": 18552,\n      \"silas\": 18553,\n      \"dye\": 18554,\n      \"reckless\": 18555,\n      \"settler\": 18556,\n      \"##itation\": 18557,\n      \"info\": 18558,\n      \"heats\": 18559,\n      \"##writing\": 18560,\n      \"176\": 18561,\n      \"canonical\": 18562,\n      \"maltese\": 18563,\n      \"fins\": 18564,\n      \"mushroom\": 18565,\n      \"stacy\": 18566,\n      \"aspen\": 18567,\n      \"avid\": 18568,\n      \"##kur\": 18569,\n      \"##loading\": 18570,\n      \"vickers\": 18571,\n      \"gaston\": 18572,\n      \"hillside\": 18573,\n      \"statutes\": 18574,\n      \"wilde\": 18575,\n      \"gail\": 18576,\n      \"kung\": 18577,\n      \"sabine\": 18578,\n      \"comfortably\": 18579,\n      \"motorcycles\": 18580,\n      \"##rgo\": 18581,\n      \"169\": 18582,\n      \"pneumonia\": 18583,\n      \"fetch\": 18584,\n      \"##sonic\": 18585,\n      \"axel\": 18586,\n      \"faintly\": 18587,\n      \"parallels\": 18588,\n      \"##oop\": 18589,\n      \"mclaren\": 18590,\n      \"spouse\": 18591,\n      \"compton\": 18592,\n      \"interdisciplinary\": 18593,\n      \"miner\": 18594,\n      \"##eni\": 18595,\n      \"181\": 18596,\n      \"clamped\": 18597,\n      \"##chal\": 18598,\n      \"##llah\": 18599,\n      \"separates\": 18600,\n      \"versa\": 18601,\n      \"##mler\": 18602,\n      \"scarborough\": 18603,\n      \"labrador\": 18604,\n      \"##lity\": 18605,\n      \"##osing\": 18606,\n      \"rutgers\": 18607,\n      \"hurdles\": 18608,\n      \"como\": 18609,\n      \"166\": 18610,\n      \"burt\": 18611,\n      \"divers\": 18612,\n      \"##100\": 18613,\n      \"wichita\": 18614,\n      \"cade\": 18615,\n      \"coincided\": 18616,\n      \"##erson\": 18617,\n      \"bruised\": 18618,\n      \"mla\": 18619,\n      \"##pper\": 18620,\n      \"vineyard\": 18621,\n      \"##ili\": 18622,\n      \"##brush\": 18623,\n      \"notch\": 18624,\n      \"mentioning\": 18625,\n      \"jase\": 18626,\n      \"hearted\": 18627,\n      \"kits\": 18628,\n      \"doe\": 18629,\n      \"##acle\": 18630,\n      \"pomerania\": 18631,\n      \"##ady\": 18632,\n      \"ronan\": 18633,\n      \"seizure\": 18634,\n      \"pavel\": 18635,\n      \"problematic\": 18636,\n      \"##zaki\": 18637,\n      \"domenico\": 18638,\n      \"##ulin\": 18639,\n      \"catering\": 18640,\n      \"penelope\": 18641,\n      \"dependence\": 18642,\n      \"parental\": 18643,\n      \"emilio\": 18644,\n      \"ministerial\": 18645,\n      \"atkinson\": 18646,\n      \"##bolic\": 18647,\n      \"clarkson\": 18648,\n      \"chargers\": 18649,\n      \"colby\": 18650,\n      \"grill\": 18651,\n      \"peeked\": 18652,\n      \"arises\": 18653,\n      \"summon\": 18654,\n      \"##aged\": 18655,\n      \"fools\": 18656,\n      \"##grapher\": 18657,\n      \"faculties\": 18658,\n      \"qaeda\": 18659,\n      \"##vial\": 18660,\n      \"garner\": 18661,\n      \"refurbished\": 18662,\n      \"##hwa\": 18663,\n      \"geelong\": 18664,\n      \"disasters\": 18665,\n      \"nudged\": 18666,\n      \"bs\": 18667,\n      \"shareholder\": 18668,\n      \"lori\": 18669,\n      \"algae\": 18670,\n      \"reinstated\": 18671,\n      \"rot\": 18672,\n      \"##ades\": 18673,\n      \"##nous\": 18674,\n      \"invites\": 18675,\n      \"stainless\": 18676,\n      \"183\": 18677,\n      \"inclusive\": 18678,\n      \"##itude\": 18679,\n      \"diocesan\": 18680,\n      \"til\": 18681,\n      \"##icz\": 18682,\n      \"denomination\": 18683,\n      \"##xa\": 18684,\n      \"benton\": 18685,\n      \"floral\": 18686,\n      \"registers\": 18687,\n      \"##ider\": 18688,\n      \"##erman\": 18689,\n      \"##kell\": 18690,\n      \"absurd\": 18691,\n      \"brunei\": 18692,\n      \"guangzhou\": 18693,\n      \"hitter\": 18694,\n      \"retaliation\": 18695,\n      \"##uled\": 18696,\n      \"##eve\": 18697,\n      \"blanc\": 18698,\n      \"nh\": 18699,\n      \"consistency\": 18700,\n      \"contamination\": 18701,\n      \"##eres\": 18702,\n      \"##rner\": 18703,\n      \"dire\": 18704,\n      \"palermo\": 18705,\n      \"broadcasters\": 18706,\n      \"diaries\": 18707,\n      \"inspire\": 18708,\n      \"vols\": 18709,\n      \"brewer\": 18710,\n      \"tightening\": 18711,\n      \"ky\": 18712,\n      \"mixtape\": 18713,\n      \"hormone\": 18714,\n      \"##tok\": 18715,\n      \"stokes\": 18716,\n      \"##color\": 18717,\n      \"##dly\": 18718,\n      \"##ssi\": 18719,\n      \"pg\": 18720,\n      \"##ometer\": 18721,\n      \"##lington\": 18722,\n      \"sanitation\": 18723,\n      \"##tility\": 18724,\n      \"intercontinental\": 18725,\n      \"apps\": 18726,\n      \"##adt\": 18727,\n      \"¹⁄₂\": 18728,\n      \"cylinders\": 18729,\n      \"economies\": 18730,\n      \"favourable\": 18731,\n      \"unison\": 18732,\n      \"croix\": 18733,\n      \"gertrude\": 18734,\n      \"odyssey\": 18735,\n      \"vanity\": 18736,\n      \"dangling\": 18737,\n      \"##logists\": 18738,\n      \"upgrades\": 18739,\n      \"dice\": 18740,\n      \"middleweight\": 18741,\n      \"practitioner\": 18742,\n      \"##ight\": 18743,\n      \"206\": 18744,\n      \"henrik\": 18745,\n      \"parlor\": 18746,\n      \"orion\": 18747,\n      \"angered\": 18748,\n      \"lac\": 18749,\n      \"python\": 18750,\n      \"blurted\": 18751,\n      \"##rri\": 18752,\n      \"sensual\": 18753,\n      \"intends\": 18754,\n      \"swings\": 18755,\n      \"angled\": 18756,\n      \"##phs\": 18757,\n      \"husky\": 18758,\n      \"attain\": 18759,\n      \"peerage\": 18760,\n      \"precinct\": 18761,\n      \"textiles\": 18762,\n      \"cheltenham\": 18763,\n      \"shuffled\": 18764,\n      \"dai\": 18765,\n      \"confess\": 18766,\n      \"tasting\": 18767,\n      \"bhutan\": 18768,\n      \"##riation\": 18769,\n      \"tyrone\": 18770,\n      \"segregation\": 18771,\n      \"abrupt\": 18772,\n      \"ruiz\": 18773,\n      \"##rish\": 18774,\n      \"smirked\": 18775,\n      \"blackwell\": 18776,\n      \"confidential\": 18777,\n      \"browning\": 18778,\n      \"amounted\": 18779,\n      \"##put\": 18780,\n      \"vase\": 18781,\n      \"scarce\": 18782,\n      \"fabulous\": 18783,\n      \"raided\": 18784,\n      \"staple\": 18785,\n      \"guyana\": 18786,\n      \"unemployed\": 18787,\n      \"glider\": 18788,\n      \"shay\": 18789,\n      \"##tow\": 18790,\n      \"carmine\": 18791,\n      \"troll\": 18792,\n      \"intervene\": 18793,\n      \"squash\": 18794,\n      \"superstar\": 18795,\n      \"##uce\": 18796,\n      \"cylindrical\": 18797,\n      \"len\": 18798,\n      \"roadway\": 18799,\n      \"researched\": 18800,\n      \"handy\": 18801,\n      \"##rium\": 18802,\n      \"##jana\": 18803,\n      \"meta\": 18804,\n      \"lao\": 18805,\n      \"declares\": 18806,\n      \"##rring\": 18807,\n      \"##tadt\": 18808,\n      \"##elin\": 18809,\n      \"##kova\": 18810,\n      \"willem\": 18811,\n      \"shrubs\": 18812,\n      \"napoleonic\": 18813,\n      \"realms\": 18814,\n      \"skater\": 18815,\n      \"qi\": 18816,\n      \"volkswagen\": 18817,\n      \"##ł\": 18818,\n      \"tad\": 18819,\n      \"hara\": 18820,\n      \"archaeologist\": 18821,\n      \"awkwardly\": 18822,\n      \"eerie\": 18823,\n      \"##kind\": 18824,\n      \"wiley\": 18825,\n      \"##heimer\": 18826,\n      \"##24\": 18827,\n      \"titus\": 18828,\n      \"organizers\": 18829,\n      \"cfl\": 18830,\n      \"crusaders\": 18831,\n      \"lama\": 18832,\n      \"usb\": 18833,\n      \"vent\": 18834,\n      \"enraged\": 18835,\n      \"thankful\": 18836,\n      \"occupants\": 18837,\n      \"maximilian\": 18838,\n      \"##gaard\": 18839,\n      \"possessing\": 18840,\n      \"textbooks\": 18841,\n      \"##oran\": 18842,\n      \"collaborator\": 18843,\n      \"quaker\": 18844,\n      \"##ulo\": 18845,\n      \"avalanche\": 18846,\n      \"mono\": 18847,\n      \"silky\": 18848,\n      \"straits\": 18849,\n      \"isaiah\": 18850,\n      \"mustang\": 18851,\n      \"surged\": 18852,\n      \"resolutions\": 18853,\n      \"potomac\": 18854,\n      \"descend\": 18855,\n      \"cl\": 18856,\n      \"kilograms\": 18857,\n      \"plato\": 18858,\n      \"strains\": 18859,\n      \"saturdays\": 18860,\n      \"##olin\": 18861,\n      \"bernstein\": 18862,\n      \"##ype\": 18863,\n      \"holstein\": 18864,\n      \"ponytail\": 18865,\n      \"##watch\": 18866,\n      \"belize\": 18867,\n      \"conversely\": 18868,\n      \"heroine\": 18869,\n      \"perpetual\": 18870,\n      \"##ylus\": 18871,\n      \"charcoal\": 18872,\n      \"piedmont\": 18873,\n      \"glee\": 18874,\n      \"negotiating\": 18875,\n      \"backdrop\": 18876,\n      \"prologue\": 18877,\n      \"##jah\": 18878,\n      \"##mmy\": 18879,\n      \"pasadena\": 18880,\n      \"climbs\": 18881,\n      \"ramos\": 18882,\n      \"sunni\": 18883,\n      \"##holm\": 18884,\n      \"##tner\": 18885,\n      \"##tri\": 18886,\n      \"anand\": 18887,\n      \"deficiency\": 18888,\n      \"hertfordshire\": 18889,\n      \"stout\": 18890,\n      \"##avi\": 18891,\n      \"aperture\": 18892,\n      \"orioles\": 18893,\n      \"##irs\": 18894,\n      \"doncaster\": 18895,\n      \"intrigued\": 18896,\n      \"bombed\": 18897,\n      \"coating\": 18898,\n      \"otis\": 18899,\n      \"##mat\": 18900,\n      \"cocktail\": 18901,\n      \"##jit\": 18902,\n      \"##eto\": 18903,\n      \"amir\": 18904,\n      \"arousal\": 18905,\n      \"sar\": 18906,\n      \"##proof\": 18907,\n      \"##act\": 18908,\n      \"##ories\": 18909,\n      \"dixie\": 18910,\n      \"pots\": 18911,\n      \"##bow\": 18912,\n      \"whereabouts\": 18913,\n      \"159\": 18914,\n      \"##fted\": 18915,\n      \"drains\": 18916,\n      \"bullying\": 18917,\n      \"cottages\": 18918,\n      \"scripture\": 18919,\n      \"coherent\": 18920,\n      \"fore\": 18921,\n      \"poe\": 18922,\n      \"appetite\": 18923,\n      \"##uration\": 18924,\n      \"sampled\": 18925,\n      \"##ators\": 18926,\n      \"##dp\": 18927,\n      \"derrick\": 18928,\n      \"rotor\": 18929,\n      \"jays\": 18930,\n      \"peacock\": 18931,\n      \"installment\": 18932,\n      \"##rro\": 18933,\n      \"advisors\": 18934,\n      \"##coming\": 18935,\n      \"rodeo\": 18936,\n      \"scotch\": 18937,\n      \"##mot\": 18938,\n      \"##db\": 18939,\n      \"##fen\": 18940,\n      \"##vant\": 18941,\n      \"ensued\": 18942,\n      \"rodrigo\": 18943,\n      \"dictatorship\": 18944,\n      \"martyrs\": 18945,\n      \"twenties\": 18946,\n      \"##н\": 18947,\n      \"towed\": 18948,\n      \"incidence\": 18949,\n      \"marta\": 18950,\n      \"rainforest\": 18951,\n      \"sai\": 18952,\n      \"scaled\": 18953,\n      \"##cles\": 18954,\n      \"oceanic\": 18955,\n      \"qualifiers\": 18956,\n      \"symphonic\": 18957,\n      \"mcbride\": 18958,\n      \"dislike\": 18959,\n      \"generalized\": 18960,\n      \"aubrey\": 18961,\n      \"colonization\": 18962,\n      \"##iation\": 18963,\n      \"##lion\": 18964,\n      \"##ssing\": 18965,\n      \"disliked\": 18966,\n      \"lublin\": 18967,\n      \"salesman\": 18968,\n      \"##ulates\": 18969,\n      \"spherical\": 18970,\n      \"whatsoever\": 18971,\n      \"sweating\": 18972,\n      \"avalon\": 18973,\n      \"contention\": 18974,\n      \"punt\": 18975,\n      \"severity\": 18976,\n      \"alderman\": 18977,\n      \"atari\": 18978,\n      \"##dina\": 18979,\n      \"##grant\": 18980,\n      \"##rop\": 18981,\n      \"scarf\": 18982,\n      \"seville\": 18983,\n      \"vertices\": 18984,\n      \"annexation\": 18985,\n      \"fairfield\": 18986,\n      \"fascination\": 18987,\n      \"inspiring\": 18988,\n      \"launches\": 18989,\n      \"palatinate\": 18990,\n      \"regretted\": 18991,\n      \"##rca\": 18992,\n      \"feral\": 18993,\n      \"##iom\": 18994,\n      \"elk\": 18995,\n      \"nap\": 18996,\n      \"olsen\": 18997,\n      \"reddy\": 18998,\n      \"yong\": 18999,\n      \"##leader\": 19000,\n      \"##iae\": 19001,\n      \"garment\": 19002,\n      \"transports\": 19003,\n      \"feng\": 19004,\n      \"gracie\": 19005,\n      \"outrage\": 19006,\n      \"viceroy\": 19007,\n      \"insides\": 19008,\n      \"##esis\": 19009,\n      \"breakup\": 19010,\n      \"grady\": 19011,\n      \"organizer\": 19012,\n      \"softer\": 19013,\n      \"grimaced\": 19014,\n      \"222\": 19015,\n      \"murals\": 19016,\n      \"galicia\": 19017,\n      \"arranging\": 19018,\n      \"vectors\": 19019,\n      \"##rsten\": 19020,\n      \"bas\": 19021,\n      \"##sb\": 19022,\n      \"##cens\": 19023,\n      \"sloan\": 19024,\n      \"##eka\": 19025,\n      \"bitten\": 19026,\n      \"ara\": 19027,\n      \"fender\": 19028,\n      \"nausea\": 19029,\n      \"bumped\": 19030,\n      \"kris\": 19031,\n      \"banquet\": 19032,\n      \"comrades\": 19033,\n      \"detector\": 19034,\n      \"persisted\": 19035,\n      \"##llan\": 19036,\n      \"adjustment\": 19037,\n      \"endowed\": 19038,\n      \"cinemas\": 19039,\n      \"##shot\": 19040,\n      \"sellers\": 19041,\n      \"##uman\": 19042,\n      \"peek\": 19043,\n      \"epa\": 19044,\n      \"kindly\": 19045,\n      \"neglect\": 19046,\n      \"simpsons\": 19047,\n      \"talon\": 19048,\n      \"mausoleum\": 19049,\n      \"runaway\": 19050,\n      \"hangul\": 19051,\n      \"lookout\": 19052,\n      \"##cic\": 19053,\n      \"rewards\": 19054,\n      \"coughed\": 19055,\n      \"acquainted\": 19056,\n      \"chloride\": 19057,\n      \"##ald\": 19058,\n      \"quicker\": 19059,\n      \"accordion\": 19060,\n      \"neolithic\": 19061,\n      \"##qa\": 19062,\n      \"artemis\": 19063,\n      \"coefficient\": 19064,\n      \"lenny\": 19065,\n      \"pandora\": 19066,\n      \"tx\": 19067,\n      \"##xed\": 19068,\n      \"ecstasy\": 19069,\n      \"litter\": 19070,\n      \"segunda\": 19071,\n      \"chairperson\": 19072,\n      \"gemma\": 19073,\n      \"hiss\": 19074,\n      \"rumor\": 19075,\n      \"vow\": 19076,\n      \"nasal\": 19077,\n      \"antioch\": 19078,\n      \"compensate\": 19079,\n      \"patiently\": 19080,\n      \"transformers\": 19081,\n      \"##eded\": 19082,\n      \"judo\": 19083,\n      \"morrow\": 19084,\n      \"penis\": 19085,\n      \"posthumous\": 19086,\n      \"philips\": 19087,\n      \"bandits\": 19088,\n      \"husbands\": 19089,\n      \"denote\": 19090,\n      \"flaming\": 19091,\n      \"##any\": 19092,\n      \"##phones\": 19093,\n      \"langley\": 19094,\n      \"yorker\": 19095,\n      \"1760\": 19096,\n      \"walters\": 19097,\n      \"##uo\": 19098,\n      \"##kle\": 19099,\n      \"gubernatorial\": 19100,\n      \"fatty\": 19101,\n      \"samsung\": 19102,\n      \"leroy\": 19103,\n      \"outlaw\": 19104,\n      \"##nine\": 19105,\n      \"unpublished\": 19106,\n      \"poole\": 19107,\n      \"jakob\": 19108,\n      \"##ᵢ\": 19109,\n      \"##ₙ\": 19110,\n      \"crete\": 19111,\n      \"distorted\": 19112,\n      \"superiority\": 19113,\n      \"##dhi\": 19114,\n      \"intercept\": 19115,\n      \"crust\": 19116,\n      \"mig\": 19117,\n      \"claus\": 19118,\n      \"crashes\": 19119,\n      \"positioning\": 19120,\n      \"188\": 19121,\n      \"stallion\": 19122,\n      \"301\": 19123,\n      \"frontal\": 19124,\n      \"armistice\": 19125,\n      \"##estinal\": 19126,\n      \"elton\": 19127,\n      \"aj\": 19128,\n      \"encompassing\": 19129,\n      \"camel\": 19130,\n      \"commemorated\": 19131,\n      \"malaria\": 19132,\n      \"woodward\": 19133,\n      \"calf\": 19134,\n      \"cigar\": 19135,\n      \"penetrate\": 19136,\n      \"##oso\": 19137,\n      \"willard\": 19138,\n      \"##rno\": 19139,\n      \"##uche\": 19140,\n      \"illustrate\": 19141,\n      \"amusing\": 19142,\n      \"convergence\": 19143,\n      \"noteworthy\": 19144,\n      \"##lma\": 19145,\n      \"##rva\": 19146,\n      \"journeys\": 19147,\n      \"realise\": 19148,\n      \"manfred\": 19149,\n      \"##sable\": 19150,\n      \"410\": 19151,\n      \"##vocation\": 19152,\n      \"hearings\": 19153,\n      \"fiance\": 19154,\n      \"##posed\": 19155,\n      \"educators\": 19156,\n      \"provoked\": 19157,\n      \"adjusting\": 19158,\n      \"##cturing\": 19159,\n      \"modular\": 19160,\n      \"stockton\": 19161,\n      \"paterson\": 19162,\n      \"vlad\": 19163,\n      \"rejects\": 19164,\n      \"electors\": 19165,\n      \"selena\": 19166,\n      \"maureen\": 19167,\n      \"##tres\": 19168,\n      \"uber\": 19169,\n      \"##rce\": 19170,\n      \"swirled\": 19171,\n      \"##num\": 19172,\n      \"proportions\": 19173,\n      \"nanny\": 19174,\n      \"pawn\": 19175,\n      \"naturalist\": 19176,\n      \"parma\": 19177,\n      \"apostles\": 19178,\n      \"awoke\": 19179,\n      \"ethel\": 19180,\n      \"wen\": 19181,\n      \"##bey\": 19182,\n      \"monsoon\": 19183,\n      \"overview\": 19184,\n      \"##inating\": 19185,\n      \"mccain\": 19186,\n      \"rendition\": 19187,\n      \"risky\": 19188,\n      \"adorned\": 19189,\n      \"##ih\": 19190,\n      \"equestrian\": 19191,\n      \"germain\": 19192,\n      \"nj\": 19193,\n      \"conspicuous\": 19194,\n      \"confirming\": 19195,\n      \"##yoshi\": 19196,\n      \"shivering\": 19197,\n      \"##imeter\": 19198,\n      \"milestone\": 19199,\n      \"rumours\": 19200,\n      \"flinched\": 19201,\n      \"bounds\": 19202,\n      \"smacked\": 19203,\n      \"token\": 19204,\n      \"##bei\": 19205,\n      \"lectured\": 19206,\n      \"automobiles\": 19207,\n      \"##shore\": 19208,\n      \"impacted\": 19209,\n      \"##iable\": 19210,\n      \"nouns\": 19211,\n      \"nero\": 19212,\n      \"##leaf\": 19213,\n      \"ismail\": 19214,\n      \"prostitute\": 19215,\n      \"trams\": 19216,\n      \"##lace\": 19217,\n      \"bridget\": 19218,\n      \"sud\": 19219,\n      \"stimulus\": 19220,\n      \"impressions\": 19221,\n      \"reins\": 19222,\n      \"revolves\": 19223,\n      \"##oud\": 19224,\n      \"##gned\": 19225,\n      \"giro\": 19226,\n      \"honeymoon\": 19227,\n      \"##swell\": 19228,\n      \"criterion\": 19229,\n      \"##sms\": 19230,\n      \"##uil\": 19231,\n      \"libyan\": 19232,\n      \"prefers\": 19233,\n      \"##osition\": 19234,\n      \"211\": 19235,\n      \"preview\": 19236,\n      \"sucks\": 19237,\n      \"accusation\": 19238,\n      \"bursts\": 19239,\n      \"metaphor\": 19240,\n      \"diffusion\": 19241,\n      \"tolerate\": 19242,\n      \"faye\": 19243,\n      \"betting\": 19244,\n      \"cinematographer\": 19245,\n      \"liturgical\": 19246,\n      \"specials\": 19247,\n      \"bitterly\": 19248,\n      \"humboldt\": 19249,\n      \"##ckle\": 19250,\n      \"flux\": 19251,\n      \"rattled\": 19252,\n      \"##itzer\": 19253,\n      \"archaeologists\": 19254,\n      \"odor\": 19255,\n      \"authorised\": 19256,\n      \"marshes\": 19257,\n      \"discretion\": 19258,\n      \"##ов\": 19259,\n      \"alarmed\": 19260,\n      \"archaic\": 19261,\n      \"inverse\": 19262,\n      \"##leton\": 19263,\n      \"explorers\": 19264,\n      \"##pine\": 19265,\n      \"drummond\": 19266,\n      \"tsunami\": 19267,\n      \"woodlands\": 19268,\n      \"##minate\": 19269,\n      \"##tland\": 19270,\n      \"booklet\": 19271,\n      \"insanity\": 19272,\n      \"owning\": 19273,\n      \"insert\": 19274,\n      \"crafted\": 19275,\n      \"calculus\": 19276,\n      \"##tore\": 19277,\n      \"receivers\": 19278,\n      \"##bt\": 19279,\n      \"stung\": 19280,\n      \"##eca\": 19281,\n      \"##nched\": 19282,\n      \"prevailing\": 19283,\n      \"travellers\": 19284,\n      \"eyeing\": 19285,\n      \"lila\": 19286,\n      \"graphs\": 19287,\n      \"##borne\": 19288,\n      \"178\": 19289,\n      \"julien\": 19290,\n      \"##won\": 19291,\n      \"morale\": 19292,\n      \"adaptive\": 19293,\n      \"therapist\": 19294,\n      \"erica\": 19295,\n      \"cw\": 19296,\n      \"libertarian\": 19297,\n      \"bowman\": 19298,\n      \"pitches\": 19299,\n      \"vita\": 19300,\n      \"##ional\": 19301,\n      \"crook\": 19302,\n      \"##ads\": 19303,\n      \"##entation\": 19304,\n      \"caledonia\": 19305,\n      \"mutiny\": 19306,\n      \"##sible\": 19307,\n      \"1840s\": 19308,\n      \"automation\": 19309,\n      \"##ß\": 19310,\n      \"flock\": 19311,\n      \"##pia\": 19312,\n      \"ironic\": 19313,\n      \"pathology\": 19314,\n      \"##imus\": 19315,\n      \"remarried\": 19316,\n      \"##22\": 19317,\n      \"joker\": 19318,\n      \"withstand\": 19319,\n      \"energies\": 19320,\n      \"##att\": 19321,\n      \"shropshire\": 19322,\n      \"hostages\": 19323,\n      \"madeleine\": 19324,\n      \"tentatively\": 19325,\n      \"conflicting\": 19326,\n      \"mateo\": 19327,\n      \"recipes\": 19328,\n      \"euros\": 19329,\n      \"ol\": 19330,\n      \"mercenaries\": 19331,\n      \"nico\": 19332,\n      \"##ndon\": 19333,\n      \"albuquerque\": 19334,\n      \"augmented\": 19335,\n      \"mythical\": 19336,\n      \"bel\": 19337,\n      \"freud\": 19338,\n      \"##child\": 19339,\n      \"cough\": 19340,\n      \"##lica\": 19341,\n      \"365\": 19342,\n      \"freddy\": 19343,\n      \"lillian\": 19344,\n      \"genetically\": 19345,\n      \"nuremberg\": 19346,\n      \"calder\": 19347,\n      \"209\": 19348,\n      \"bonn\": 19349,\n      \"outdoors\": 19350,\n      \"paste\": 19351,\n      \"suns\": 19352,\n      \"urgency\": 19353,\n      \"vin\": 19354,\n      \"restraint\": 19355,\n      \"tyson\": 19356,\n      \"##cera\": 19357,\n      \"##selle\": 19358,\n      \"barrage\": 19359,\n      \"bethlehem\": 19360,\n      \"kahn\": 19361,\n      \"##par\": 19362,\n      \"mounts\": 19363,\n      \"nippon\": 19364,\n      \"barony\": 19365,\n      \"happier\": 19366,\n      \"ryu\": 19367,\n      \"makeshift\": 19368,\n      \"sheldon\": 19369,\n      \"blushed\": 19370,\n      \"castillo\": 19371,\n      \"barking\": 19372,\n      \"listener\": 19373,\n      \"taped\": 19374,\n      \"bethel\": 19375,\n      \"fluent\": 19376,\n      \"headlines\": 19377,\n      \"pornography\": 19378,\n      \"rum\": 19379,\n      \"disclosure\": 19380,\n      \"sighing\": 19381,\n      \"mace\": 19382,\n      \"doubling\": 19383,\n      \"gunther\": 19384,\n      \"manly\": 19385,\n      \"##plex\": 19386,\n      \"rt\": 19387,\n      \"interventions\": 19388,\n      \"physiological\": 19389,\n      \"forwards\": 19390,\n      \"emerges\": 19391,\n      \"##tooth\": 19392,\n      \"##gny\": 19393,\n      \"compliment\": 19394,\n      \"rib\": 19395,\n      \"recession\": 19396,\n      \"visibly\": 19397,\n      \"barge\": 19398,\n      \"faults\": 19399,\n      \"connector\": 19400,\n      \"exquisite\": 19401,\n      \"prefect\": 19402,\n      \"##rlin\": 19403,\n      \"patio\": 19404,\n      \"##cured\": 19405,\n      \"elevators\": 19406,\n      \"brandt\": 19407,\n      \"italics\": 19408,\n      \"pena\": 19409,\n      \"173\": 19410,\n      \"wasp\": 19411,\n      \"satin\": 19412,\n      \"ea\": 19413,\n      \"botswana\": 19414,\n      \"graceful\": 19415,\n      \"respectable\": 19416,\n      \"##jima\": 19417,\n      \"##rter\": 19418,\n      \"##oic\": 19419,\n      \"franciscan\": 19420,\n      \"generates\": 19421,\n      \"##dl\": 19422,\n      \"alfredo\": 19423,\n      \"disgusting\": 19424,\n      \"##olate\": 19425,\n      \"##iously\": 19426,\n      \"sherwood\": 19427,\n      \"warns\": 19428,\n      \"cod\": 19429,\n      \"promo\": 19430,\n      \"cheryl\": 19431,\n      \"sino\": 19432,\n      \"##ة\": 19433,\n      \"##escu\": 19434,\n      \"twitch\": 19435,\n      \"##zhi\": 19436,\n      \"brownish\": 19437,\n      \"thom\": 19438,\n      \"ortiz\": 19439,\n      \"##dron\": 19440,\n      \"densely\": 19441,\n      \"##beat\": 19442,\n      \"carmel\": 19443,\n      \"reinforce\": 19444,\n      \"##bana\": 19445,\n      \"187\": 19446,\n      \"anastasia\": 19447,\n      \"downhill\": 19448,\n      \"vertex\": 19449,\n      \"contaminated\": 19450,\n      \"remembrance\": 19451,\n      \"harmonic\": 19452,\n      \"homework\": 19453,\n      \"##sol\": 19454,\n      \"fiancee\": 19455,\n      \"gears\": 19456,\n      \"olds\": 19457,\n      \"angelica\": 19458,\n      \"loft\": 19459,\n      \"ramsay\": 19460,\n      \"quiz\": 19461,\n      \"colliery\": 19462,\n      \"sevens\": 19463,\n      \"##cape\": 19464,\n      \"autism\": 19465,\n      \"##hil\": 19466,\n      \"walkway\": 19467,\n      \"##boats\": 19468,\n      \"ruben\": 19469,\n      \"abnormal\": 19470,\n      \"ounce\": 19471,\n      \"khmer\": 19472,\n      \"##bbe\": 19473,\n      \"zachary\": 19474,\n      \"bedside\": 19475,\n      \"morphology\": 19476,\n      \"punching\": 19477,\n      \"##olar\": 19478,\n      \"sparrow\": 19479,\n      \"convinces\": 19480,\n      \"##35\": 19481,\n      \"hewitt\": 19482,\n      \"queer\": 19483,\n      \"remastered\": 19484,\n      \"rods\": 19485,\n      \"mabel\": 19486,\n      \"solemn\": 19487,\n      \"notified\": 19488,\n      \"lyricist\": 19489,\n      \"symmetric\": 19490,\n      \"##xide\": 19491,\n      \"174\": 19492,\n      \"encore\": 19493,\n      \"passports\": 19494,\n      \"wildcats\": 19495,\n      \"##uni\": 19496,\n      \"baja\": 19497,\n      \"##pac\": 19498,\n      \"mildly\": 19499,\n      \"##ease\": 19500,\n      \"bleed\": 19501,\n      \"commodity\": 19502,\n      \"mounds\": 19503,\n      \"glossy\": 19504,\n      \"orchestras\": 19505,\n      \"##omo\": 19506,\n      \"damian\": 19507,\n      \"prelude\": 19508,\n      \"ambitions\": 19509,\n      \"##vet\": 19510,\n      \"awhile\": 19511,\n      \"remotely\": 19512,\n      \"##aud\": 19513,\n      \"asserts\": 19514,\n      \"imply\": 19515,\n      \"##iques\": 19516,\n      \"distinctly\": 19517,\n      \"modelling\": 19518,\n      \"remedy\": 19519,\n      \"##dded\": 19520,\n      \"windshield\": 19521,\n      \"dani\": 19522,\n      \"xiao\": 19523,\n      \"##endra\": 19524,\n      \"audible\": 19525,\n      \"powerplant\": 19526,\n      \"1300\": 19527,\n      \"invalid\": 19528,\n      \"elemental\": 19529,\n      \"acquisitions\": 19530,\n      \"##hala\": 19531,\n      \"immaculate\": 19532,\n      \"libby\": 19533,\n      \"plata\": 19534,\n      \"smuggling\": 19535,\n      \"ventilation\": 19536,\n      \"denoted\": 19537,\n      \"minh\": 19538,\n      \"##morphism\": 19539,\n      \"430\": 19540,\n      \"differed\": 19541,\n      \"dion\": 19542,\n      \"kelley\": 19543,\n      \"lore\": 19544,\n      \"mocking\": 19545,\n      \"sabbath\": 19546,\n      \"spikes\": 19547,\n      \"hygiene\": 19548,\n      \"drown\": 19549,\n      \"runoff\": 19550,\n      \"stylized\": 19551,\n      \"tally\": 19552,\n      \"liberated\": 19553,\n      \"aux\": 19554,\n      \"interpreter\": 19555,\n      \"righteous\": 19556,\n      \"aba\": 19557,\n      \"siren\": 19558,\n      \"reaper\": 19559,\n      \"pearce\": 19560,\n      \"millie\": 19561,\n      \"##cier\": 19562,\n      \"##yra\": 19563,\n      \"gaius\": 19564,\n      \"##iso\": 19565,\n      \"captures\": 19566,\n      \"##ttering\": 19567,\n      \"dorm\": 19568,\n      \"claudio\": 19569,\n      \"##sic\": 19570,\n      \"benches\": 19571,\n      \"knighted\": 19572,\n      \"blackness\": 19573,\n      \"##ored\": 19574,\n      \"discount\": 19575,\n      \"fumble\": 19576,\n      \"oxidation\": 19577,\n      \"routed\": 19578,\n      \"##ς\": 19579,\n      \"novak\": 19580,\n      \"perpendicular\": 19581,\n      \"spoiled\": 19582,\n      \"fracture\": 19583,\n      \"splits\": 19584,\n      \"##urt\": 19585,\n      \"pads\": 19586,\n      \"topology\": 19587,\n      \"##cats\": 19588,\n      \"axes\": 19589,\n      \"fortunate\": 19590,\n      \"offenders\": 19591,\n      \"protestants\": 19592,\n      \"esteem\": 19593,\n      \"221\": 19594,\n      \"broadband\": 19595,\n      \"convened\": 19596,\n      \"frankly\": 19597,\n      \"hound\": 19598,\n      \"prototypes\": 19599,\n      \"isil\": 19600,\n      \"facilitated\": 19601,\n      \"keel\": 19602,\n      \"##sher\": 19603,\n      \"sahara\": 19604,\n      \"awaited\": 19605,\n      \"bubba\": 19606,\n      \"orb\": 19607,\n      \"prosecutors\": 19608,\n      \"186\": 19609,\n      \"hem\": 19610,\n      \"520\": 19611,\n      \"##xing\": 19612,\n      \"relaxing\": 19613,\n      \"remnant\": 19614,\n      \"romney\": 19615,\n      \"sorted\": 19616,\n      \"slalom\": 19617,\n      \"stefano\": 19618,\n      \"ulrich\": 19619,\n      \"##active\": 19620,\n      \"exemption\": 19621,\n      \"folder\": 19622,\n      \"pauses\": 19623,\n      \"foliage\": 19624,\n      \"hitchcock\": 19625,\n      \"epithet\": 19626,\n      \"204\": 19627,\n      \"criticisms\": 19628,\n      \"##aca\": 19629,\n      \"ballistic\": 19630,\n      \"brody\": 19631,\n      \"hinduism\": 19632,\n      \"chaotic\": 19633,\n      \"youths\": 19634,\n      \"equals\": 19635,\n      \"##pala\": 19636,\n      \"pts\": 19637,\n      \"thicker\": 19638,\n      \"analogous\": 19639,\n      \"capitalist\": 19640,\n      \"improvised\": 19641,\n      \"overseeing\": 19642,\n      \"sinatra\": 19643,\n      \"ascended\": 19644,\n      \"beverage\": 19645,\n      \"##tl\": 19646,\n      \"straightforward\": 19647,\n      \"##kon\": 19648,\n      \"curran\": 19649,\n      \"##west\": 19650,\n      \"bois\": 19651,\n      \"325\": 19652,\n      \"induce\": 19653,\n      \"surveying\": 19654,\n      \"emperors\": 19655,\n      \"sax\": 19656,\n      \"unpopular\": 19657,\n      \"##kk\": 19658,\n      \"cartoonist\": 19659,\n      \"fused\": 19660,\n      \"##mble\": 19661,\n      \"unto\": 19662,\n      \"##yuki\": 19663,\n      \"localities\": 19664,\n      \"##cko\": 19665,\n      \"##ln\": 19666,\n      \"darlington\": 19667,\n      \"slain\": 19668,\n      \"academie\": 19669,\n      \"lobbying\": 19670,\n      \"sediment\": 19671,\n      \"puzzles\": 19672,\n      \"##grass\": 19673,\n      \"defiance\": 19674,\n      \"dickens\": 19675,\n      \"manifest\": 19676,\n      \"tongues\": 19677,\n      \"alumnus\": 19678,\n      \"arbor\": 19679,\n      \"coincide\": 19680,\n      \"184\": 19681,\n      \"appalachian\": 19682,\n      \"mustafa\": 19683,\n      \"examiner\": 19684,\n      \"cabaret\": 19685,\n      \"traumatic\": 19686,\n      \"yves\": 19687,\n      \"bracelet\": 19688,\n      \"draining\": 19689,\n      \"heroin\": 19690,\n      \"magnum\": 19691,\n      \"baths\": 19692,\n      \"odessa\": 19693,\n      \"consonants\": 19694,\n      \"mitsubishi\": 19695,\n      \"##gua\": 19696,\n      \"kellan\": 19697,\n      \"vaudeville\": 19698,\n      \"##fr\": 19699,\n      \"joked\": 19700,\n      \"null\": 19701,\n      \"straps\": 19702,\n      \"probation\": 19703,\n      \"##ław\": 19704,\n      \"ceded\": 19705,\n      \"interfaces\": 19706,\n      \"##pas\": 19707,\n      \"##zawa\": 19708,\n      \"blinding\": 19709,\n      \"viet\": 19710,\n      \"224\": 19711,\n      \"rothschild\": 19712,\n      \"museo\": 19713,\n      \"640\": 19714,\n      \"huddersfield\": 19715,\n      \"##vr\": 19716,\n      \"tactic\": 19717,\n      \"##storm\": 19718,\n      \"brackets\": 19719,\n      \"dazed\": 19720,\n      \"incorrectly\": 19721,\n      \"##vu\": 19722,\n      \"reg\": 19723,\n      \"glazed\": 19724,\n      \"fearful\": 19725,\n      \"manifold\": 19726,\n      \"benefited\": 19727,\n      \"irony\": 19728,\n      \"##sun\": 19729,\n      \"stumbling\": 19730,\n      \"##rte\": 19731,\n      \"willingness\": 19732,\n      \"balkans\": 19733,\n      \"mei\": 19734,\n      \"wraps\": 19735,\n      \"##aba\": 19736,\n      \"injected\": 19737,\n      \"##lea\": 19738,\n      \"gu\": 19739,\n      \"syed\": 19740,\n      \"harmless\": 19741,\n      \"##hammer\": 19742,\n      \"bray\": 19743,\n      \"takeoff\": 19744,\n      \"poppy\": 19745,\n      \"timor\": 19746,\n      \"cardboard\": 19747,\n      \"astronaut\": 19748,\n      \"purdue\": 19749,\n      \"weeping\": 19750,\n      \"southbound\": 19751,\n      \"cursing\": 19752,\n      \"stalls\": 19753,\n      \"diagonal\": 19754,\n      \"##neer\": 19755,\n      \"lamar\": 19756,\n      \"bryce\": 19757,\n      \"comte\": 19758,\n      \"weekdays\": 19759,\n      \"harrington\": 19760,\n      \"##uba\": 19761,\n      \"negatively\": 19762,\n      \"##see\": 19763,\n      \"lays\": 19764,\n      \"grouping\": 19765,\n      \"##cken\": 19766,\n      \"##henko\": 19767,\n      \"affirmed\": 19768,\n      \"halle\": 19769,\n      \"modernist\": 19770,\n      \"##lai\": 19771,\n      \"hodges\": 19772,\n      \"smelling\": 19773,\n      \"aristocratic\": 19774,\n      \"baptized\": 19775,\n      \"dismiss\": 19776,\n      \"justification\": 19777,\n      \"oilers\": 19778,\n      \"##now\": 19779,\n      \"coupling\": 19780,\n      \"qin\": 19781,\n      \"snack\": 19782,\n      \"healer\": 19783,\n      \"##qing\": 19784,\n      \"gardener\": 19785,\n      \"layla\": 19786,\n      \"battled\": 19787,\n      \"formulated\": 19788,\n      \"stephenson\": 19789,\n      \"gravitational\": 19790,\n      \"##gill\": 19791,\n      \"##jun\": 19792,\n      \"1768\": 19793,\n      \"granny\": 19794,\n      \"coordinating\": 19795,\n      \"suites\": 19796,\n      \"##cd\": 19797,\n      \"##ioned\": 19798,\n      \"monarchs\": 19799,\n      \"##cote\": 19800,\n      \"##hips\": 19801,\n      \"sep\": 19802,\n      \"blended\": 19803,\n      \"apr\": 19804,\n      \"barrister\": 19805,\n      \"deposition\": 19806,\n      \"fia\": 19807,\n      \"mina\": 19808,\n      \"policemen\": 19809,\n      \"paranoid\": 19810,\n      \"##pressed\": 19811,\n      \"churchyard\": 19812,\n      \"covert\": 19813,\n      \"crumpled\": 19814,\n      \"creep\": 19815,\n      \"abandoning\": 19816,\n      \"tr\": 19817,\n      \"transmit\": 19818,\n      \"conceal\": 19819,\n      \"barr\": 19820,\n      \"understands\": 19821,\n      \"readiness\": 19822,\n      \"spire\": 19823,\n      \"##cology\": 19824,\n      \"##enia\": 19825,\n      \"##erry\": 19826,\n      \"610\": 19827,\n      \"startling\": 19828,\n      \"unlock\": 19829,\n      \"vida\": 19830,\n      \"bowled\": 19831,\n      \"slots\": 19832,\n      \"##nat\": 19833,\n      \"##islav\": 19834,\n      \"spaced\": 19835,\n      \"trusting\": 19836,\n      \"admire\": 19837,\n      \"rig\": 19838,\n      \"##ink\": 19839,\n      \"slack\": 19840,\n      \"##70\": 19841,\n      \"mv\": 19842,\n      \"207\": 19843,\n      \"casualty\": 19844,\n      \"##wei\": 19845,\n      \"classmates\": 19846,\n      \"##odes\": 19847,\n      \"##rar\": 19848,\n      \"##rked\": 19849,\n      \"amherst\": 19850,\n      \"furnished\": 19851,\n      \"evolve\": 19852,\n      \"foundry\": 19853,\n      \"menace\": 19854,\n      \"mead\": 19855,\n      \"##lein\": 19856,\n      \"flu\": 19857,\n      \"wesleyan\": 19858,\n      \"##kled\": 19859,\n      \"monterey\": 19860,\n      \"webber\": 19861,\n      \"##vos\": 19862,\n      \"wil\": 19863,\n      \"##mith\": 19864,\n      \"##на\": 19865,\n      \"bartholomew\": 19866,\n      \"justices\": 19867,\n      \"restrained\": 19868,\n      \"##cke\": 19869,\n      \"amenities\": 19870,\n      \"191\": 19871,\n      \"mediated\": 19872,\n      \"sewage\": 19873,\n      \"trenches\": 19874,\n      \"ml\": 19875,\n      \"mainz\": 19876,\n      \"##thus\": 19877,\n      \"1800s\": 19878,\n      \"##cula\": 19879,\n      \"##inski\": 19880,\n      \"caine\": 19881,\n      \"bonding\": 19882,\n      \"213\": 19883,\n      \"converts\": 19884,\n      \"spheres\": 19885,\n      \"superseded\": 19886,\n      \"marianne\": 19887,\n      \"crypt\": 19888,\n      \"sweaty\": 19889,\n      \"ensign\": 19890,\n      \"historia\": 19891,\n      \"##br\": 19892,\n      \"spruce\": 19893,\n      \"##post\": 19894,\n      \"##ask\": 19895,\n      \"forks\": 19896,\n      \"thoughtfully\": 19897,\n      \"yukon\": 19898,\n      \"pamphlet\": 19899,\n      \"ames\": 19900,\n      \"##uter\": 19901,\n      \"karma\": 19902,\n      \"##yya\": 19903,\n      \"bryn\": 19904,\n      \"negotiation\": 19905,\n      \"sighs\": 19906,\n      \"incapable\": 19907,\n      \"##mbre\": 19908,\n      \"##ntial\": 19909,\n      \"actresses\": 19910,\n      \"taft\": 19911,\n      \"##mill\": 19912,\n      \"luce\": 19913,\n      \"prevailed\": 19914,\n      \"##amine\": 19915,\n      \"1773\": 19916,\n      \"motionless\": 19917,\n      \"envoy\": 19918,\n      \"testify\": 19919,\n      \"investing\": 19920,\n      \"sculpted\": 19921,\n      \"instructors\": 19922,\n      \"provence\": 19923,\n      \"kali\": 19924,\n      \"cullen\": 19925,\n      \"horseback\": 19926,\n      \"##while\": 19927,\n      \"goodwin\": 19928,\n      \"##jos\": 19929,\n      \"gaa\": 19930,\n      \"norte\": 19931,\n      \"##ldon\": 19932,\n      \"modify\": 19933,\n      \"wavelength\": 19934,\n      \"abd\": 19935,\n      \"214\": 19936,\n      \"skinned\": 19937,\n      \"sprinter\": 19938,\n      \"forecast\": 19939,\n      \"scheduling\": 19940,\n      \"marries\": 19941,\n      \"squared\": 19942,\n      \"tentative\": 19943,\n      \"##chman\": 19944,\n      \"boer\": 19945,\n      \"##isch\": 19946,\n      \"bolts\": 19947,\n      \"swap\": 19948,\n      \"fisherman\": 19949,\n      \"assyrian\": 19950,\n      \"impatiently\": 19951,\n      \"guthrie\": 19952,\n      \"martins\": 19953,\n      \"murdoch\": 19954,\n      \"194\": 19955,\n      \"tanya\": 19956,\n      \"nicely\": 19957,\n      \"dolly\": 19958,\n      \"lacy\": 19959,\n      \"med\": 19960,\n      \"##45\": 19961,\n      \"syn\": 19962,\n      \"decks\": 19963,\n      \"fashionable\": 19964,\n      \"millionaire\": 19965,\n      \"##ust\": 19966,\n      \"surfing\": 19967,\n      \"##ml\": 19968,\n      \"##ision\": 19969,\n      \"heaved\": 19970,\n      \"tammy\": 19971,\n      \"consulate\": 19972,\n      \"attendees\": 19973,\n      \"routinely\": 19974,\n      \"197\": 19975,\n      \"fuse\": 19976,\n      \"saxophonist\": 19977,\n      \"backseat\": 19978,\n      \"malaya\": 19979,\n      \"##lord\": 19980,\n      \"scowl\": 19981,\n      \"tau\": 19982,\n      \"##ishly\": 19983,\n      \"193\": 19984,\n      \"sighted\": 19985,\n      \"steaming\": 19986,\n      \"##rks\": 19987,\n      \"303\": 19988,\n      \"911\": 19989,\n      \"##holes\": 19990,\n      \"##hong\": 19991,\n      \"ching\": 19992,\n      \"##wife\": 19993,\n      \"bless\": 19994,\n      \"conserved\": 19995,\n      \"jurassic\": 19996,\n      \"stacey\": 19997,\n      \"unix\": 19998,\n      \"zion\": 19999,\n      \"chunk\": 20000,\n      \"rigorous\": 20001,\n      \"blaine\": 20002,\n      \"198\": 20003,\n      \"peabody\": 20004,\n      \"slayer\": 20005,\n      \"dismay\": 20006,\n      \"brewers\": 20007,\n      \"nz\": 20008,\n      \"##jer\": 20009,\n      \"det\": 20010,\n      \"##glia\": 20011,\n      \"glover\": 20012,\n      \"postwar\": 20013,\n      \"int\": 20014,\n      \"penetration\": 20015,\n      \"sylvester\": 20016,\n      \"imitation\": 20017,\n      \"vertically\": 20018,\n      \"airlift\": 20019,\n      \"heiress\": 20020,\n      \"knoxville\": 20021,\n      \"viva\": 20022,\n      \"##uin\": 20023,\n      \"390\": 20024,\n      \"macon\": 20025,\n      \"##rim\": 20026,\n      \"##fighter\": 20027,\n      \"##gonal\": 20028,\n      \"janice\": 20029,\n      \"##orescence\": 20030,\n      \"##wari\": 20031,\n      \"marius\": 20032,\n      \"belongings\": 20033,\n      \"leicestershire\": 20034,\n      \"196\": 20035,\n      \"blanco\": 20036,\n      \"inverted\": 20037,\n      \"preseason\": 20038,\n      \"sanity\": 20039,\n      \"sobbing\": 20040,\n      \"##due\": 20041,\n      \"##elt\": 20042,\n      \"##dled\": 20043,\n      \"collingwood\": 20044,\n      \"regeneration\": 20045,\n      \"flickering\": 20046,\n      \"shortest\": 20047,\n      \"##mount\": 20048,\n      \"##osi\": 20049,\n      \"feminism\": 20050,\n      \"##lat\": 20051,\n      \"sherlock\": 20052,\n      \"cabinets\": 20053,\n      \"fumbled\": 20054,\n      \"northbound\": 20055,\n      \"precedent\": 20056,\n      \"snaps\": 20057,\n      \"##mme\": 20058,\n      \"researching\": 20059,\n      \"##akes\": 20060,\n      \"guillaume\": 20061,\n      \"insights\": 20062,\n      \"manipulated\": 20063,\n      \"vapor\": 20064,\n      \"neighbour\": 20065,\n      \"sap\": 20066,\n      \"gangster\": 20067,\n      \"frey\": 20068,\n      \"f1\": 20069,\n      \"stalking\": 20070,\n      \"scarcely\": 20071,\n      \"callie\": 20072,\n      \"barnett\": 20073,\n      \"tendencies\": 20074,\n      \"audi\": 20075,\n      \"doomed\": 20076,\n      \"assessing\": 20077,\n      \"slung\": 20078,\n      \"panchayat\": 20079,\n      \"ambiguous\": 20080,\n      \"bartlett\": 20081,\n      \"##etto\": 20082,\n      \"distributing\": 20083,\n      \"violating\": 20084,\n      \"wolverhampton\": 20085,\n      \"##hetic\": 20086,\n      \"swami\": 20087,\n      \"histoire\": 20088,\n      \"##urus\": 20089,\n      \"liable\": 20090,\n      \"pounder\": 20091,\n      \"groin\": 20092,\n      \"hussain\": 20093,\n      \"larsen\": 20094,\n      \"popping\": 20095,\n      \"surprises\": 20096,\n      \"##atter\": 20097,\n      \"vie\": 20098,\n      \"curt\": 20099,\n      \"##station\": 20100,\n      \"mute\": 20101,\n      \"relocate\": 20102,\n      \"musicals\": 20103,\n      \"authorization\": 20104,\n      \"richter\": 20105,\n      \"##sef\": 20106,\n      \"immortality\": 20107,\n      \"tna\": 20108,\n      \"bombings\": 20109,\n      \"##press\": 20110,\n      \"deteriorated\": 20111,\n      \"yiddish\": 20112,\n      \"##acious\": 20113,\n      \"robbed\": 20114,\n      \"colchester\": 20115,\n      \"cs\": 20116,\n      \"pmid\": 20117,\n      \"ao\": 20118,\n      \"verified\": 20119,\n      \"balancing\": 20120,\n      \"apostle\": 20121,\n      \"swayed\": 20122,\n      \"recognizable\": 20123,\n      \"oxfordshire\": 20124,\n      \"retention\": 20125,\n      \"nottinghamshire\": 20126,\n      \"contender\": 20127,\n      \"judd\": 20128,\n      \"invitational\": 20129,\n      \"shrimp\": 20130,\n      \"uhf\": 20131,\n      \"##icient\": 20132,\n      \"cleaner\": 20133,\n      \"longitudinal\": 20134,\n      \"tanker\": 20135,\n      \"##mur\": 20136,\n      \"acronym\": 20137,\n      \"broker\": 20138,\n      \"koppen\": 20139,\n      \"sundance\": 20140,\n      \"suppliers\": 20141,\n      \"##gil\": 20142,\n      \"4000\": 20143,\n      \"clipped\": 20144,\n      \"fuels\": 20145,\n      \"petite\": 20146,\n      \"##anne\": 20147,\n      \"landslide\": 20148,\n      \"helene\": 20149,\n      \"diversion\": 20150,\n      \"populous\": 20151,\n      \"landowners\": 20152,\n      \"auspices\": 20153,\n      \"melville\": 20154,\n      \"quantitative\": 20155,\n      \"##xes\": 20156,\n      \"ferries\": 20157,\n      \"nicky\": 20158,\n      \"##llus\": 20159,\n      \"doo\": 20160,\n      \"haunting\": 20161,\n      \"roche\": 20162,\n      \"carver\": 20163,\n      \"downed\": 20164,\n      \"unavailable\": 20165,\n      \"##pathy\": 20166,\n      \"approximation\": 20167,\n      \"hiroshima\": 20168,\n      \"##hue\": 20169,\n      \"garfield\": 20170,\n      \"valle\": 20171,\n      \"comparatively\": 20172,\n      \"keyboardist\": 20173,\n      \"traveler\": 20174,\n      \"##eit\": 20175,\n      \"congestion\": 20176,\n      \"calculating\": 20177,\n      \"subsidiaries\": 20178,\n      \"##bate\": 20179,\n      \"serb\": 20180,\n      \"modernization\": 20181,\n      \"fairies\": 20182,\n      \"deepened\": 20183,\n      \"ville\": 20184,\n      \"averages\": 20185,\n      \"##lore\": 20186,\n      \"inflammatory\": 20187,\n      \"tonga\": 20188,\n      \"##itch\": 20189,\n      \"co₂\": 20190,\n      \"squads\": 20191,\n      \"##hea\": 20192,\n      \"gigantic\": 20193,\n      \"serum\": 20194,\n      \"enjoyment\": 20195,\n      \"retailer\": 20196,\n      \"verona\": 20197,\n      \"35th\": 20198,\n      \"cis\": 20199,\n      \"##phobic\": 20200,\n      \"magna\": 20201,\n      \"technicians\": 20202,\n      \"##vati\": 20203,\n      \"arithmetic\": 20204,\n      \"##sport\": 20205,\n      \"levin\": 20206,\n      \"##dation\": 20207,\n      \"amtrak\": 20208,\n      \"chow\": 20209,\n      \"sienna\": 20210,\n      \"##eyer\": 20211,\n      \"backstage\": 20212,\n      \"entrepreneurship\": 20213,\n      \"##otic\": 20214,\n      \"learnt\": 20215,\n      \"tao\": 20216,\n      \"##udy\": 20217,\n      \"worcestershire\": 20218,\n      \"formulation\": 20219,\n      \"baggage\": 20220,\n      \"hesitant\": 20221,\n      \"bali\": 20222,\n      \"sabotage\": 20223,\n      \"##kari\": 20224,\n      \"barren\": 20225,\n      \"enhancing\": 20226,\n      \"murmur\": 20227,\n      \"pl\": 20228,\n      \"freshly\": 20229,\n      \"putnam\": 20230,\n      \"syntax\": 20231,\n      \"aces\": 20232,\n      \"medicines\": 20233,\n      \"resentment\": 20234,\n      \"bandwidth\": 20235,\n      \"##sier\": 20236,\n      \"grins\": 20237,\n      \"chili\": 20238,\n      \"guido\": 20239,\n      \"##sei\": 20240,\n      \"framing\": 20241,\n      \"implying\": 20242,\n      \"gareth\": 20243,\n      \"lissa\": 20244,\n      \"genevieve\": 20245,\n      \"pertaining\": 20246,\n      \"admissions\": 20247,\n      \"geo\": 20248,\n      \"thorpe\": 20249,\n      \"proliferation\": 20250,\n      \"sato\": 20251,\n      \"bela\": 20252,\n      \"analyzing\": 20253,\n      \"parting\": 20254,\n      \"##gor\": 20255,\n      \"awakened\": 20256,\n      \"##isman\": 20257,\n      \"huddled\": 20258,\n      \"secrecy\": 20259,\n      \"##kling\": 20260,\n      \"hush\": 20261,\n      \"gentry\": 20262,\n      \"540\": 20263,\n      \"dungeons\": 20264,\n      \"##ego\": 20265,\n      \"coasts\": 20266,\n      \"##utz\": 20267,\n      \"sacrificed\": 20268,\n      \"##chule\": 20269,\n      \"landowner\": 20270,\n      \"mutually\": 20271,\n      \"prevalence\": 20272,\n      \"programmer\": 20273,\n      \"adolescent\": 20274,\n      \"disrupted\": 20275,\n      \"seaside\": 20276,\n      \"gee\": 20277,\n      \"trusts\": 20278,\n      \"vamp\": 20279,\n      \"georgie\": 20280,\n      \"##nesian\": 20281,\n      \"##iol\": 20282,\n      \"schedules\": 20283,\n      \"sindh\": 20284,\n      \"##market\": 20285,\n      \"etched\": 20286,\n      \"hm\": 20287,\n      \"sparse\": 20288,\n      \"bey\": 20289,\n      \"beaux\": 20290,\n      \"scratching\": 20291,\n      \"gliding\": 20292,\n      \"unidentified\": 20293,\n      \"216\": 20294,\n      \"collaborating\": 20295,\n      \"gems\": 20296,\n      \"jesuits\": 20297,\n      \"oro\": 20298,\n      \"accumulation\": 20299,\n      \"shaping\": 20300,\n      \"mbe\": 20301,\n      \"anal\": 20302,\n      \"##xin\": 20303,\n      \"231\": 20304,\n      \"enthusiasts\": 20305,\n      \"newscast\": 20306,\n      \"##egan\": 20307,\n      \"janata\": 20308,\n      \"dewey\": 20309,\n      \"parkinson\": 20310,\n      \"179\": 20311,\n      \"ankara\": 20312,\n      \"biennial\": 20313,\n      \"towering\": 20314,\n      \"dd\": 20315,\n      \"inconsistent\": 20316,\n      \"950\": 20317,\n      \"##chet\": 20318,\n      \"thriving\": 20319,\n      \"terminate\": 20320,\n      \"cabins\": 20321,\n      \"furiously\": 20322,\n      \"eats\": 20323,\n      \"advocating\": 20324,\n      \"donkey\": 20325,\n      \"marley\": 20326,\n      \"muster\": 20327,\n      \"phyllis\": 20328,\n      \"leiden\": 20329,\n      \"##user\": 20330,\n      \"grassland\": 20331,\n      \"glittering\": 20332,\n      \"iucn\": 20333,\n      \"loneliness\": 20334,\n      \"217\": 20335,\n      \"memorandum\": 20336,\n      \"armenians\": 20337,\n      \"##ddle\": 20338,\n      \"popularized\": 20339,\n      \"rhodesia\": 20340,\n      \"60s\": 20341,\n      \"lame\": 20342,\n      \"##illon\": 20343,\n      \"sans\": 20344,\n      \"bikini\": 20345,\n      \"header\": 20346,\n      \"orbits\": 20347,\n      \"##xx\": 20348,\n      \"##finger\": 20349,\n      \"##ulator\": 20350,\n      \"sharif\": 20351,\n      \"spines\": 20352,\n      \"biotechnology\": 20353,\n      \"strolled\": 20354,\n      \"naughty\": 20355,\n      \"yates\": 20356,\n      \"##wire\": 20357,\n      \"fremantle\": 20358,\n      \"milo\": 20359,\n      \"##mour\": 20360,\n      \"abducted\": 20361,\n      \"removes\": 20362,\n      \"##atin\": 20363,\n      \"humming\": 20364,\n      \"wonderland\": 20365,\n      \"##chrome\": 20366,\n      \"##ester\": 20367,\n      \"hume\": 20368,\n      \"pivotal\": 20369,\n      \"##rates\": 20370,\n      \"armand\": 20371,\n      \"grams\": 20372,\n      \"believers\": 20373,\n      \"elector\": 20374,\n      \"rte\": 20375,\n      \"apron\": 20376,\n      \"bis\": 20377,\n      \"scraped\": 20378,\n      \"##yria\": 20379,\n      \"endorsement\": 20380,\n      \"initials\": 20381,\n      \"##llation\": 20382,\n      \"eps\": 20383,\n      \"dotted\": 20384,\n      \"hints\": 20385,\n      \"buzzing\": 20386,\n      \"emigration\": 20387,\n      \"nearer\": 20388,\n      \"##tom\": 20389,\n      \"indicators\": 20390,\n      \"##ulu\": 20391,\n      \"coarse\": 20392,\n      \"neutron\": 20393,\n      \"protectorate\": 20394,\n      \"##uze\": 20395,\n      \"directional\": 20396,\n      \"exploits\": 20397,\n      \"pains\": 20398,\n      \"loire\": 20399,\n      \"1830s\": 20400,\n      \"proponents\": 20401,\n      \"guggenheim\": 20402,\n      \"rabbits\": 20403,\n      \"ritchie\": 20404,\n      \"305\": 20405,\n      \"hectare\": 20406,\n      \"inputs\": 20407,\n      \"hutton\": 20408,\n      \"##raz\": 20409,\n      \"verify\": 20410,\n      \"##ako\": 20411,\n      \"boilers\": 20412,\n      \"longitude\": 20413,\n      \"##lev\": 20414,\n      \"skeletal\": 20415,\n      \"yer\": 20416,\n      \"emilia\": 20417,\n      \"citrus\": 20418,\n      \"compromised\": 20419,\n      \"##gau\": 20420,\n      \"pokemon\": 20421,\n      \"prescription\": 20422,\n      \"paragraph\": 20423,\n      \"eduard\": 20424,\n      \"cadillac\": 20425,\n      \"attire\": 20426,\n      \"categorized\": 20427,\n      \"kenyan\": 20428,\n      \"weddings\": 20429,\n      \"charley\": 20430,\n      \"##bourg\": 20431,\n      \"entertain\": 20432,\n      \"monmouth\": 20433,\n      \"##lles\": 20434,\n      \"nutrients\": 20435,\n      \"davey\": 20436,\n      \"mesh\": 20437,\n      \"incentive\": 20438,\n      \"practised\": 20439,\n      \"ecosystems\": 20440,\n      \"kemp\": 20441,\n      \"subdued\": 20442,\n      \"overheard\": 20443,\n      \"##rya\": 20444,\n      \"bodily\": 20445,\n      \"maxim\": 20446,\n      \"##nius\": 20447,\n      \"apprenticeship\": 20448,\n      \"ursula\": 20449,\n      \"##fight\": 20450,\n      \"lodged\": 20451,\n      \"rug\": 20452,\n      \"silesian\": 20453,\n      \"unconstitutional\": 20454,\n      \"patel\": 20455,\n      \"inspected\": 20456,\n      \"coyote\": 20457,\n      \"unbeaten\": 20458,\n      \"##hak\": 20459,\n      \"34th\": 20460,\n      \"disruption\": 20461,\n      \"convict\": 20462,\n      \"parcel\": 20463,\n      \"##cl\": 20464,\n      \"##nham\": 20465,\n      \"collier\": 20466,\n      \"implicated\": 20467,\n      \"mallory\": 20468,\n      \"##iac\": 20469,\n      \"##lab\": 20470,\n      \"susannah\": 20471,\n      \"winkler\": 20472,\n      \"##rber\": 20473,\n      \"shia\": 20474,\n      \"phelps\": 20475,\n      \"sediments\": 20476,\n      \"graphical\": 20477,\n      \"robotic\": 20478,\n      \"##sner\": 20479,\n      \"adulthood\": 20480,\n      \"mart\": 20481,\n      \"smoked\": 20482,\n      \"##isto\": 20483,\n      \"kathryn\": 20484,\n      \"clarified\": 20485,\n      \"##aran\": 20486,\n      \"divides\": 20487,\n      \"convictions\": 20488,\n      \"oppression\": 20489,\n      \"pausing\": 20490,\n      \"burying\": 20491,\n      \"##mt\": 20492,\n      \"federico\": 20493,\n      \"mathias\": 20494,\n      \"eileen\": 20495,\n      \"##tana\": 20496,\n      \"kite\": 20497,\n      \"hunched\": 20498,\n      \"##acies\": 20499,\n      \"189\": 20500,\n      \"##atz\": 20501,\n      \"disadvantage\": 20502,\n      \"liza\": 20503,\n      \"kinetic\": 20504,\n      \"greedy\": 20505,\n      \"paradox\": 20506,\n      \"yokohama\": 20507,\n      \"dowager\": 20508,\n      \"trunks\": 20509,\n      \"ventured\": 20510,\n      \"##gement\": 20511,\n      \"gupta\": 20512,\n      \"vilnius\": 20513,\n      \"olaf\": 20514,\n      \"##thest\": 20515,\n      \"crimean\": 20516,\n      \"hopper\": 20517,\n      \"##ej\": 20518,\n      \"progressively\": 20519,\n      \"arturo\": 20520,\n      \"mouthed\": 20521,\n      \"arrondissement\": 20522,\n      \"##fusion\": 20523,\n      \"rubin\": 20524,\n      \"simulcast\": 20525,\n      \"oceania\": 20526,\n      \"##orum\": 20527,\n      \"##stra\": 20528,\n      \"##rred\": 20529,\n      \"busiest\": 20530,\n      \"intensely\": 20531,\n      \"navigator\": 20532,\n      \"cary\": 20533,\n      \"##vine\": 20534,\n      \"##hini\": 20535,\n      \"##bies\": 20536,\n      \"fife\": 20537,\n      \"rowe\": 20538,\n      \"rowland\": 20539,\n      \"posing\": 20540,\n      \"insurgents\": 20541,\n      \"shafts\": 20542,\n      \"lawsuits\": 20543,\n      \"activate\": 20544,\n      \"conor\": 20545,\n      \"inward\": 20546,\n      \"culturally\": 20547,\n      \"garlic\": 20548,\n      \"265\": 20549,\n      \"##eering\": 20550,\n      \"eclectic\": 20551,\n      \"##hui\": 20552,\n      \"##kee\": 20553,\n      \"##nl\": 20554,\n      \"furrowed\": 20555,\n      \"vargas\": 20556,\n      \"meteorological\": 20557,\n      \"rendezvous\": 20558,\n      \"##aus\": 20559,\n      \"culinary\": 20560,\n      \"commencement\": 20561,\n      \"##dition\": 20562,\n      \"quota\": 20563,\n      \"##notes\": 20564,\n      \"mommy\": 20565,\n      \"salaries\": 20566,\n      \"overlapping\": 20567,\n      \"mule\": 20568,\n      \"##iology\": 20569,\n      \"##mology\": 20570,\n      \"sums\": 20571,\n      \"wentworth\": 20572,\n      \"##isk\": 20573,\n      \"##zione\": 20574,\n      \"mainline\": 20575,\n      \"subgroup\": 20576,\n      \"##illy\": 20577,\n      \"hack\": 20578,\n      \"plaintiff\": 20579,\n      \"verdi\": 20580,\n      \"bulb\": 20581,\n      \"differentiation\": 20582,\n      \"engagements\": 20583,\n      \"multinational\": 20584,\n      \"supplemented\": 20585,\n      \"bertrand\": 20586,\n      \"caller\": 20587,\n      \"regis\": 20588,\n      \"##naire\": 20589,\n      \"##sler\": 20590,\n      \"##arts\": 20591,\n      \"##imated\": 20592,\n      \"blossom\": 20593,\n      \"propagation\": 20594,\n      \"kilometer\": 20595,\n      \"viaduct\": 20596,\n      \"vineyards\": 20597,\n      \"##uate\": 20598,\n      \"beckett\": 20599,\n      \"optimization\": 20600,\n      \"golfer\": 20601,\n      \"songwriters\": 20602,\n      \"seminal\": 20603,\n      \"semitic\": 20604,\n      \"thud\": 20605,\n      \"volatile\": 20606,\n      \"evolving\": 20607,\n      \"ridley\": 20608,\n      \"##wley\": 20609,\n      \"trivial\": 20610,\n      \"distributions\": 20611,\n      \"scandinavia\": 20612,\n      \"jiang\": 20613,\n      \"##ject\": 20614,\n      \"wrestled\": 20615,\n      \"insistence\": 20616,\n      \"##dio\": 20617,\n      \"emphasizes\": 20618,\n      \"napkin\": 20619,\n      \"##ods\": 20620,\n      \"adjunct\": 20621,\n      \"rhyme\": 20622,\n      \"##ricted\": 20623,\n      \"##eti\": 20624,\n      \"hopeless\": 20625,\n      \"surrounds\": 20626,\n      \"tremble\": 20627,\n      \"32nd\": 20628,\n      \"smoky\": 20629,\n      \"##ntly\": 20630,\n      \"oils\": 20631,\n      \"medicinal\": 20632,\n      \"padded\": 20633,\n      \"steer\": 20634,\n      \"wilkes\": 20635,\n      \"219\": 20636,\n      \"255\": 20637,\n      \"concessions\": 20638,\n      \"hue\": 20639,\n      \"uniquely\": 20640,\n      \"blinded\": 20641,\n      \"landon\": 20642,\n      \"yahoo\": 20643,\n      \"##lane\": 20644,\n      \"hendrix\": 20645,\n      \"commemorating\": 20646,\n      \"dex\": 20647,\n      \"specify\": 20648,\n      \"chicks\": 20649,\n      \"##ggio\": 20650,\n      \"intercity\": 20651,\n      \"1400\": 20652,\n      \"morley\": 20653,\n      \"##torm\": 20654,\n      \"highlighting\": 20655,\n      \"##oting\": 20656,\n      \"pang\": 20657,\n      \"oblique\": 20658,\n      \"stalled\": 20659,\n      \"##liner\": 20660,\n      \"flirting\": 20661,\n      \"newborn\": 20662,\n      \"1769\": 20663,\n      \"bishopric\": 20664,\n      \"shaved\": 20665,\n      \"232\": 20666,\n      \"currie\": 20667,\n      \"##ush\": 20668,\n      \"dharma\": 20669,\n      \"spartan\": 20670,\n      \"##ooped\": 20671,\n      \"favorites\": 20672,\n      \"smug\": 20673,\n      \"novella\": 20674,\n      \"sirens\": 20675,\n      \"abusive\": 20676,\n      \"creations\": 20677,\n      \"espana\": 20678,\n      \"##lage\": 20679,\n      \"paradigm\": 20680,\n      \"semiconductor\": 20681,\n      \"sheen\": 20682,\n      \"##rdo\": 20683,\n      \"##yen\": 20684,\n      \"##zak\": 20685,\n      \"nrl\": 20686,\n      \"renew\": 20687,\n      \"##pose\": 20688,\n      \"##tur\": 20689,\n      \"adjutant\": 20690,\n      \"marches\": 20691,\n      \"norma\": 20692,\n      \"##enity\": 20693,\n      \"ineffective\": 20694,\n      \"weimar\": 20695,\n      \"grunt\": 20696,\n      \"##gat\": 20697,\n      \"lordship\": 20698,\n      \"plotting\": 20699,\n      \"expenditure\": 20700,\n      \"infringement\": 20701,\n      \"lbs\": 20702,\n      \"refrain\": 20703,\n      \"av\": 20704,\n      \"mimi\": 20705,\n      \"mistakenly\": 20706,\n      \"postmaster\": 20707,\n      \"1771\": 20708,\n      \"##bara\": 20709,\n      \"ras\": 20710,\n      \"motorsports\": 20711,\n      \"tito\": 20712,\n      \"199\": 20713,\n      \"subjective\": 20714,\n      \"##zza\": 20715,\n      \"bully\": 20716,\n      \"stew\": 20717,\n      \"##kaya\": 20718,\n      \"prescott\": 20719,\n      \"1a\": 20720,\n      \"##raphic\": 20721,\n      \"##zam\": 20722,\n      \"bids\": 20723,\n      \"styling\": 20724,\n      \"paranormal\": 20725,\n      \"reeve\": 20726,\n      \"sneaking\": 20727,\n      \"exploding\": 20728,\n      \"katz\": 20729,\n      \"akbar\": 20730,\n      \"migrant\": 20731,\n      \"syllables\": 20732,\n      \"indefinitely\": 20733,\n      \"##ogical\": 20734,\n      \"destroys\": 20735,\n      \"replaces\": 20736,\n      \"applause\": 20737,\n      \"##phine\": 20738,\n      \"pest\": 20739,\n      \"##fide\": 20740,\n      \"218\": 20741,\n      \"articulated\": 20742,\n      \"bertie\": 20743,\n      \"##thing\": 20744,\n      \"##cars\": 20745,\n      \"##ptic\": 20746,\n      \"courtroom\": 20747,\n      \"crowley\": 20748,\n      \"aesthetics\": 20749,\n      \"cummings\": 20750,\n      \"tehsil\": 20751,\n      \"hormones\": 20752,\n      \"titanic\": 20753,\n      \"dangerously\": 20754,\n      \"##ibe\": 20755,\n      \"stadion\": 20756,\n      \"jaenelle\": 20757,\n      \"auguste\": 20758,\n      \"ciudad\": 20759,\n      \"##chu\": 20760,\n      \"mysore\": 20761,\n      \"partisans\": 20762,\n      \"##sio\": 20763,\n      \"lucan\": 20764,\n      \"philipp\": 20765,\n      \"##aly\": 20766,\n      \"debating\": 20767,\n      \"henley\": 20768,\n      \"interiors\": 20769,\n      \"##rano\": 20770,\n      \"##tious\": 20771,\n      \"homecoming\": 20772,\n      \"beyonce\": 20773,\n      \"usher\": 20774,\n      \"henrietta\": 20775,\n      \"prepares\": 20776,\n      \"weeds\": 20777,\n      \"##oman\": 20778,\n      \"ely\": 20779,\n      \"plucked\": 20780,\n      \"##pire\": 20781,\n      \"##dable\": 20782,\n      \"luxurious\": 20783,\n      \"##aq\": 20784,\n      \"artifact\": 20785,\n      \"password\": 20786,\n      \"pasture\": 20787,\n      \"juno\": 20788,\n      \"maddy\": 20789,\n      \"minsk\": 20790,\n      \"##dder\": 20791,\n      \"##ologies\": 20792,\n      \"##rone\": 20793,\n      \"assessments\": 20794,\n      \"martian\": 20795,\n      \"royalist\": 20796,\n      \"1765\": 20797,\n      \"examines\": 20798,\n      \"##mani\": 20799,\n      \"##rge\": 20800,\n      \"nino\": 20801,\n      \"223\": 20802,\n      \"parry\": 20803,\n      \"scooped\": 20804,\n      \"relativity\": 20805,\n      \"##eli\": 20806,\n      \"##uting\": 20807,\n      \"##cao\": 20808,\n      \"congregational\": 20809,\n      \"noisy\": 20810,\n      \"traverse\": 20811,\n      \"##agawa\": 20812,\n      \"strikeouts\": 20813,\n      \"nickelodeon\": 20814,\n      \"obituary\": 20815,\n      \"transylvania\": 20816,\n      \"binds\": 20817,\n      \"depictions\": 20818,\n      \"polk\": 20819,\n      \"trolley\": 20820,\n      \"##yed\": 20821,\n      \"##lard\": 20822,\n      \"breeders\": 20823,\n      \"##under\": 20824,\n      \"dryly\": 20825,\n      \"hokkaido\": 20826,\n      \"1762\": 20827,\n      \"strengths\": 20828,\n      \"stacks\": 20829,\n      \"bonaparte\": 20830,\n      \"connectivity\": 20831,\n      \"neared\": 20832,\n      \"prostitutes\": 20833,\n      \"stamped\": 20834,\n      \"anaheim\": 20835,\n      \"gutierrez\": 20836,\n      \"sinai\": 20837,\n      \"##zzling\": 20838,\n      \"bram\": 20839,\n      \"fresno\": 20840,\n      \"madhya\": 20841,\n      \"##86\": 20842,\n      \"proton\": 20843,\n      \"##lena\": 20844,\n      \"##llum\": 20845,\n      \"##phon\": 20846,\n      \"reelected\": 20847,\n      \"wanda\": 20848,\n      \"##anus\": 20849,\n      \"##lb\": 20850,\n      \"ample\": 20851,\n      \"distinguishing\": 20852,\n      \"##yler\": 20853,\n      \"grasping\": 20854,\n      \"sermons\": 20855,\n      \"tomato\": 20856,\n      \"bland\": 20857,\n      \"stimulation\": 20858,\n      \"avenues\": 20859,\n      \"##eux\": 20860,\n      \"spreads\": 20861,\n      \"scarlett\": 20862,\n      \"fern\": 20863,\n      \"pentagon\": 20864,\n      \"assert\": 20865,\n      \"baird\": 20866,\n      \"chesapeake\": 20867,\n      \"ir\": 20868,\n      \"calmed\": 20869,\n      \"distortion\": 20870,\n      \"fatalities\": 20871,\n      \"##olis\": 20872,\n      \"correctional\": 20873,\n      \"pricing\": 20874,\n      \"##astic\": 20875,\n      \"##gina\": 20876,\n      \"prom\": 20877,\n      \"dammit\": 20878,\n      \"ying\": 20879,\n      \"collaborate\": 20880,\n      \"##chia\": 20881,\n      \"welterweight\": 20882,\n      \"33rd\": 20883,\n      \"pointer\": 20884,\n      \"substitution\": 20885,\n      \"bonded\": 20886,\n      \"umpire\": 20887,\n      \"communicating\": 20888,\n      \"multitude\": 20889,\n      \"paddle\": 20890,\n      \"##obe\": 20891,\n      \"federally\": 20892,\n      \"intimacy\": 20893,\n      \"##insky\": 20894,\n      \"betray\": 20895,\n      \"ssr\": 20896,\n      \"##lett\": 20897,\n      \"##lean\": 20898,\n      \"##lves\": 20899,\n      \"##therapy\": 20900,\n      \"airbus\": 20901,\n      \"##tery\": 20902,\n      \"functioned\": 20903,\n      \"ud\": 20904,\n      \"bearer\": 20905,\n      \"biomedical\": 20906,\n      \"netflix\": 20907,\n      \"##hire\": 20908,\n      \"##nca\": 20909,\n      \"condom\": 20910,\n      \"brink\": 20911,\n      \"ik\": 20912,\n      \"##nical\": 20913,\n      \"macy\": 20914,\n      \"##bet\": 20915,\n      \"flap\": 20916,\n      \"gma\": 20917,\n      \"experimented\": 20918,\n      \"jelly\": 20919,\n      \"lavender\": 20920,\n      \"##icles\": 20921,\n      \"##ulia\": 20922,\n      \"munro\": 20923,\n      \"##mian\": 20924,\n      \"##tial\": 20925,\n      \"rye\": 20926,\n      \"##rle\": 20927,\n      \"60th\": 20928,\n      \"gigs\": 20929,\n      \"hottest\": 20930,\n      \"rotated\": 20931,\n      \"predictions\": 20932,\n      \"fuji\": 20933,\n      \"bu\": 20934,\n      \"##erence\": 20935,\n      \"##omi\": 20936,\n      \"barangay\": 20937,\n      \"##fulness\": 20938,\n      \"##sas\": 20939,\n      \"clocks\": 20940,\n      \"##rwood\": 20941,\n      \"##liness\": 20942,\n      \"cereal\": 20943,\n      \"roe\": 20944,\n      \"wight\": 20945,\n      \"decker\": 20946,\n      \"uttered\": 20947,\n      \"babu\": 20948,\n      \"onion\": 20949,\n      \"xml\": 20950,\n      \"forcibly\": 20951,\n      \"##df\": 20952,\n      \"petra\": 20953,\n      \"sarcasm\": 20954,\n      \"hartley\": 20955,\n      \"peeled\": 20956,\n      \"storytelling\": 20957,\n      \"##42\": 20958,\n      \"##xley\": 20959,\n      \"##ysis\": 20960,\n      \"##ffa\": 20961,\n      \"fibre\": 20962,\n      \"kiel\": 20963,\n      \"auditor\": 20964,\n      \"fig\": 20965,\n      \"harald\": 20966,\n      \"greenville\": 20967,\n      \"##berries\": 20968,\n      \"geographically\": 20969,\n      \"nell\": 20970,\n      \"quartz\": 20971,\n      \"##athic\": 20972,\n      \"cemeteries\": 20973,\n      \"##lr\": 20974,\n      \"crossings\": 20975,\n      \"nah\": 20976,\n      \"holloway\": 20977,\n      \"reptiles\": 20978,\n      \"chun\": 20979,\n      \"sichuan\": 20980,\n      \"snowy\": 20981,\n      \"660\": 20982,\n      \"corrections\": 20983,\n      \"##ivo\": 20984,\n      \"zheng\": 20985,\n      \"ambassadors\": 20986,\n      \"blacksmith\": 20987,\n      \"fielded\": 20988,\n      \"fluids\": 20989,\n      \"hardcover\": 20990,\n      \"turnover\": 20991,\n      \"medications\": 20992,\n      \"melvin\": 20993,\n      \"academies\": 20994,\n      \"##erton\": 20995,\n      \"ro\": 20996,\n      \"roach\": 20997,\n      \"absorbing\": 20998,\n      \"spaniards\": 20999,\n      \"colton\": 21000,\n      \"##founded\": 21001,\n      \"outsider\": 21002,\n      \"espionage\": 21003,\n      \"kelsey\": 21004,\n      \"245\": 21005,\n      \"edible\": 21006,\n      \"##ulf\": 21007,\n      \"dora\": 21008,\n      \"establishes\": 21009,\n      \"##sham\": 21010,\n      \"##tries\": 21011,\n      \"contracting\": 21012,\n      \"##tania\": 21013,\n      \"cinematic\": 21014,\n      \"costello\": 21015,\n      \"nesting\": 21016,\n      \"##uron\": 21017,\n      \"connolly\": 21018,\n      \"duff\": 21019,\n      \"##nology\": 21020,\n      \"mma\": 21021,\n      \"##mata\": 21022,\n      \"fergus\": 21023,\n      \"sexes\": 21024,\n      \"gi\": 21025,\n      \"optics\": 21026,\n      \"spectator\": 21027,\n      \"woodstock\": 21028,\n      \"banning\": 21029,\n      \"##hee\": 21030,\n      \"##fle\": 21031,\n      \"differentiate\": 21032,\n      \"outfielder\": 21033,\n      \"refinery\": 21034,\n      \"226\": 21035,\n      \"312\": 21036,\n      \"gerhard\": 21037,\n      \"horde\": 21038,\n      \"lair\": 21039,\n      \"drastically\": 21040,\n      \"##udi\": 21041,\n      \"landfall\": 21042,\n      \"##cheng\": 21043,\n      \"motorsport\": 21044,\n      \"odi\": 21045,\n      \"##achi\": 21046,\n      \"predominant\": 21047,\n      \"quay\": 21048,\n      \"skins\": 21049,\n      \"##ental\": 21050,\n      \"edna\": 21051,\n      \"harshly\": 21052,\n      \"complementary\": 21053,\n      \"murdering\": 21054,\n      \"##aves\": 21055,\n      \"wreckage\": 21056,\n      \"##90\": 21057,\n      \"ono\": 21058,\n      \"outstretched\": 21059,\n      \"lennox\": 21060,\n      \"munitions\": 21061,\n      \"galen\": 21062,\n      \"reconcile\": 21063,\n      \"470\": 21064,\n      \"scalp\": 21065,\n      \"bicycles\": 21066,\n      \"gillespie\": 21067,\n      \"questionable\": 21068,\n      \"rosenberg\": 21069,\n      \"guillermo\": 21070,\n      \"hostel\": 21071,\n      \"jarvis\": 21072,\n      \"kabul\": 21073,\n      \"volvo\": 21074,\n      \"opium\": 21075,\n      \"yd\": 21076,\n      \"##twined\": 21077,\n      \"abuses\": 21078,\n      \"decca\": 21079,\n      \"outpost\": 21080,\n      \"##cino\": 21081,\n      \"sensible\": 21082,\n      \"neutrality\": 21083,\n      \"##64\": 21084,\n      \"ponce\": 21085,\n      \"anchorage\": 21086,\n      \"atkins\": 21087,\n      \"turrets\": 21088,\n      \"inadvertently\": 21089,\n      \"disagree\": 21090,\n      \"libre\": 21091,\n      \"vodka\": 21092,\n      \"reassuring\": 21093,\n      \"weighs\": 21094,\n      \"##yal\": 21095,\n      \"glide\": 21096,\n      \"jumper\": 21097,\n      \"ceilings\": 21098,\n      \"repertory\": 21099,\n      \"outs\": 21100,\n      \"stain\": 21101,\n      \"##bial\": 21102,\n      \"envy\": 21103,\n      \"##ucible\": 21104,\n      \"smashing\": 21105,\n      \"heightened\": 21106,\n      \"policing\": 21107,\n      \"hyun\": 21108,\n      \"mixes\": 21109,\n      \"lai\": 21110,\n      \"prima\": 21111,\n      \"##ples\": 21112,\n      \"celeste\": 21113,\n      \"##bina\": 21114,\n      \"lucrative\": 21115,\n      \"intervened\": 21116,\n      \"kc\": 21117,\n      \"manually\": 21118,\n      \"##rned\": 21119,\n      \"stature\": 21120,\n      \"staffed\": 21121,\n      \"bun\": 21122,\n      \"bastards\": 21123,\n      \"nairobi\": 21124,\n      \"priced\": 21125,\n      \"##auer\": 21126,\n      \"thatcher\": 21127,\n      \"##kia\": 21128,\n      \"tripped\": 21129,\n      \"comune\": 21130,\n      \"##ogan\": 21131,\n      \"##pled\": 21132,\n      \"brasil\": 21133,\n      \"incentives\": 21134,\n      \"emanuel\": 21135,\n      \"hereford\": 21136,\n      \"musica\": 21137,\n      \"##kim\": 21138,\n      \"benedictine\": 21139,\n      \"biennale\": 21140,\n      \"##lani\": 21141,\n      \"eureka\": 21142,\n      \"gardiner\": 21143,\n      \"rb\": 21144,\n      \"knocks\": 21145,\n      \"sha\": 21146,\n      \"##ael\": 21147,\n      \"##elled\": 21148,\n      \"##onate\": 21149,\n      \"efficacy\": 21150,\n      \"ventura\": 21151,\n      \"masonic\": 21152,\n      \"sanford\": 21153,\n      \"maize\": 21154,\n      \"leverage\": 21155,\n      \"##feit\": 21156,\n      \"capacities\": 21157,\n      \"santana\": 21158,\n      \"##aur\": 21159,\n      \"novelty\": 21160,\n      \"vanilla\": 21161,\n      \"##cter\": 21162,\n      \"##tour\": 21163,\n      \"benin\": 21164,\n      \"##oir\": 21165,\n      \"##rain\": 21166,\n      \"neptune\": 21167,\n      \"drafting\": 21168,\n      \"tallinn\": 21169,\n      \"##cable\": 21170,\n      \"humiliation\": 21171,\n      \"##boarding\": 21172,\n      \"schleswig\": 21173,\n      \"fabian\": 21174,\n      \"bernardo\": 21175,\n      \"liturgy\": 21176,\n      \"spectacle\": 21177,\n      \"sweeney\": 21178,\n      \"pont\": 21179,\n      \"routledge\": 21180,\n      \"##tment\": 21181,\n      \"cosmos\": 21182,\n      \"ut\": 21183,\n      \"hilt\": 21184,\n      \"sleek\": 21185,\n      \"universally\": 21186,\n      \"##eville\": 21187,\n      \"##gawa\": 21188,\n      \"typed\": 21189,\n      \"##dry\": 21190,\n      \"favors\": 21191,\n      \"allegheny\": 21192,\n      \"glaciers\": 21193,\n      \"##rly\": 21194,\n      \"recalling\": 21195,\n      \"aziz\": 21196,\n      \"##log\": 21197,\n      \"parasite\": 21198,\n      \"requiem\": 21199,\n      \"auf\": 21200,\n      \"##berto\": 21201,\n      \"##llin\": 21202,\n      \"illumination\": 21203,\n      \"##breaker\": 21204,\n      \"##issa\": 21205,\n      \"festivities\": 21206,\n      \"bows\": 21207,\n      \"govern\": 21208,\n      \"vibe\": 21209,\n      \"vp\": 21210,\n      \"333\": 21211,\n      \"sprawled\": 21212,\n      \"larson\": 21213,\n      \"pilgrim\": 21214,\n      \"bwf\": 21215,\n      \"leaping\": 21216,\n      \"##rts\": 21217,\n      \"##ssel\": 21218,\n      \"alexei\": 21219,\n      \"greyhound\": 21220,\n      \"hoarse\": 21221,\n      \"##dler\": 21222,\n      \"##oration\": 21223,\n      \"seneca\": 21224,\n      \"##cule\": 21225,\n      \"gaping\": 21226,\n      \"##ulously\": 21227,\n      \"##pura\": 21228,\n      \"cinnamon\": 21229,\n      \"##gens\": 21230,\n      \"##rricular\": 21231,\n      \"craven\": 21232,\n      \"fantasies\": 21233,\n      \"houghton\": 21234,\n      \"engined\": 21235,\n      \"reigned\": 21236,\n      \"dictator\": 21237,\n      \"supervising\": 21238,\n      \"##oris\": 21239,\n      \"bogota\": 21240,\n      \"commentaries\": 21241,\n      \"unnatural\": 21242,\n      \"fingernails\": 21243,\n      \"spirituality\": 21244,\n      \"tighten\": 21245,\n      \"##tm\": 21246,\n      \"canadiens\": 21247,\n      \"protesting\": 21248,\n      \"intentional\": 21249,\n      \"cheers\": 21250,\n      \"sparta\": 21251,\n      \"##ytic\": 21252,\n      \"##iere\": 21253,\n      \"##zine\": 21254,\n      \"widen\": 21255,\n      \"belgarath\": 21256,\n      \"controllers\": 21257,\n      \"dodd\": 21258,\n      \"iaaf\": 21259,\n      \"navarre\": 21260,\n      \"##ication\": 21261,\n      \"defect\": 21262,\n      \"squire\": 21263,\n      \"steiner\": 21264,\n      \"whisky\": 21265,\n      \"##mins\": 21266,\n      \"560\": 21267,\n      \"inevitably\": 21268,\n      \"tome\": 21269,\n      \"##gold\": 21270,\n      \"chew\": 21271,\n      \"##uid\": 21272,\n      \"##lid\": 21273,\n      \"elastic\": 21274,\n      \"##aby\": 21275,\n      \"streaked\": 21276,\n      \"alliances\": 21277,\n      \"jailed\": 21278,\n      \"regal\": 21279,\n      \"##ined\": 21280,\n      \"##phy\": 21281,\n      \"czechoslovak\": 21282,\n      \"narration\": 21283,\n      \"absently\": 21284,\n      \"##uld\": 21285,\n      \"bluegrass\": 21286,\n      \"guangdong\": 21287,\n      \"quran\": 21288,\n      \"criticizing\": 21289,\n      \"hose\": 21290,\n      \"hari\": 21291,\n      \"##liest\": 21292,\n      \"##owa\": 21293,\n      \"skier\": 21294,\n      \"streaks\": 21295,\n      \"deploy\": 21296,\n      \"##lom\": 21297,\n      \"raft\": 21298,\n      \"bose\": 21299,\n      \"dialed\": 21300,\n      \"huff\": 21301,\n      \"##eira\": 21302,\n      \"haifa\": 21303,\n      \"simplest\": 21304,\n      \"bursting\": 21305,\n      \"endings\": 21306,\n      \"ib\": 21307,\n      \"sultanate\": 21308,\n      \"##titled\": 21309,\n      \"franks\": 21310,\n      \"whitman\": 21311,\n      \"ensures\": 21312,\n      \"sven\": 21313,\n      \"##ggs\": 21314,\n      \"collaborators\": 21315,\n      \"forster\": 21316,\n      \"organising\": 21317,\n      \"ui\": 21318,\n      \"banished\": 21319,\n      \"napier\": 21320,\n      \"injustice\": 21321,\n      \"teller\": 21322,\n      \"layered\": 21323,\n      \"thump\": 21324,\n      \"##otti\": 21325,\n      \"roc\": 21326,\n      \"battleships\": 21327,\n      \"evidenced\": 21328,\n      \"fugitive\": 21329,\n      \"sadie\": 21330,\n      \"robotics\": 21331,\n      \"##roud\": 21332,\n      \"equatorial\": 21333,\n      \"geologist\": 21334,\n      \"##iza\": 21335,\n      \"yielding\": 21336,\n      \"##bron\": 21337,\n      \"##sr\": 21338,\n      \"internationale\": 21339,\n      \"mecca\": 21340,\n      \"##diment\": 21341,\n      \"sbs\": 21342,\n      \"skyline\": 21343,\n      \"toad\": 21344,\n      \"uploaded\": 21345,\n      \"reflective\": 21346,\n      \"undrafted\": 21347,\n      \"lal\": 21348,\n      \"leafs\": 21349,\n      \"bayern\": 21350,\n      \"##dai\": 21351,\n      \"lakshmi\": 21352,\n      \"shortlisted\": 21353,\n      \"##stick\": 21354,\n      \"##wicz\": 21355,\n      \"camouflage\": 21356,\n      \"donate\": 21357,\n      \"af\": 21358,\n      \"christi\": 21359,\n      \"lau\": 21360,\n      \"##acio\": 21361,\n      \"disclosed\": 21362,\n      \"nemesis\": 21363,\n      \"1761\": 21364,\n      \"assemble\": 21365,\n      \"straining\": 21366,\n      \"northamptonshire\": 21367,\n      \"tal\": 21368,\n      \"##asi\": 21369,\n      \"bernardino\": 21370,\n      \"premature\": 21371,\n      \"heidi\": 21372,\n      \"42nd\": 21373,\n      \"coefficients\": 21374,\n      \"galactic\": 21375,\n      \"reproduce\": 21376,\n      \"buzzed\": 21377,\n      \"sensations\": 21378,\n      \"zionist\": 21379,\n      \"monsieur\": 21380,\n      \"myrtle\": 21381,\n      \"##eme\": 21382,\n      \"archery\": 21383,\n      \"strangled\": 21384,\n      \"musically\": 21385,\n      \"viewpoint\": 21386,\n      \"antiquities\": 21387,\n      \"bei\": 21388,\n      \"trailers\": 21389,\n      \"seahawks\": 21390,\n      \"cured\": 21391,\n      \"pee\": 21392,\n      \"preferring\": 21393,\n      \"tasmanian\": 21394,\n      \"lange\": 21395,\n      \"sul\": 21396,\n      \"##mail\": 21397,\n      \"##working\": 21398,\n      \"colder\": 21399,\n      \"overland\": 21400,\n      \"lucivar\": 21401,\n      \"massey\": 21402,\n      \"gatherings\": 21403,\n      \"haitian\": 21404,\n      \"##smith\": 21405,\n      \"disapproval\": 21406,\n      \"flaws\": 21407,\n      \"##cco\": 21408,\n      \"##enbach\": 21409,\n      \"1766\": 21410,\n      \"npr\": 21411,\n      \"##icular\": 21412,\n      \"boroughs\": 21413,\n      \"creole\": 21414,\n      \"forums\": 21415,\n      \"techno\": 21416,\n      \"1755\": 21417,\n      \"dent\": 21418,\n      \"abdominal\": 21419,\n      \"streetcar\": 21420,\n      \"##eson\": 21421,\n      \"##stream\": 21422,\n      \"procurement\": 21423,\n      \"gemini\": 21424,\n      \"predictable\": 21425,\n      \"##tya\": 21426,\n      \"acheron\": 21427,\n      \"christoph\": 21428,\n      \"feeder\": 21429,\n      \"fronts\": 21430,\n      \"vendor\": 21431,\n      \"bernhard\": 21432,\n      \"jammu\": 21433,\n      \"tumors\": 21434,\n      \"slang\": 21435,\n      \"##uber\": 21436,\n      \"goaltender\": 21437,\n      \"twists\": 21438,\n      \"curving\": 21439,\n      \"manson\": 21440,\n      \"vuelta\": 21441,\n      \"mer\": 21442,\n      \"peanut\": 21443,\n      \"confessions\": 21444,\n      \"pouch\": 21445,\n      \"unpredictable\": 21446,\n      \"allowance\": 21447,\n      \"theodor\": 21448,\n      \"vascular\": 21449,\n      \"##factory\": 21450,\n      \"bala\": 21451,\n      \"authenticity\": 21452,\n      \"metabolic\": 21453,\n      \"coughing\": 21454,\n      \"nanjing\": 21455,\n      \"##cea\": 21456,\n      \"pembroke\": 21457,\n      \"##bard\": 21458,\n      \"splendid\": 21459,\n      \"36th\": 21460,\n      \"ff\": 21461,\n      \"hourly\": 21462,\n      \"##ahu\": 21463,\n      \"elmer\": 21464,\n      \"handel\": 21465,\n      \"##ivate\": 21466,\n      \"awarding\": 21467,\n      \"thrusting\": 21468,\n      \"dl\": 21469,\n      \"experimentation\": 21470,\n      \"##hesion\": 21471,\n      \"##46\": 21472,\n      \"caressed\": 21473,\n      \"entertained\": 21474,\n      \"steak\": 21475,\n      \"##rangle\": 21476,\n      \"biologist\": 21477,\n      \"orphans\": 21478,\n      \"baroness\": 21479,\n      \"oyster\": 21480,\n      \"stepfather\": 21481,\n      \"##dridge\": 21482,\n      \"mirage\": 21483,\n      \"reefs\": 21484,\n      \"speeding\": 21485,\n      \"##31\": 21486,\n      \"barons\": 21487,\n      \"1764\": 21488,\n      \"227\": 21489,\n      \"inhabit\": 21490,\n      \"preached\": 21491,\n      \"repealed\": 21492,\n      \"##tral\": 21493,\n      \"honoring\": 21494,\n      \"boogie\": 21495,\n      \"captives\": 21496,\n      \"administer\": 21497,\n      \"johanna\": 21498,\n      \"##imate\": 21499,\n      \"gel\": 21500,\n      \"suspiciously\": 21501,\n      \"1767\": 21502,\n      \"sobs\": 21503,\n      \"##dington\": 21504,\n      \"backbone\": 21505,\n      \"hayward\": 21506,\n      \"garry\": 21507,\n      \"##folding\": 21508,\n      \"##nesia\": 21509,\n      \"maxi\": 21510,\n      \"##oof\": 21511,\n      \"##ppe\": 21512,\n      \"ellison\": 21513,\n      \"galileo\": 21514,\n      \"##stand\": 21515,\n      \"crimea\": 21516,\n      \"frenzy\": 21517,\n      \"amour\": 21518,\n      \"bumper\": 21519,\n      \"matrices\": 21520,\n      \"natalia\": 21521,\n      \"baking\": 21522,\n      \"garth\": 21523,\n      \"palestinians\": 21524,\n      \"##grove\": 21525,\n      \"smack\": 21526,\n      \"conveyed\": 21527,\n      \"ensembles\": 21528,\n      \"gardening\": 21529,\n      \"##manship\": 21530,\n      \"##rup\": 21531,\n      \"##stituting\": 21532,\n      \"1640\": 21533,\n      \"harvesting\": 21534,\n      \"topography\": 21535,\n      \"jing\": 21536,\n      \"shifters\": 21537,\n      \"dormitory\": 21538,\n      \"##carriage\": 21539,\n      \"##lston\": 21540,\n      \"ist\": 21541,\n      \"skulls\": 21542,\n      \"##stadt\": 21543,\n      \"dolores\": 21544,\n      \"jewellery\": 21545,\n      \"sarawak\": 21546,\n      \"##wai\": 21547,\n      \"##zier\": 21548,\n      \"fences\": 21549,\n      \"christy\": 21550,\n      \"confinement\": 21551,\n      \"tumbling\": 21552,\n      \"credibility\": 21553,\n      \"fir\": 21554,\n      \"stench\": 21555,\n      \"##bria\": 21556,\n      \"##plication\": 21557,\n      \"##nged\": 21558,\n      \"##sam\": 21559,\n      \"virtues\": 21560,\n      \"##belt\": 21561,\n      \"marjorie\": 21562,\n      \"pba\": 21563,\n      \"##eem\": 21564,\n      \"##made\": 21565,\n      \"celebrates\": 21566,\n      \"schooner\": 21567,\n      \"agitated\": 21568,\n      \"barley\": 21569,\n      \"fulfilling\": 21570,\n      \"anthropologist\": 21571,\n      \"##pro\": 21572,\n      \"restrict\": 21573,\n      \"novi\": 21574,\n      \"regulating\": 21575,\n      \"##nent\": 21576,\n      \"padres\": 21577,\n      \"##rani\": 21578,\n      \"##hesive\": 21579,\n      \"loyola\": 21580,\n      \"tabitha\": 21581,\n      \"milky\": 21582,\n      \"olson\": 21583,\n      \"proprietor\": 21584,\n      \"crambidae\": 21585,\n      \"guarantees\": 21586,\n      \"intercollegiate\": 21587,\n      \"ljubljana\": 21588,\n      \"hilda\": 21589,\n      \"##sko\": 21590,\n      \"ignorant\": 21591,\n      \"hooded\": 21592,\n      \"##lts\": 21593,\n      \"sardinia\": 21594,\n      \"##lidae\": 21595,\n      \"##vation\": 21596,\n      \"frontman\": 21597,\n      \"privileged\": 21598,\n      \"witchcraft\": 21599,\n      \"##gp\": 21600,\n      \"jammed\": 21601,\n      \"laude\": 21602,\n      \"poking\": 21603,\n      \"##than\": 21604,\n      \"bracket\": 21605,\n      \"amazement\": 21606,\n      \"yunnan\": 21607,\n      \"##erus\": 21608,\n      \"maharaja\": 21609,\n      \"linnaeus\": 21610,\n      \"264\": 21611,\n      \"commissioning\": 21612,\n      \"milano\": 21613,\n      \"peacefully\": 21614,\n      \"##logies\": 21615,\n      \"akira\": 21616,\n      \"rani\": 21617,\n      \"regulator\": 21618,\n      \"##36\": 21619,\n      \"grasses\": 21620,\n      \"##rance\": 21621,\n      \"luzon\": 21622,\n      \"crows\": 21623,\n      \"compiler\": 21624,\n      \"gretchen\": 21625,\n      \"seaman\": 21626,\n      \"edouard\": 21627,\n      \"tab\": 21628,\n      \"buccaneers\": 21629,\n      \"ellington\": 21630,\n      \"hamlets\": 21631,\n      \"whig\": 21632,\n      \"socialists\": 21633,\n      \"##anto\": 21634,\n      \"directorial\": 21635,\n      \"easton\": 21636,\n      \"mythological\": 21637,\n      \"##kr\": 21638,\n      \"##vary\": 21639,\n      \"rhineland\": 21640,\n      \"semantic\": 21641,\n      \"taut\": 21642,\n      \"dune\": 21643,\n      \"inventions\": 21644,\n      \"succeeds\": 21645,\n      \"##iter\": 21646,\n      \"replication\": 21647,\n      \"branched\": 21648,\n      \"##pired\": 21649,\n      \"jul\": 21650,\n      \"prosecuted\": 21651,\n      \"kangaroo\": 21652,\n      \"penetrated\": 21653,\n      \"##avian\": 21654,\n      \"middlesbrough\": 21655,\n      \"doses\": 21656,\n      \"bleak\": 21657,\n      \"madam\": 21658,\n      \"predatory\": 21659,\n      \"relentless\": 21660,\n      \"##vili\": 21661,\n      \"reluctance\": 21662,\n      \"##vir\": 21663,\n      \"hailey\": 21664,\n      \"crore\": 21665,\n      \"silvery\": 21666,\n      \"1759\": 21667,\n      \"monstrous\": 21668,\n      \"swimmers\": 21669,\n      \"transmissions\": 21670,\n      \"hawthorn\": 21671,\n      \"informing\": 21672,\n      \"##eral\": 21673,\n      \"toilets\": 21674,\n      \"caracas\": 21675,\n      \"crouch\": 21676,\n      \"kb\": 21677,\n      \"##sett\": 21678,\n      \"295\": 21679,\n      \"cartel\": 21680,\n      \"hadley\": 21681,\n      \"##aling\": 21682,\n      \"alexia\": 21683,\n      \"yvonne\": 21684,\n      \"##biology\": 21685,\n      \"cinderella\": 21686,\n      \"eton\": 21687,\n      \"superb\": 21688,\n      \"blizzard\": 21689,\n      \"stabbing\": 21690,\n      \"industrialist\": 21691,\n      \"maximus\": 21692,\n      \"##gm\": 21693,\n      \"##orus\": 21694,\n      \"groves\": 21695,\n      \"maud\": 21696,\n      \"clade\": 21697,\n      \"oversized\": 21698,\n      \"comedic\": 21699,\n      \"##bella\": 21700,\n      \"rosen\": 21701,\n      \"nomadic\": 21702,\n      \"fulham\": 21703,\n      \"montane\": 21704,\n      \"beverages\": 21705,\n      \"galaxies\": 21706,\n      \"redundant\": 21707,\n      \"swarm\": 21708,\n      \"##rot\": 21709,\n      \"##folia\": 21710,\n      \"##llis\": 21711,\n      \"buckinghamshire\": 21712,\n      \"fen\": 21713,\n      \"bearings\": 21714,\n      \"bahadur\": 21715,\n      \"##rom\": 21716,\n      \"gilles\": 21717,\n      \"phased\": 21718,\n      \"dynamite\": 21719,\n      \"faber\": 21720,\n      \"benoit\": 21721,\n      \"vip\": 21722,\n      \"##ount\": 21723,\n      \"##wd\": 21724,\n      \"booking\": 21725,\n      \"fractured\": 21726,\n      \"tailored\": 21727,\n      \"anya\": 21728,\n      \"spices\": 21729,\n      \"westwood\": 21730,\n      \"cairns\": 21731,\n      \"auditions\": 21732,\n      \"inflammation\": 21733,\n      \"steamed\": 21734,\n      \"##rocity\": 21735,\n      \"##acion\": 21736,\n      \"##urne\": 21737,\n      \"skyla\": 21738,\n      \"thereof\": 21739,\n      \"watford\": 21740,\n      \"torment\": 21741,\n      \"archdeacon\": 21742,\n      \"transforms\": 21743,\n      \"lulu\": 21744,\n      \"demeanor\": 21745,\n      \"fucked\": 21746,\n      \"serge\": 21747,\n      \"##sor\": 21748,\n      \"mckenna\": 21749,\n      \"minas\": 21750,\n      \"entertainer\": 21751,\n      \"##icide\": 21752,\n      \"caress\": 21753,\n      \"originate\": 21754,\n      \"residue\": 21755,\n      \"##sty\": 21756,\n      \"1740\": 21757,\n      \"##ilised\": 21758,\n      \"##org\": 21759,\n      \"beech\": 21760,\n      \"##wana\": 21761,\n      \"subsidies\": 21762,\n      \"##ghton\": 21763,\n      \"emptied\": 21764,\n      \"gladstone\": 21765,\n      \"ru\": 21766,\n      \"firefighters\": 21767,\n      \"voodoo\": 21768,\n      \"##rcle\": 21769,\n      \"het\": 21770,\n      \"nightingale\": 21771,\n      \"tamara\": 21772,\n      \"edmond\": 21773,\n      \"ingredient\": 21774,\n      \"weaknesses\": 21775,\n      \"silhouette\": 21776,\n      \"285\": 21777,\n      \"compatibility\": 21778,\n      \"withdrawing\": 21779,\n      \"hampson\": 21780,\n      \"##mona\": 21781,\n      \"anguish\": 21782,\n      \"giggling\": 21783,\n      \"##mber\": 21784,\n      \"bookstore\": 21785,\n      \"##jiang\": 21786,\n      \"southernmost\": 21787,\n      \"tilting\": 21788,\n      \"##vance\": 21789,\n      \"bai\": 21790,\n      \"economical\": 21791,\n      \"rf\": 21792,\n      \"briefcase\": 21793,\n      \"dreadful\": 21794,\n      \"hinted\": 21795,\n      \"projections\": 21796,\n      \"shattering\": 21797,\n      \"totaling\": 21798,\n      \"##rogate\": 21799,\n      \"analogue\": 21800,\n      \"indicted\": 21801,\n      \"periodical\": 21802,\n      \"fullback\": 21803,\n      \"##dman\": 21804,\n      \"haynes\": 21805,\n      \"##tenberg\": 21806,\n      \"##ffs\": 21807,\n      \"##ishment\": 21808,\n      \"1745\": 21809,\n      \"thirst\": 21810,\n      \"stumble\": 21811,\n      \"penang\": 21812,\n      \"vigorous\": 21813,\n      \"##ddling\": 21814,\n      \"##kor\": 21815,\n      \"##lium\": 21816,\n      \"octave\": 21817,\n      \"##ove\": 21818,\n      \"##enstein\": 21819,\n      \"##inen\": 21820,\n      \"##ones\": 21821,\n      \"siberian\": 21822,\n      \"##uti\": 21823,\n      \"cbn\": 21824,\n      \"repeal\": 21825,\n      \"swaying\": 21826,\n      \"##vington\": 21827,\n      \"khalid\": 21828,\n      \"tanaka\": 21829,\n      \"unicorn\": 21830,\n      \"otago\": 21831,\n      \"plastered\": 21832,\n      \"lobe\": 21833,\n      \"riddle\": 21834,\n      \"##rella\": 21835,\n      \"perch\": 21836,\n      \"##ishing\": 21837,\n      \"croydon\": 21838,\n      \"filtered\": 21839,\n      \"graeme\": 21840,\n      \"tripoli\": 21841,\n      \"##ossa\": 21842,\n      \"crocodile\": 21843,\n      \"##chers\": 21844,\n      \"sufi\": 21845,\n      \"mined\": 21846,\n      \"##tung\": 21847,\n      \"inferno\": 21848,\n      \"lsu\": 21849,\n      \"##phi\": 21850,\n      \"swelled\": 21851,\n      \"utilizes\": 21852,\n      \"£2\": 21853,\n      \"cale\": 21854,\n      \"periodicals\": 21855,\n      \"styx\": 21856,\n      \"hike\": 21857,\n      \"informally\": 21858,\n      \"coop\": 21859,\n      \"lund\": 21860,\n      \"##tidae\": 21861,\n      \"ala\": 21862,\n      \"hen\": 21863,\n      \"qui\": 21864,\n      \"transformations\": 21865,\n      \"disposed\": 21866,\n      \"sheath\": 21867,\n      \"chickens\": 21868,\n      \"##cade\": 21869,\n      \"fitzroy\": 21870,\n      \"sas\": 21871,\n      \"silesia\": 21872,\n      \"unacceptable\": 21873,\n      \"odisha\": 21874,\n      \"1650\": 21875,\n      \"sabrina\": 21876,\n      \"pe\": 21877,\n      \"spokane\": 21878,\n      \"ratios\": 21879,\n      \"athena\": 21880,\n      \"massage\": 21881,\n      \"shen\": 21882,\n      \"dilemma\": 21883,\n      \"##drum\": 21884,\n      \"##riz\": 21885,\n      \"##hul\": 21886,\n      \"corona\": 21887,\n      \"doubtful\": 21888,\n      \"niall\": 21889,\n      \"##pha\": 21890,\n      \"##bino\": 21891,\n      \"fines\": 21892,\n      \"cite\": 21893,\n      \"acknowledging\": 21894,\n      \"bangor\": 21895,\n      \"ballard\": 21896,\n      \"bathurst\": 21897,\n      \"##resh\": 21898,\n      \"huron\": 21899,\n      \"mustered\": 21900,\n      \"alzheimer\": 21901,\n      \"garments\": 21902,\n      \"kinase\": 21903,\n      \"tyre\": 21904,\n      \"warship\": 21905,\n      \"##cp\": 21906,\n      \"flashback\": 21907,\n      \"pulmonary\": 21908,\n      \"braun\": 21909,\n      \"cheat\": 21910,\n      \"kamal\": 21911,\n      \"cyclists\": 21912,\n      \"constructions\": 21913,\n      \"grenades\": 21914,\n      \"ndp\": 21915,\n      \"traveller\": 21916,\n      \"excuses\": 21917,\n      \"stomped\": 21918,\n      \"signalling\": 21919,\n      \"trimmed\": 21920,\n      \"futsal\": 21921,\n      \"mosques\": 21922,\n      \"relevance\": 21923,\n      \"##wine\": 21924,\n      \"wta\": 21925,\n      \"##23\": 21926,\n      \"##vah\": 21927,\n      \"##lter\": 21928,\n      \"hoc\": 21929,\n      \"##riding\": 21930,\n      \"optimistic\": 21931,\n      \"##´s\": 21932,\n      \"deco\": 21933,\n      \"sim\": 21934,\n      \"interacting\": 21935,\n      \"rejecting\": 21936,\n      \"moniker\": 21937,\n      \"waterways\": 21938,\n      \"##ieri\": 21939,\n      \"##oku\": 21940,\n      \"mayors\": 21941,\n      \"gdansk\": 21942,\n      \"outnumbered\": 21943,\n      \"pearls\": 21944,\n      \"##ended\": 21945,\n      \"##hampton\": 21946,\n      \"fairs\": 21947,\n      \"totals\": 21948,\n      \"dominating\": 21949,\n      \"262\": 21950,\n      \"notions\": 21951,\n      \"stairway\": 21952,\n      \"compiling\": 21953,\n      \"pursed\": 21954,\n      \"commodities\": 21955,\n      \"grease\": 21956,\n      \"yeast\": 21957,\n      \"##jong\": 21958,\n      \"carthage\": 21959,\n      \"griffiths\": 21960,\n      \"residual\": 21961,\n      \"amc\": 21962,\n      \"contraction\": 21963,\n      \"laird\": 21964,\n      \"sapphire\": 21965,\n      \"##marine\": 21966,\n      \"##ivated\": 21967,\n      \"amalgamation\": 21968,\n      \"dissolve\": 21969,\n      \"inclination\": 21970,\n      \"lyle\": 21971,\n      \"packaged\": 21972,\n      \"altitudes\": 21973,\n      \"suez\": 21974,\n      \"canons\": 21975,\n      \"graded\": 21976,\n      \"lurched\": 21977,\n      \"narrowing\": 21978,\n      \"boasts\": 21979,\n      \"guise\": 21980,\n      \"wed\": 21981,\n      \"enrico\": 21982,\n      \"##ovsky\": 21983,\n      \"rower\": 21984,\n      \"scarred\": 21985,\n      \"bree\": 21986,\n      \"cub\": 21987,\n      \"iberian\": 21988,\n      \"protagonists\": 21989,\n      \"bargaining\": 21990,\n      \"proposing\": 21991,\n      \"trainers\": 21992,\n      \"voyages\": 21993,\n      \"vans\": 21994,\n      \"fishes\": 21995,\n      \"##aea\": 21996,\n      \"##ivist\": 21997,\n      \"##verance\": 21998,\n      \"encryption\": 21999,\n      \"artworks\": 22000,\n      \"kazan\": 22001,\n      \"sabre\": 22002,\n      \"cleopatra\": 22003,\n      \"hepburn\": 22004,\n      \"rotting\": 22005,\n      \"supremacy\": 22006,\n      \"mecklenburg\": 22007,\n      \"##brate\": 22008,\n      \"burrows\": 22009,\n      \"hazards\": 22010,\n      \"outgoing\": 22011,\n      \"flair\": 22012,\n      \"organizes\": 22013,\n      \"##ctions\": 22014,\n      \"scorpion\": 22015,\n      \"##usions\": 22016,\n      \"boo\": 22017,\n      \"234\": 22018,\n      \"chevalier\": 22019,\n      \"dunedin\": 22020,\n      \"slapping\": 22021,\n      \"##34\": 22022,\n      \"ineligible\": 22023,\n      \"pensions\": 22024,\n      \"##38\": 22025,\n      \"##omic\": 22026,\n      \"manufactures\": 22027,\n      \"emails\": 22028,\n      \"bismarck\": 22029,\n      \"238\": 22030,\n      \"weakening\": 22031,\n      \"blackish\": 22032,\n      \"ding\": 22033,\n      \"mcgee\": 22034,\n      \"quo\": 22035,\n      \"##rling\": 22036,\n      \"northernmost\": 22037,\n      \"xx\": 22038,\n      \"manpower\": 22039,\n      \"greed\": 22040,\n      \"sampson\": 22041,\n      \"clicking\": 22042,\n      \"##ange\": 22043,\n      \"##horpe\": 22044,\n      \"##inations\": 22045,\n      \"##roving\": 22046,\n      \"torre\": 22047,\n      \"##eptive\": 22048,\n      \"##moral\": 22049,\n      \"symbolism\": 22050,\n      \"38th\": 22051,\n      \"asshole\": 22052,\n      \"meritorious\": 22053,\n      \"outfits\": 22054,\n      \"splashed\": 22055,\n      \"biographies\": 22056,\n      \"sprung\": 22057,\n      \"astros\": 22058,\n      \"##tale\": 22059,\n      \"302\": 22060,\n      \"737\": 22061,\n      \"filly\": 22062,\n      \"raoul\": 22063,\n      \"nw\": 22064,\n      \"tokugawa\": 22065,\n      \"linden\": 22066,\n      \"clubhouse\": 22067,\n      \"##apa\": 22068,\n      \"tracts\": 22069,\n      \"romano\": 22070,\n      \"##pio\": 22071,\n      \"putin\": 22072,\n      \"tags\": 22073,\n      \"##note\": 22074,\n      \"chained\": 22075,\n      \"dickson\": 22076,\n      \"gunshot\": 22077,\n      \"moe\": 22078,\n      \"gunn\": 22079,\n      \"rashid\": 22080,\n      \"##tails\": 22081,\n      \"zipper\": 22082,\n      \"##bas\": 22083,\n      \"##nea\": 22084,\n      \"contrasted\": 22085,\n      \"##ply\": 22086,\n      \"##udes\": 22087,\n      \"plum\": 22088,\n      \"pharaoh\": 22089,\n      \"##pile\": 22090,\n      \"aw\": 22091,\n      \"comedies\": 22092,\n      \"ingrid\": 22093,\n      \"sandwiches\": 22094,\n      \"subdivisions\": 22095,\n      \"1100\": 22096,\n      \"mariana\": 22097,\n      \"nokia\": 22098,\n      \"kamen\": 22099,\n      \"hz\": 22100,\n      \"delaney\": 22101,\n      \"veto\": 22102,\n      \"herring\": 22103,\n      \"##words\": 22104,\n      \"possessive\": 22105,\n      \"outlines\": 22106,\n      \"##roup\": 22107,\n      \"siemens\": 22108,\n      \"stairwell\": 22109,\n      \"rc\": 22110,\n      \"gallantry\": 22111,\n      \"messiah\": 22112,\n      \"palais\": 22113,\n      \"yells\": 22114,\n      \"233\": 22115,\n      \"zeppelin\": 22116,\n      \"##dm\": 22117,\n      \"bolivar\": 22118,\n      \"##cede\": 22119,\n      \"smackdown\": 22120,\n      \"mckinley\": 22121,\n      \"##mora\": 22122,\n      \"##yt\": 22123,\n      \"muted\": 22124,\n      \"geologic\": 22125,\n      \"finely\": 22126,\n      \"unitary\": 22127,\n      \"avatar\": 22128,\n      \"hamas\": 22129,\n      \"maynard\": 22130,\n      \"rees\": 22131,\n      \"bog\": 22132,\n      \"contrasting\": 22133,\n      \"##rut\": 22134,\n      \"liv\": 22135,\n      \"chico\": 22136,\n      \"disposition\": 22137,\n      \"pixel\": 22138,\n      \"##erate\": 22139,\n      \"becca\": 22140,\n      \"dmitry\": 22141,\n      \"yeshiva\": 22142,\n      \"narratives\": 22143,\n      \"##lva\": 22144,\n      \"##ulton\": 22145,\n      \"mercenary\": 22146,\n      \"sharpe\": 22147,\n      \"tempered\": 22148,\n      \"navigate\": 22149,\n      \"stealth\": 22150,\n      \"amassed\": 22151,\n      \"keynes\": 22152,\n      \"##lini\": 22153,\n      \"untouched\": 22154,\n      \"##rrie\": 22155,\n      \"havoc\": 22156,\n      \"lithium\": 22157,\n      \"##fighting\": 22158,\n      \"abyss\": 22159,\n      \"graf\": 22160,\n      \"southward\": 22161,\n      \"wolverine\": 22162,\n      \"balloons\": 22163,\n      \"implements\": 22164,\n      \"ngos\": 22165,\n      \"transitions\": 22166,\n      \"##icum\": 22167,\n      \"ambushed\": 22168,\n      \"concacaf\": 22169,\n      \"dormant\": 22170,\n      \"economists\": 22171,\n      \"##dim\": 22172,\n      \"costing\": 22173,\n      \"csi\": 22174,\n      \"rana\": 22175,\n      \"universite\": 22176,\n      \"boulders\": 22177,\n      \"verity\": 22178,\n      \"##llon\": 22179,\n      \"collin\": 22180,\n      \"mellon\": 22181,\n      \"misses\": 22182,\n      \"cypress\": 22183,\n      \"fluorescent\": 22184,\n      \"lifeless\": 22185,\n      \"spence\": 22186,\n      \"##ulla\": 22187,\n      \"crewe\": 22188,\n      \"shepard\": 22189,\n      \"pak\": 22190,\n      \"revelations\": 22191,\n      \"##م\": 22192,\n      \"jolly\": 22193,\n      \"gibbons\": 22194,\n      \"paw\": 22195,\n      \"##dro\": 22196,\n      \"##quel\": 22197,\n      \"freeing\": 22198,\n      \"##test\": 22199,\n      \"shack\": 22200,\n      \"fries\": 22201,\n      \"palatine\": 22202,\n      \"##51\": 22203,\n      \"##hiko\": 22204,\n      \"accompaniment\": 22205,\n      \"cruising\": 22206,\n      \"recycled\": 22207,\n      \"##aver\": 22208,\n      \"erwin\": 22209,\n      \"sorting\": 22210,\n      \"synthesizers\": 22211,\n      \"dyke\": 22212,\n      \"realities\": 22213,\n      \"sg\": 22214,\n      \"strides\": 22215,\n      \"enslaved\": 22216,\n      \"wetland\": 22217,\n      \"##ghan\": 22218,\n      \"competence\": 22219,\n      \"gunpowder\": 22220,\n      \"grassy\": 22221,\n      \"maroon\": 22222,\n      \"reactors\": 22223,\n      \"objection\": 22224,\n      \"##oms\": 22225,\n      \"carlson\": 22226,\n      \"gearbox\": 22227,\n      \"macintosh\": 22228,\n      \"radios\": 22229,\n      \"shelton\": 22230,\n      \"##sho\": 22231,\n      \"clergyman\": 22232,\n      \"prakash\": 22233,\n      \"254\": 22234,\n      \"mongols\": 22235,\n      \"trophies\": 22236,\n      \"oricon\": 22237,\n      \"228\": 22238,\n      \"stimuli\": 22239,\n      \"twenty20\": 22240,\n      \"cantonese\": 22241,\n      \"cortes\": 22242,\n      \"mirrored\": 22243,\n      \"##saurus\": 22244,\n      \"bhp\": 22245,\n      \"cristina\": 22246,\n      \"melancholy\": 22247,\n      \"##lating\": 22248,\n      \"enjoyable\": 22249,\n      \"nuevo\": 22250,\n      \"##wny\": 22251,\n      \"downfall\": 22252,\n      \"schumacher\": 22253,\n      \"##ind\": 22254,\n      \"banging\": 22255,\n      \"lausanne\": 22256,\n      \"rumbled\": 22257,\n      \"paramilitary\": 22258,\n      \"reflex\": 22259,\n      \"ax\": 22260,\n      \"amplitude\": 22261,\n      \"migratory\": 22262,\n      \"##gall\": 22263,\n      \"##ups\": 22264,\n      \"midi\": 22265,\n      \"barnard\": 22266,\n      \"lastly\": 22267,\n      \"sherry\": 22268,\n      \"##hp\": 22269,\n      \"##nall\": 22270,\n      \"keystone\": 22271,\n      \"##kra\": 22272,\n      \"carleton\": 22273,\n      \"slippery\": 22274,\n      \"##53\": 22275,\n      \"coloring\": 22276,\n      \"foe\": 22277,\n      \"socket\": 22278,\n      \"otter\": 22279,\n      \"##rgos\": 22280,\n      \"mats\": 22281,\n      \"##tose\": 22282,\n      \"consultants\": 22283,\n      \"bafta\": 22284,\n      \"bison\": 22285,\n      \"topping\": 22286,\n      \"##km\": 22287,\n      \"490\": 22288,\n      \"primal\": 22289,\n      \"abandonment\": 22290,\n      \"transplant\": 22291,\n      \"atoll\": 22292,\n      \"hideous\": 22293,\n      \"mort\": 22294,\n      \"pained\": 22295,\n      \"reproduced\": 22296,\n      \"tae\": 22297,\n      \"howling\": 22298,\n      \"##turn\": 22299,\n      \"unlawful\": 22300,\n      \"billionaire\": 22301,\n      \"hotter\": 22302,\n      \"poised\": 22303,\n      \"lansing\": 22304,\n      \"##chang\": 22305,\n      \"dinamo\": 22306,\n      \"retro\": 22307,\n      \"messing\": 22308,\n      \"nfc\": 22309,\n      \"domesday\": 22310,\n      \"##mina\": 22311,\n      \"blitz\": 22312,\n      \"timed\": 22313,\n      \"##athing\": 22314,\n      \"##kley\": 22315,\n      \"ascending\": 22316,\n      \"gesturing\": 22317,\n      \"##izations\": 22318,\n      \"signaled\": 22319,\n      \"tis\": 22320,\n      \"chinatown\": 22321,\n      \"mermaid\": 22322,\n      \"savanna\": 22323,\n      \"jameson\": 22324,\n      \"##aint\": 22325,\n      \"catalina\": 22326,\n      \"##pet\": 22327,\n      \"##hers\": 22328,\n      \"cochrane\": 22329,\n      \"cy\": 22330,\n      \"chatting\": 22331,\n      \"##kus\": 22332,\n      \"alerted\": 22333,\n      \"computation\": 22334,\n      \"mused\": 22335,\n      \"noelle\": 22336,\n      \"majestic\": 22337,\n      \"mohawk\": 22338,\n      \"campo\": 22339,\n      \"octagonal\": 22340,\n      \"##sant\": 22341,\n      \"##hend\": 22342,\n      \"241\": 22343,\n      \"aspiring\": 22344,\n      \"##mart\": 22345,\n      \"comprehend\": 22346,\n      \"iona\": 22347,\n      \"paralyzed\": 22348,\n      \"shimmering\": 22349,\n      \"swindon\": 22350,\n      \"rhone\": 22351,\n      \"##eley\": 22352,\n      \"reputed\": 22353,\n      \"configurations\": 22354,\n      \"pitchfork\": 22355,\n      \"agitation\": 22356,\n      \"francais\": 22357,\n      \"gillian\": 22358,\n      \"lipstick\": 22359,\n      \"##ilo\": 22360,\n      \"outsiders\": 22361,\n      \"pontifical\": 22362,\n      \"resisting\": 22363,\n      \"bitterness\": 22364,\n      \"sewer\": 22365,\n      \"rockies\": 22366,\n      \"##edd\": 22367,\n      \"##ucher\": 22368,\n      \"misleading\": 22369,\n      \"1756\": 22370,\n      \"exiting\": 22371,\n      \"galloway\": 22372,\n      \"##nging\": 22373,\n      \"risked\": 22374,\n      \"##heart\": 22375,\n      \"246\": 22376,\n      \"commemoration\": 22377,\n      \"schultz\": 22378,\n      \"##rka\": 22379,\n      \"integrating\": 22380,\n      \"##rsa\": 22381,\n      \"poses\": 22382,\n      \"shrieked\": 22383,\n      \"##weiler\": 22384,\n      \"guineas\": 22385,\n      \"gladys\": 22386,\n      \"jerking\": 22387,\n      \"owls\": 22388,\n      \"goldsmith\": 22389,\n      \"nightly\": 22390,\n      \"penetrating\": 22391,\n      \"##unced\": 22392,\n      \"lia\": 22393,\n      \"##33\": 22394,\n      \"ignited\": 22395,\n      \"betsy\": 22396,\n      \"##aring\": 22397,\n      \"##thorpe\": 22398,\n      \"follower\": 22399,\n      \"vigorously\": 22400,\n      \"##rave\": 22401,\n      \"coded\": 22402,\n      \"kiran\": 22403,\n      \"knit\": 22404,\n      \"zoology\": 22405,\n      \"tbilisi\": 22406,\n      \"##28\": 22407,\n      \"##bered\": 22408,\n      \"repository\": 22409,\n      \"govt\": 22410,\n      \"deciduous\": 22411,\n      \"dino\": 22412,\n      \"growling\": 22413,\n      \"##bba\": 22414,\n      \"enhancement\": 22415,\n      \"unleashed\": 22416,\n      \"chanting\": 22417,\n      \"pussy\": 22418,\n      \"biochemistry\": 22419,\n      \"##eric\": 22420,\n      \"kettle\": 22421,\n      \"repression\": 22422,\n      \"toxicity\": 22423,\n      \"nrhp\": 22424,\n      \"##arth\": 22425,\n      \"##kko\": 22426,\n      \"##bush\": 22427,\n      \"ernesto\": 22428,\n      \"commended\": 22429,\n      \"outspoken\": 22430,\n      \"242\": 22431,\n      \"mca\": 22432,\n      \"parchment\": 22433,\n      \"sms\": 22434,\n      \"kristen\": 22435,\n      \"##aton\": 22436,\n      \"bisexual\": 22437,\n      \"raked\": 22438,\n      \"glamour\": 22439,\n      \"navajo\": 22440,\n      \"a2\": 22441,\n      \"conditioned\": 22442,\n      \"showcased\": 22443,\n      \"##hma\": 22444,\n      \"spacious\": 22445,\n      \"youthful\": 22446,\n      \"##esa\": 22447,\n      \"usl\": 22448,\n      \"appliances\": 22449,\n      \"junta\": 22450,\n      \"brest\": 22451,\n      \"layne\": 22452,\n      \"conglomerate\": 22453,\n      \"enchanted\": 22454,\n      \"chao\": 22455,\n      \"loosened\": 22456,\n      \"picasso\": 22457,\n      \"circulating\": 22458,\n      \"inspect\": 22459,\n      \"montevideo\": 22460,\n      \"##centric\": 22461,\n      \"##kti\": 22462,\n      \"piazza\": 22463,\n      \"spurred\": 22464,\n      \"##aith\": 22465,\n      \"bari\": 22466,\n      \"freedoms\": 22467,\n      \"poultry\": 22468,\n      \"stamford\": 22469,\n      \"lieu\": 22470,\n      \"##ect\": 22471,\n      \"indigo\": 22472,\n      \"sarcastic\": 22473,\n      \"bahia\": 22474,\n      \"stump\": 22475,\n      \"attach\": 22476,\n      \"dvds\": 22477,\n      \"frankenstein\": 22478,\n      \"lille\": 22479,\n      \"approx\": 22480,\n      \"scriptures\": 22481,\n      \"pollen\": 22482,\n      \"##script\": 22483,\n      \"nmi\": 22484,\n      \"overseen\": 22485,\n      \"##ivism\": 22486,\n      \"tides\": 22487,\n      \"proponent\": 22488,\n      \"newmarket\": 22489,\n      \"inherit\": 22490,\n      \"milling\": 22491,\n      \"##erland\": 22492,\n      \"centralized\": 22493,\n      \"##rou\": 22494,\n      \"distributors\": 22495,\n      \"credentials\": 22496,\n      \"drawers\": 22497,\n      \"abbreviation\": 22498,\n      \"##lco\": 22499,\n      \"##xon\": 22500,\n      \"downing\": 22501,\n      \"uncomfortably\": 22502,\n      \"ripe\": 22503,\n      \"##oes\": 22504,\n      \"erase\": 22505,\n      \"franchises\": 22506,\n      \"##ever\": 22507,\n      \"populace\": 22508,\n      \"##bery\": 22509,\n      \"##khar\": 22510,\n      \"decomposition\": 22511,\n      \"pleas\": 22512,\n      \"##tet\": 22513,\n      \"daryl\": 22514,\n      \"sabah\": 22515,\n      \"##stle\": 22516,\n      \"##wide\": 22517,\n      \"fearless\": 22518,\n      \"genie\": 22519,\n      \"lesions\": 22520,\n      \"annette\": 22521,\n      \"##ogist\": 22522,\n      \"oboe\": 22523,\n      \"appendix\": 22524,\n      \"nair\": 22525,\n      \"dripped\": 22526,\n      \"petitioned\": 22527,\n      \"maclean\": 22528,\n      \"mosquito\": 22529,\n      \"parrot\": 22530,\n      \"rpg\": 22531,\n      \"hampered\": 22532,\n      \"1648\": 22533,\n      \"operatic\": 22534,\n      \"reservoirs\": 22535,\n      \"##tham\": 22536,\n      \"irrelevant\": 22537,\n      \"jolt\": 22538,\n      \"summarized\": 22539,\n      \"##fp\": 22540,\n      \"medallion\": 22541,\n      \"##taff\": 22542,\n      \"##−\": 22543,\n      \"clawed\": 22544,\n      \"harlow\": 22545,\n      \"narrower\": 22546,\n      \"goddard\": 22547,\n      \"marcia\": 22548,\n      \"bodied\": 22549,\n      \"fremont\": 22550,\n      \"suarez\": 22551,\n      \"altering\": 22552,\n      \"tempest\": 22553,\n      \"mussolini\": 22554,\n      \"porn\": 22555,\n      \"##isms\": 22556,\n      \"sweetly\": 22557,\n      \"oversees\": 22558,\n      \"walkers\": 22559,\n      \"solitude\": 22560,\n      \"grimly\": 22561,\n      \"shrines\": 22562,\n      \"hk\": 22563,\n      \"ich\": 22564,\n      \"supervisors\": 22565,\n      \"hostess\": 22566,\n      \"dietrich\": 22567,\n      \"legitimacy\": 22568,\n      \"brushes\": 22569,\n      \"expressive\": 22570,\n      \"##yp\": 22571,\n      \"dissipated\": 22572,\n      \"##rse\": 22573,\n      \"localized\": 22574,\n      \"systemic\": 22575,\n      \"##nikov\": 22576,\n      \"gettysburg\": 22577,\n      \"##js\": 22578,\n      \"##uaries\": 22579,\n      \"dialogues\": 22580,\n      \"muttering\": 22581,\n      \"251\": 22582,\n      \"housekeeper\": 22583,\n      \"sicilian\": 22584,\n      \"discouraged\": 22585,\n      \"##frey\": 22586,\n      \"beamed\": 22587,\n      \"kaladin\": 22588,\n      \"halftime\": 22589,\n      \"kidnap\": 22590,\n      \"##amo\": 22591,\n      \"##llet\": 22592,\n      \"1754\": 22593,\n      \"synonymous\": 22594,\n      \"depleted\": 22595,\n      \"instituto\": 22596,\n      \"insulin\": 22597,\n      \"reprised\": 22598,\n      \"##opsis\": 22599,\n      \"clashed\": 22600,\n      \"##ctric\": 22601,\n      \"interrupting\": 22602,\n      \"radcliffe\": 22603,\n      \"insisting\": 22604,\n      \"medici\": 22605,\n      \"1715\": 22606,\n      \"ejected\": 22607,\n      \"playfully\": 22608,\n      \"turbulent\": 22609,\n      \"##47\": 22610,\n      \"starvation\": 22611,\n      \"##rini\": 22612,\n      \"shipment\": 22613,\n      \"rebellious\": 22614,\n      \"petersen\": 22615,\n      \"verification\": 22616,\n      \"merits\": 22617,\n      \"##rified\": 22618,\n      \"cakes\": 22619,\n      \"##charged\": 22620,\n      \"1757\": 22621,\n      \"milford\": 22622,\n      \"shortages\": 22623,\n      \"spying\": 22624,\n      \"fidelity\": 22625,\n      \"##aker\": 22626,\n      \"emitted\": 22627,\n      \"storylines\": 22628,\n      \"harvested\": 22629,\n      \"seismic\": 22630,\n      \"##iform\": 22631,\n      \"cheung\": 22632,\n      \"kilda\": 22633,\n      \"theoretically\": 22634,\n      \"barbie\": 22635,\n      \"lynx\": 22636,\n      \"##rgy\": 22637,\n      \"##tius\": 22638,\n      \"goblin\": 22639,\n      \"mata\": 22640,\n      \"poisonous\": 22641,\n      \"##nburg\": 22642,\n      \"reactive\": 22643,\n      \"residues\": 22644,\n      \"obedience\": 22645,\n      \"##евич\": 22646,\n      \"conjecture\": 22647,\n      \"##rac\": 22648,\n      \"401\": 22649,\n      \"hating\": 22650,\n      \"sixties\": 22651,\n      \"kicker\": 22652,\n      \"moaning\": 22653,\n      \"motown\": 22654,\n      \"##bha\": 22655,\n      \"emancipation\": 22656,\n      \"neoclassical\": 22657,\n      \"##hering\": 22658,\n      \"consoles\": 22659,\n      \"ebert\": 22660,\n      \"professorship\": 22661,\n      \"##tures\": 22662,\n      \"sustaining\": 22663,\n      \"assaults\": 22664,\n      \"obeyed\": 22665,\n      \"affluent\": 22666,\n      \"incurred\": 22667,\n      \"tornadoes\": 22668,\n      \"##eber\": 22669,\n      \"##zow\": 22670,\n      \"emphasizing\": 22671,\n      \"highlanders\": 22672,\n      \"cheated\": 22673,\n      \"helmets\": 22674,\n      \"##ctus\": 22675,\n      \"internship\": 22676,\n      \"terence\": 22677,\n      \"bony\": 22678,\n      \"executions\": 22679,\n      \"legislators\": 22680,\n      \"berries\": 22681,\n      \"peninsular\": 22682,\n      \"tinged\": 22683,\n      \"##aco\": 22684,\n      \"1689\": 22685,\n      \"amplifier\": 22686,\n      \"corvette\": 22687,\n      \"ribbons\": 22688,\n      \"lavish\": 22689,\n      \"pennant\": 22690,\n      \"##lander\": 22691,\n      \"worthless\": 22692,\n      \"##chfield\": 22693,\n      \"##forms\": 22694,\n      \"mariano\": 22695,\n      \"pyrenees\": 22696,\n      \"expenditures\": 22697,\n      \"##icides\": 22698,\n      \"chesterfield\": 22699,\n      \"mandir\": 22700,\n      \"tailor\": 22701,\n      \"39th\": 22702,\n      \"sergey\": 22703,\n      \"nestled\": 22704,\n      \"willed\": 22705,\n      \"aristocracy\": 22706,\n      \"devotees\": 22707,\n      \"goodnight\": 22708,\n      \"raaf\": 22709,\n      \"rumored\": 22710,\n      \"weaponry\": 22711,\n      \"remy\": 22712,\n      \"appropriations\": 22713,\n      \"harcourt\": 22714,\n      \"burr\": 22715,\n      \"riaa\": 22716,\n      \"##lence\": 22717,\n      \"limitation\": 22718,\n      \"unnoticed\": 22719,\n      \"guo\": 22720,\n      \"soaking\": 22721,\n      \"swamps\": 22722,\n      \"##tica\": 22723,\n      \"collapsing\": 22724,\n      \"tatiana\": 22725,\n      \"descriptive\": 22726,\n      \"brigham\": 22727,\n      \"psalm\": 22728,\n      \"##chment\": 22729,\n      \"maddox\": 22730,\n      \"##lization\": 22731,\n      \"patti\": 22732,\n      \"caliph\": 22733,\n      \"##aja\": 22734,\n      \"akron\": 22735,\n      \"injuring\": 22736,\n      \"serra\": 22737,\n      \"##ganj\": 22738,\n      \"basins\": 22739,\n      \"##sari\": 22740,\n      \"astonished\": 22741,\n      \"launcher\": 22742,\n      \"##church\": 22743,\n      \"hilary\": 22744,\n      \"wilkins\": 22745,\n      \"sewing\": 22746,\n      \"##sf\": 22747,\n      \"stinging\": 22748,\n      \"##fia\": 22749,\n      \"##ncia\": 22750,\n      \"underwood\": 22751,\n      \"startup\": 22752,\n      \"##ition\": 22753,\n      \"compilations\": 22754,\n      \"vibrations\": 22755,\n      \"embankment\": 22756,\n      \"jurist\": 22757,\n      \"##nity\": 22758,\n      \"bard\": 22759,\n      \"juventus\": 22760,\n      \"groundwater\": 22761,\n      \"kern\": 22762,\n      \"palaces\": 22763,\n      \"helium\": 22764,\n      \"boca\": 22765,\n      \"cramped\": 22766,\n      \"marissa\": 22767,\n      \"soto\": 22768,\n      \"##worm\": 22769,\n      \"jae\": 22770,\n      \"princely\": 22771,\n      \"##ggy\": 22772,\n      \"faso\": 22773,\n      \"bazaar\": 22774,\n      \"warmly\": 22775,\n      \"##voking\": 22776,\n      \"229\": 22777,\n      \"pairing\": 22778,\n      \"##lite\": 22779,\n      \"##grate\": 22780,\n      \"##nets\": 22781,\n      \"wien\": 22782,\n      \"freaked\": 22783,\n      \"ulysses\": 22784,\n      \"rebirth\": 22785,\n      \"##alia\": 22786,\n      \"##rent\": 22787,\n      \"mummy\": 22788,\n      \"guzman\": 22789,\n      \"jimenez\": 22790,\n      \"stilled\": 22791,\n      \"##nitz\": 22792,\n      \"trajectory\": 22793,\n      \"tha\": 22794,\n      \"woken\": 22795,\n      \"archival\": 22796,\n      \"professions\": 22797,\n      \"##pts\": 22798,\n      \"##pta\": 22799,\n      \"hilly\": 22800,\n      \"shadowy\": 22801,\n      \"shrink\": 22802,\n      \"##bolt\": 22803,\n      \"norwood\": 22804,\n      \"glued\": 22805,\n      \"migrate\": 22806,\n      \"stereotypes\": 22807,\n      \"devoid\": 22808,\n      \"##pheus\": 22809,\n      \"625\": 22810,\n      \"evacuate\": 22811,\n      \"horrors\": 22812,\n      \"infancy\": 22813,\n      \"gotham\": 22814,\n      \"knowles\": 22815,\n      \"optic\": 22816,\n      \"downloaded\": 22817,\n      \"sachs\": 22818,\n      \"kingsley\": 22819,\n      \"parramatta\": 22820,\n      \"darryl\": 22821,\n      \"mor\": 22822,\n      \"##onale\": 22823,\n      \"shady\": 22824,\n      \"commence\": 22825,\n      \"confesses\": 22826,\n      \"kan\": 22827,\n      \"##meter\": 22828,\n      \"##placed\": 22829,\n      \"marlborough\": 22830,\n      \"roundabout\": 22831,\n      \"regents\": 22832,\n      \"frigates\": 22833,\n      \"io\": 22834,\n      \"##imating\": 22835,\n      \"gothenburg\": 22836,\n      \"revoked\": 22837,\n      \"carvings\": 22838,\n      \"clockwise\": 22839,\n      \"convertible\": 22840,\n      \"intruder\": 22841,\n      \"##sche\": 22842,\n      \"banged\": 22843,\n      \"##ogo\": 22844,\n      \"vicky\": 22845,\n      \"bourgeois\": 22846,\n      \"##mony\": 22847,\n      \"dupont\": 22848,\n      \"footing\": 22849,\n      \"##gum\": 22850,\n      \"pd\": 22851,\n      \"##real\": 22852,\n      \"buckle\": 22853,\n      \"yun\": 22854,\n      \"penthouse\": 22855,\n      \"sane\": 22856,\n      \"720\": 22857,\n      \"serviced\": 22858,\n      \"stakeholders\": 22859,\n      \"neumann\": 22860,\n      \"bb\": 22861,\n      \"##eers\": 22862,\n      \"comb\": 22863,\n      \"##gam\": 22864,\n      \"catchment\": 22865,\n      \"pinning\": 22866,\n      \"rallies\": 22867,\n      \"typing\": 22868,\n      \"##elles\": 22869,\n      \"forefront\": 22870,\n      \"freiburg\": 22871,\n      \"sweetie\": 22872,\n      \"giacomo\": 22873,\n      \"widowed\": 22874,\n      \"goodwill\": 22875,\n      \"worshipped\": 22876,\n      \"aspirations\": 22877,\n      \"midday\": 22878,\n      \"##vat\": 22879,\n      \"fishery\": 22880,\n      \"##trick\": 22881,\n      \"bournemouth\": 22882,\n      \"turk\": 22883,\n      \"243\": 22884,\n      \"hearth\": 22885,\n      \"ethanol\": 22886,\n      \"guadalajara\": 22887,\n      \"murmurs\": 22888,\n      \"sl\": 22889,\n      \"##uge\": 22890,\n      \"afforded\": 22891,\n      \"scripted\": 22892,\n      \"##hta\": 22893,\n      \"wah\": 22894,\n      \"##jn\": 22895,\n      \"coroner\": 22896,\n      \"translucent\": 22897,\n      \"252\": 22898,\n      \"memorials\": 22899,\n      \"puck\": 22900,\n      \"progresses\": 22901,\n      \"clumsy\": 22902,\n      \"##race\": 22903,\n      \"315\": 22904,\n      \"candace\": 22905,\n      \"recounted\": 22906,\n      \"##27\": 22907,\n      \"##slin\": 22908,\n      \"##uve\": 22909,\n      \"filtering\": 22910,\n      \"##mac\": 22911,\n      \"howl\": 22912,\n      \"strata\": 22913,\n      \"heron\": 22914,\n      \"leveled\": 22915,\n      \"##ays\": 22916,\n      \"dubious\": 22917,\n      \"##oja\": 22918,\n      \"##т\": 22919,\n      \"##wheel\": 22920,\n      \"citations\": 22921,\n      \"exhibiting\": 22922,\n      \"##laya\": 22923,\n      \"##mics\": 22924,\n      \"##pods\": 22925,\n      \"turkic\": 22926,\n      \"##lberg\": 22927,\n      \"injunction\": 22928,\n      \"##ennial\": 22929,\n      \"##mit\": 22930,\n      \"antibodies\": 22931,\n      \"##44\": 22932,\n      \"organise\": 22933,\n      \"##rigues\": 22934,\n      \"cardiovascular\": 22935,\n      \"cushion\": 22936,\n      \"inverness\": 22937,\n      \"##zquez\": 22938,\n      \"dia\": 22939,\n      \"cocoa\": 22940,\n      \"sibling\": 22941,\n      \"##tman\": 22942,\n      \"##roid\": 22943,\n      \"expanse\": 22944,\n      \"feasible\": 22945,\n      \"tunisian\": 22946,\n      \"algiers\": 22947,\n      \"##relli\": 22948,\n      \"rus\": 22949,\n      \"bloomberg\": 22950,\n      \"dso\": 22951,\n      \"westphalia\": 22952,\n      \"bro\": 22953,\n      \"tacoma\": 22954,\n      \"281\": 22955,\n      \"downloads\": 22956,\n      \"##ours\": 22957,\n      \"konrad\": 22958,\n      \"duran\": 22959,\n      \"##hdi\": 22960,\n      \"continuum\": 22961,\n      \"jett\": 22962,\n      \"compares\": 22963,\n      \"legislator\": 22964,\n      \"secession\": 22965,\n      \"##nable\": 22966,\n      \"##gues\": 22967,\n      \"##zuka\": 22968,\n      \"translating\": 22969,\n      \"reacher\": 22970,\n      \"##gley\": 22971,\n      \"##ła\": 22972,\n      \"aleppo\": 22973,\n      \"##agi\": 22974,\n      \"tc\": 22975,\n      \"orchards\": 22976,\n      \"trapping\": 22977,\n      \"linguist\": 22978,\n      \"versatile\": 22979,\n      \"drumming\": 22980,\n      \"postage\": 22981,\n      \"calhoun\": 22982,\n      \"superiors\": 22983,\n      \"##mx\": 22984,\n      \"barefoot\": 22985,\n      \"leary\": 22986,\n      \"##cis\": 22987,\n      \"ignacio\": 22988,\n      \"alfa\": 22989,\n      \"kaplan\": 22990,\n      \"##rogen\": 22991,\n      \"bratislava\": 22992,\n      \"mori\": 22993,\n      \"##vot\": 22994,\n      \"disturb\": 22995,\n      \"haas\": 22996,\n      \"313\": 22997,\n      \"cartridges\": 22998,\n      \"gilmore\": 22999,\n      \"radiated\": 23000,\n      \"salford\": 23001,\n      \"tunic\": 23002,\n      \"hades\": 23003,\n      \"##ulsive\": 23004,\n      \"archeological\": 23005,\n      \"delilah\": 23006,\n      \"magistrates\": 23007,\n      \"auditioned\": 23008,\n      \"brewster\": 23009,\n      \"charters\": 23010,\n      \"empowerment\": 23011,\n      \"blogs\": 23012,\n      \"cappella\": 23013,\n      \"dynasties\": 23014,\n      \"iroquois\": 23015,\n      \"whipping\": 23016,\n      \"##krishna\": 23017,\n      \"raceway\": 23018,\n      \"truths\": 23019,\n      \"myra\": 23020,\n      \"weaken\": 23021,\n      \"judah\": 23022,\n      \"mcgregor\": 23023,\n      \"##horse\": 23024,\n      \"mic\": 23025,\n      \"refueling\": 23026,\n      \"37th\": 23027,\n      \"burnley\": 23028,\n      \"bosses\": 23029,\n      \"markus\": 23030,\n      \"premio\": 23031,\n      \"query\": 23032,\n      \"##gga\": 23033,\n      \"dunbar\": 23034,\n      \"##economic\": 23035,\n      \"darkest\": 23036,\n      \"lyndon\": 23037,\n      \"sealing\": 23038,\n      \"commendation\": 23039,\n      \"reappeared\": 23040,\n      \"##mun\": 23041,\n      \"addicted\": 23042,\n      \"ezio\": 23043,\n      \"slaughtered\": 23044,\n      \"satisfactory\": 23045,\n      \"shuffle\": 23046,\n      \"##eves\": 23047,\n      \"##thic\": 23048,\n      \"##uj\": 23049,\n      \"fortification\": 23050,\n      \"warrington\": 23051,\n      \"##otto\": 23052,\n      \"resurrected\": 23053,\n      \"fargo\": 23054,\n      \"mane\": 23055,\n      \"##utable\": 23056,\n      \"##lei\": 23057,\n      \"##space\": 23058,\n      \"foreword\": 23059,\n      \"ox\": 23060,\n      \"##aris\": 23061,\n      \"##vern\": 23062,\n      \"abrams\": 23063,\n      \"hua\": 23064,\n      \"##mento\": 23065,\n      \"sakura\": 23066,\n      \"##alo\": 23067,\n      \"uv\": 23068,\n      \"sentimental\": 23069,\n      \"##skaya\": 23070,\n      \"midfield\": 23071,\n      \"##eses\": 23072,\n      \"sturdy\": 23073,\n      \"scrolls\": 23074,\n      \"macleod\": 23075,\n      \"##kyu\": 23076,\n      \"entropy\": 23077,\n      \"##lance\": 23078,\n      \"mitochondrial\": 23079,\n      \"cicero\": 23080,\n      \"excelled\": 23081,\n      \"thinner\": 23082,\n      \"convoys\": 23083,\n      \"perceive\": 23084,\n      \"##oslav\": 23085,\n      \"##urable\": 23086,\n      \"systematically\": 23087,\n      \"grind\": 23088,\n      \"burkina\": 23089,\n      \"287\": 23090,\n      \"##tagram\": 23091,\n      \"ops\": 23092,\n      \"##aman\": 23093,\n      \"guantanamo\": 23094,\n      \"##cloth\": 23095,\n      \"##tite\": 23096,\n      \"forcefully\": 23097,\n      \"wavy\": 23098,\n      \"##jou\": 23099,\n      \"pointless\": 23100,\n      \"##linger\": 23101,\n      \"##tze\": 23102,\n      \"layton\": 23103,\n      \"portico\": 23104,\n      \"superficial\": 23105,\n      \"clerical\": 23106,\n      \"outlaws\": 23107,\n      \"##hism\": 23108,\n      \"burials\": 23109,\n      \"muir\": 23110,\n      \"##inn\": 23111,\n      \"creditors\": 23112,\n      \"hauling\": 23113,\n      \"rattle\": 23114,\n      \"##leg\": 23115,\n      \"calais\": 23116,\n      \"monde\": 23117,\n      \"archers\": 23118,\n      \"reclaimed\": 23119,\n      \"dwell\": 23120,\n      \"wexford\": 23121,\n      \"hellenic\": 23122,\n      \"falsely\": 23123,\n      \"remorse\": 23124,\n      \"##tek\": 23125,\n      \"dough\": 23126,\n      \"furnishings\": 23127,\n      \"##uttered\": 23128,\n      \"gabon\": 23129,\n      \"neurological\": 23130,\n      \"novice\": 23131,\n      \"##igraphy\": 23132,\n      \"contemplated\": 23133,\n      \"pulpit\": 23134,\n      \"nightstand\": 23135,\n      \"saratoga\": 23136,\n      \"##istan\": 23137,\n      \"documenting\": 23138,\n      \"pulsing\": 23139,\n      \"taluk\": 23140,\n      \"##firmed\": 23141,\n      \"busted\": 23142,\n      \"marital\": 23143,\n      \"##rien\": 23144,\n      \"disagreements\": 23145,\n      \"wasps\": 23146,\n      \"##yes\": 23147,\n      \"hodge\": 23148,\n      \"mcdonnell\": 23149,\n      \"mimic\": 23150,\n      \"fran\": 23151,\n      \"pendant\": 23152,\n      \"dhabi\": 23153,\n      \"musa\": 23154,\n      \"##nington\": 23155,\n      \"congratulations\": 23156,\n      \"argent\": 23157,\n      \"darrell\": 23158,\n      \"concussion\": 23159,\n      \"losers\": 23160,\n      \"regrets\": 23161,\n      \"thessaloniki\": 23162,\n      \"reversal\": 23163,\n      \"donaldson\": 23164,\n      \"hardwood\": 23165,\n      \"thence\": 23166,\n      \"achilles\": 23167,\n      \"ritter\": 23168,\n      \"##eran\": 23169,\n      \"demonic\": 23170,\n      \"jurgen\": 23171,\n      \"prophets\": 23172,\n      \"goethe\": 23173,\n      \"eki\": 23174,\n      \"classmate\": 23175,\n      \"buff\": 23176,\n      \"##cking\": 23177,\n      \"yank\": 23178,\n      \"irrational\": 23179,\n      \"##inging\": 23180,\n      \"perished\": 23181,\n      \"seductive\": 23182,\n      \"qur\": 23183,\n      \"sourced\": 23184,\n      \"##crat\": 23185,\n      \"##typic\": 23186,\n      \"mustard\": 23187,\n      \"ravine\": 23188,\n      \"barre\": 23189,\n      \"horizontally\": 23190,\n      \"characterization\": 23191,\n      \"phylogenetic\": 23192,\n      \"boise\": 23193,\n      \"##dit\": 23194,\n      \"##runner\": 23195,\n      \"##tower\": 23196,\n      \"brutally\": 23197,\n      \"intercourse\": 23198,\n      \"seduce\": 23199,\n      \"##bbing\": 23200,\n      \"fay\": 23201,\n      \"ferris\": 23202,\n      \"ogden\": 23203,\n      \"amar\": 23204,\n      \"nik\": 23205,\n      \"unarmed\": 23206,\n      \"##inator\": 23207,\n      \"evaluating\": 23208,\n      \"kyrgyzstan\": 23209,\n      \"sweetness\": 23210,\n      \"##lford\": 23211,\n      \"##oki\": 23212,\n      \"mccormick\": 23213,\n      \"meiji\": 23214,\n      \"notoriety\": 23215,\n      \"stimulate\": 23216,\n      \"disrupt\": 23217,\n      \"figuring\": 23218,\n      \"instructional\": 23219,\n      \"mcgrath\": 23220,\n      \"##zoo\": 23221,\n      \"groundbreaking\": 23222,\n      \"##lto\": 23223,\n      \"flinch\": 23224,\n      \"khorasan\": 23225,\n      \"agrarian\": 23226,\n      \"bengals\": 23227,\n      \"mixer\": 23228,\n      \"radiating\": 23229,\n      \"##sov\": 23230,\n      \"ingram\": 23231,\n      \"pitchers\": 23232,\n      \"nad\": 23233,\n      \"tariff\": 23234,\n      \"##cript\": 23235,\n      \"tata\": 23236,\n      \"##codes\": 23237,\n      \"##emi\": 23238,\n      \"##ungen\": 23239,\n      \"appellate\": 23240,\n      \"lehigh\": 23241,\n      \"##bled\": 23242,\n      \"##giri\": 23243,\n      \"brawl\": 23244,\n      \"duct\": 23245,\n      \"texans\": 23246,\n      \"##ciation\": 23247,\n      \"##ropolis\": 23248,\n      \"skipper\": 23249,\n      \"speculative\": 23250,\n      \"vomit\": 23251,\n      \"doctrines\": 23252,\n      \"stresses\": 23253,\n      \"253\": 23254,\n      \"davy\": 23255,\n      \"graders\": 23256,\n      \"whitehead\": 23257,\n      \"jozef\": 23258,\n      \"timely\": 23259,\n      \"cumulative\": 23260,\n      \"haryana\": 23261,\n      \"paints\": 23262,\n      \"appropriately\": 23263,\n      \"boon\": 23264,\n      \"cactus\": 23265,\n      \"##ales\": 23266,\n      \"##pid\": 23267,\n      \"dow\": 23268,\n      \"legions\": 23269,\n      \"##pit\": 23270,\n      \"perceptions\": 23271,\n      \"1730\": 23272,\n      \"picturesque\": 23273,\n      \"##yse\": 23274,\n      \"periphery\": 23275,\n      \"rune\": 23276,\n      \"wr\": 23277,\n      \"##aha\": 23278,\n      \"celtics\": 23279,\n      \"sentencing\": 23280,\n      \"whoa\": 23281,\n      \"##erin\": 23282,\n      \"confirms\": 23283,\n      \"variance\": 23284,\n      \"425\": 23285,\n      \"moines\": 23286,\n      \"mathews\": 23287,\n      \"spade\": 23288,\n      \"rave\": 23289,\n      \"m1\": 23290,\n      \"fronted\": 23291,\n      \"fx\": 23292,\n      \"blending\": 23293,\n      \"alleging\": 23294,\n      \"reared\": 23295,\n      \"##gl\": 23296,\n      \"237\": 23297,\n      \"##paper\": 23298,\n      \"grassroots\": 23299,\n      \"eroded\": 23300,\n      \"##free\": 23301,\n      \"##physical\": 23302,\n      \"directs\": 23303,\n      \"ordeal\": 23304,\n      \"##sław\": 23305,\n      \"accelerate\": 23306,\n      \"hacker\": 23307,\n      \"rooftop\": 23308,\n      \"##inia\": 23309,\n      \"lev\": 23310,\n      \"buys\": 23311,\n      \"cebu\": 23312,\n      \"devote\": 23313,\n      \"##lce\": 23314,\n      \"specialising\": 23315,\n      \"##ulsion\": 23316,\n      \"choreographed\": 23317,\n      \"repetition\": 23318,\n      \"warehouses\": 23319,\n      \"##ryl\": 23320,\n      \"paisley\": 23321,\n      \"tuscany\": 23322,\n      \"analogy\": 23323,\n      \"sorcerer\": 23324,\n      \"hash\": 23325,\n      \"huts\": 23326,\n      \"shards\": 23327,\n      \"descends\": 23328,\n      \"exclude\": 23329,\n      \"nix\": 23330,\n      \"chaplin\": 23331,\n      \"gaga\": 23332,\n      \"ito\": 23333,\n      \"vane\": 23334,\n      \"##drich\": 23335,\n      \"causeway\": 23336,\n      \"misconduct\": 23337,\n      \"limo\": 23338,\n      \"orchestrated\": 23339,\n      \"glands\": 23340,\n      \"jana\": 23341,\n      \"##kot\": 23342,\n      \"u2\": 23343,\n      \"##mple\": 23344,\n      \"##sons\": 23345,\n      \"branching\": 23346,\n      \"contrasts\": 23347,\n      \"scoop\": 23348,\n      \"longed\": 23349,\n      \"##virus\": 23350,\n      \"chattanooga\": 23351,\n      \"##75\": 23352,\n      \"syrup\": 23353,\n      \"cornerstone\": 23354,\n      \"##tized\": 23355,\n      \"##mind\": 23356,\n      \"##iaceae\": 23357,\n      \"careless\": 23358,\n      \"precedence\": 23359,\n      \"frescoes\": 23360,\n      \"##uet\": 23361,\n      \"chilled\": 23362,\n      \"consult\": 23363,\n      \"modelled\": 23364,\n      \"snatch\": 23365,\n      \"peat\": 23366,\n      \"##thermal\": 23367,\n      \"caucasian\": 23368,\n      \"humane\": 23369,\n      \"relaxation\": 23370,\n      \"spins\": 23371,\n      \"temperance\": 23372,\n      \"##lbert\": 23373,\n      \"occupations\": 23374,\n      \"lambda\": 23375,\n      \"hybrids\": 23376,\n      \"moons\": 23377,\n      \"mp3\": 23378,\n      \"##oese\": 23379,\n      \"247\": 23380,\n      \"rolf\": 23381,\n      \"societal\": 23382,\n      \"yerevan\": 23383,\n      \"ness\": 23384,\n      \"##ssler\": 23385,\n      \"befriended\": 23386,\n      \"mechanized\": 23387,\n      \"nominate\": 23388,\n      \"trough\": 23389,\n      \"boasted\": 23390,\n      \"cues\": 23391,\n      \"seater\": 23392,\n      \"##hom\": 23393,\n      \"bends\": 23394,\n      \"##tangle\": 23395,\n      \"conductors\": 23396,\n      \"emptiness\": 23397,\n      \"##lmer\": 23398,\n      \"eurasian\": 23399,\n      \"adriatic\": 23400,\n      \"tian\": 23401,\n      \"##cie\": 23402,\n      \"anxiously\": 23403,\n      \"lark\": 23404,\n      \"propellers\": 23405,\n      \"chichester\": 23406,\n      \"jock\": 23407,\n      \"ev\": 23408,\n      \"2a\": 23409,\n      \"##holding\": 23410,\n      \"credible\": 23411,\n      \"recounts\": 23412,\n      \"tori\": 23413,\n      \"loyalist\": 23414,\n      \"abduction\": 23415,\n      \"##hoot\": 23416,\n      \"##redo\": 23417,\n      \"nepali\": 23418,\n      \"##mite\": 23419,\n      \"ventral\": 23420,\n      \"tempting\": 23421,\n      \"##ango\": 23422,\n      \"##crats\": 23423,\n      \"steered\": 23424,\n      \"##wice\": 23425,\n      \"javelin\": 23426,\n      \"dipping\": 23427,\n      \"laborers\": 23428,\n      \"prentice\": 23429,\n      \"looming\": 23430,\n      \"titanium\": 23431,\n      \"##ː\": 23432,\n      \"badges\": 23433,\n      \"emir\": 23434,\n      \"tensor\": 23435,\n      \"##ntation\": 23436,\n      \"egyptians\": 23437,\n      \"rash\": 23438,\n      \"denies\": 23439,\n      \"hawthorne\": 23440,\n      \"lombard\": 23441,\n      \"showers\": 23442,\n      \"wehrmacht\": 23443,\n      \"dietary\": 23444,\n      \"trojan\": 23445,\n      \"##reus\": 23446,\n      \"welles\": 23447,\n      \"executing\": 23448,\n      \"horseshoe\": 23449,\n      \"lifeboat\": 23450,\n      \"##lak\": 23451,\n      \"elsa\": 23452,\n      \"infirmary\": 23453,\n      \"nearing\": 23454,\n      \"roberta\": 23455,\n      \"boyer\": 23456,\n      \"mutter\": 23457,\n      \"trillion\": 23458,\n      \"joanne\": 23459,\n      \"##fine\": 23460,\n      \"##oked\": 23461,\n      \"sinks\": 23462,\n      \"vortex\": 23463,\n      \"uruguayan\": 23464,\n      \"clasp\": 23465,\n      \"sirius\": 23466,\n      \"##block\": 23467,\n      \"accelerator\": 23468,\n      \"prohibit\": 23469,\n      \"sunken\": 23470,\n      \"byu\": 23471,\n      \"chronological\": 23472,\n      \"diplomats\": 23473,\n      \"ochreous\": 23474,\n      \"510\": 23475,\n      \"symmetrical\": 23476,\n      \"1644\": 23477,\n      \"maia\": 23478,\n      \"##tology\": 23479,\n      \"salts\": 23480,\n      \"reigns\": 23481,\n      \"atrocities\": 23482,\n      \"##ия\": 23483,\n      \"hess\": 23484,\n      \"bared\": 23485,\n      \"issn\": 23486,\n      \"##vyn\": 23487,\n      \"cater\": 23488,\n      \"saturated\": 23489,\n      \"##cycle\": 23490,\n      \"##isse\": 23491,\n      \"sable\": 23492,\n      \"voyager\": 23493,\n      \"dyer\": 23494,\n      \"yusuf\": 23495,\n      \"##inge\": 23496,\n      \"fountains\": 23497,\n      \"wolff\": 23498,\n      \"##39\": 23499,\n      \"##nni\": 23500,\n      \"engraving\": 23501,\n      \"rollins\": 23502,\n      \"atheist\": 23503,\n      \"ominous\": 23504,\n      \"##ault\": 23505,\n      \"herr\": 23506,\n      \"chariot\": 23507,\n      \"martina\": 23508,\n      \"strung\": 23509,\n      \"##fell\": 23510,\n      \"##farlane\": 23511,\n      \"horrific\": 23512,\n      \"sahib\": 23513,\n      \"gazes\": 23514,\n      \"saetan\": 23515,\n      \"erased\": 23516,\n      \"ptolemy\": 23517,\n      \"##olic\": 23518,\n      \"flushing\": 23519,\n      \"lauderdale\": 23520,\n      \"analytic\": 23521,\n      \"##ices\": 23522,\n      \"530\": 23523,\n      \"navarro\": 23524,\n      \"beak\": 23525,\n      \"gorilla\": 23526,\n      \"herrera\": 23527,\n      \"broom\": 23528,\n      \"guadalupe\": 23529,\n      \"raiding\": 23530,\n      \"sykes\": 23531,\n      \"311\": 23532,\n      \"bsc\": 23533,\n      \"deliveries\": 23534,\n      \"1720\": 23535,\n      \"invasions\": 23536,\n      \"carmichael\": 23537,\n      \"tajikistan\": 23538,\n      \"thematic\": 23539,\n      \"ecumenical\": 23540,\n      \"sentiments\": 23541,\n      \"onstage\": 23542,\n      \"##rians\": 23543,\n      \"##brand\": 23544,\n      \"##sume\": 23545,\n      \"catastrophic\": 23546,\n      \"flanks\": 23547,\n      \"molten\": 23548,\n      \"##arns\": 23549,\n      \"waller\": 23550,\n      \"aimee\": 23551,\n      \"terminating\": 23552,\n      \"##icing\": 23553,\n      \"alternately\": 23554,\n      \"##oche\": 23555,\n      \"nehru\": 23556,\n      \"printers\": 23557,\n      \"outraged\": 23558,\n      \"##eving\": 23559,\n      \"empires\": 23560,\n      \"template\": 23561,\n      \"banners\": 23562,\n      \"repetitive\": 23563,\n      \"za\": 23564,\n      \"##oise\": 23565,\n      \"vegetarian\": 23566,\n      \"##tell\": 23567,\n      \"guiana\": 23568,\n      \"opt\": 23569,\n      \"cavendish\": 23570,\n      \"lucknow\": 23571,\n      \"synthesized\": 23572,\n      \"##hani\": 23573,\n      \"##mada\": 23574,\n      \"finalized\": 23575,\n      \"##ctable\": 23576,\n      \"fictitious\": 23577,\n      \"mayoral\": 23578,\n      \"unreliable\": 23579,\n      \"##enham\": 23580,\n      \"embracing\": 23581,\n      \"peppers\": 23582,\n      \"rbis\": 23583,\n      \"##chio\": 23584,\n      \"##neo\": 23585,\n      \"inhibition\": 23586,\n      \"slashed\": 23587,\n      \"togo\": 23588,\n      \"orderly\": 23589,\n      \"embroidered\": 23590,\n      \"safari\": 23591,\n      \"salty\": 23592,\n      \"236\": 23593,\n      \"barron\": 23594,\n      \"benito\": 23595,\n      \"totaled\": 23596,\n      \"##dak\": 23597,\n      \"pubs\": 23598,\n      \"simulated\": 23599,\n      \"caden\": 23600,\n      \"devin\": 23601,\n      \"tolkien\": 23602,\n      \"momma\": 23603,\n      \"welding\": 23604,\n      \"sesame\": 23605,\n      \"##ept\": 23606,\n      \"gottingen\": 23607,\n      \"hardness\": 23608,\n      \"630\": 23609,\n      \"shaman\": 23610,\n      \"temeraire\": 23611,\n      \"620\": 23612,\n      \"adequately\": 23613,\n      \"pediatric\": 23614,\n      \"##kit\": 23615,\n      \"ck\": 23616,\n      \"assertion\": 23617,\n      \"radicals\": 23618,\n      \"composure\": 23619,\n      \"cadence\": 23620,\n      \"seafood\": 23621,\n      \"beaufort\": 23622,\n      \"lazarus\": 23623,\n      \"mani\": 23624,\n      \"warily\": 23625,\n      \"cunning\": 23626,\n      \"kurdistan\": 23627,\n      \"249\": 23628,\n      \"cantata\": 23629,\n      \"##kir\": 23630,\n      \"ares\": 23631,\n      \"##41\": 23632,\n      \"##clusive\": 23633,\n      \"nape\": 23634,\n      \"townland\": 23635,\n      \"geared\": 23636,\n      \"insulted\": 23637,\n      \"flutter\": 23638,\n      \"boating\": 23639,\n      \"violate\": 23640,\n      \"draper\": 23641,\n      \"dumping\": 23642,\n      \"malmo\": 23643,\n      \"##hh\": 23644,\n      \"##romatic\": 23645,\n      \"firearm\": 23646,\n      \"alta\": 23647,\n      \"bono\": 23648,\n      \"obscured\": 23649,\n      \"##clave\": 23650,\n      \"exceeds\": 23651,\n      \"panorama\": 23652,\n      \"unbelievable\": 23653,\n      \"##train\": 23654,\n      \"preschool\": 23655,\n      \"##essed\": 23656,\n      \"disconnected\": 23657,\n      \"installing\": 23658,\n      \"rescuing\": 23659,\n      \"secretaries\": 23660,\n      \"accessibility\": 23661,\n      \"##castle\": 23662,\n      \"##drive\": 23663,\n      \"##ifice\": 23664,\n      \"##film\": 23665,\n      \"bouts\": 23666,\n      \"slug\": 23667,\n      \"waterway\": 23668,\n      \"mindanao\": 23669,\n      \"##buro\": 23670,\n      \"##ratic\": 23671,\n      \"halves\": 23672,\n      \"##ل\": 23673,\n      \"calming\": 23674,\n      \"liter\": 23675,\n      \"maternity\": 23676,\n      \"adorable\": 23677,\n      \"bragg\": 23678,\n      \"electrification\": 23679,\n      \"mcc\": 23680,\n      \"##dote\": 23681,\n      \"roxy\": 23682,\n      \"schizophrenia\": 23683,\n      \"##body\": 23684,\n      \"munoz\": 23685,\n      \"kaye\": 23686,\n      \"whaling\": 23687,\n      \"239\": 23688,\n      \"mil\": 23689,\n      \"tingling\": 23690,\n      \"tolerant\": 23691,\n      \"##ago\": 23692,\n      \"unconventional\": 23693,\n      \"volcanoes\": 23694,\n      \"##finder\": 23695,\n      \"deportivo\": 23696,\n      \"##llie\": 23697,\n      \"robson\": 23698,\n      \"kaufman\": 23699,\n      \"neuroscience\": 23700,\n      \"wai\": 23701,\n      \"deportation\": 23702,\n      \"masovian\": 23703,\n      \"scraping\": 23704,\n      \"converse\": 23705,\n      \"##bh\": 23706,\n      \"hacking\": 23707,\n      \"bulge\": 23708,\n      \"##oun\": 23709,\n      \"administratively\": 23710,\n      \"yao\": 23711,\n      \"580\": 23712,\n      \"amp\": 23713,\n      \"mammoth\": 23714,\n      \"booster\": 23715,\n      \"claremont\": 23716,\n      \"hooper\": 23717,\n      \"nomenclature\": 23718,\n      \"pursuits\": 23719,\n      \"mclaughlin\": 23720,\n      \"melinda\": 23721,\n      \"##sul\": 23722,\n      \"catfish\": 23723,\n      \"barclay\": 23724,\n      \"substrates\": 23725,\n      \"taxa\": 23726,\n      \"zee\": 23727,\n      \"originals\": 23728,\n      \"kimberly\": 23729,\n      \"packets\": 23730,\n      \"padma\": 23731,\n      \"##ality\": 23732,\n      \"borrowing\": 23733,\n      \"ostensibly\": 23734,\n      \"solvent\": 23735,\n      \"##bri\": 23736,\n      \"##genesis\": 23737,\n      \"##mist\": 23738,\n      \"lukas\": 23739,\n      \"shreveport\": 23740,\n      \"veracruz\": 23741,\n      \"##ь\": 23742,\n      \"##lou\": 23743,\n      \"##wives\": 23744,\n      \"cheney\": 23745,\n      \"tt\": 23746,\n      \"anatolia\": 23747,\n      \"hobbs\": 23748,\n      \"##zyn\": 23749,\n      \"cyclic\": 23750,\n      \"radiant\": 23751,\n      \"alistair\": 23752,\n      \"greenish\": 23753,\n      \"siena\": 23754,\n      \"dat\": 23755,\n      \"independents\": 23756,\n      \"##bation\": 23757,\n      \"conform\": 23758,\n      \"pieter\": 23759,\n      \"hyper\": 23760,\n      \"applicant\": 23761,\n      \"bradshaw\": 23762,\n      \"spores\": 23763,\n      \"telangana\": 23764,\n      \"vinci\": 23765,\n      \"inexpensive\": 23766,\n      \"nuclei\": 23767,\n      \"322\": 23768,\n      \"jang\": 23769,\n      \"nme\": 23770,\n      \"soho\": 23771,\n      \"spd\": 23772,\n      \"##ign\": 23773,\n      \"cradled\": 23774,\n      \"receptionist\": 23775,\n      \"pow\": 23776,\n      \"##43\": 23777,\n      \"##rika\": 23778,\n      \"fascism\": 23779,\n      \"##ifer\": 23780,\n      \"experimenting\": 23781,\n      \"##ading\": 23782,\n      \"##iec\": 23783,\n      \"##region\": 23784,\n      \"345\": 23785,\n      \"jocelyn\": 23786,\n      \"maris\": 23787,\n      \"stair\": 23788,\n      \"nocturnal\": 23789,\n      \"toro\": 23790,\n      \"constabulary\": 23791,\n      \"elgin\": 23792,\n      \"##kker\": 23793,\n      \"msc\": 23794,\n      \"##giving\": 23795,\n      \"##schen\": 23796,\n      \"##rase\": 23797,\n      \"doherty\": 23798,\n      \"doping\": 23799,\n      \"sarcastically\": 23800,\n      \"batter\": 23801,\n      \"maneuvers\": 23802,\n      \"##cano\": 23803,\n      \"##apple\": 23804,\n      \"##gai\": 23805,\n      \"##git\": 23806,\n      \"intrinsic\": 23807,\n      \"##nst\": 23808,\n      \"##stor\": 23809,\n      \"1753\": 23810,\n      \"showtime\": 23811,\n      \"cafes\": 23812,\n      \"gasps\": 23813,\n      \"lviv\": 23814,\n      \"ushered\": 23815,\n      \"##thed\": 23816,\n      \"fours\": 23817,\n      \"restart\": 23818,\n      \"astonishment\": 23819,\n      \"transmitting\": 23820,\n      \"flyer\": 23821,\n      \"shrugs\": 23822,\n      \"##sau\": 23823,\n      \"intriguing\": 23824,\n      \"cones\": 23825,\n      \"dictated\": 23826,\n      \"mushrooms\": 23827,\n      \"medial\": 23828,\n      \"##kovsky\": 23829,\n      \"##elman\": 23830,\n      \"escorting\": 23831,\n      \"gaped\": 23832,\n      \"##26\": 23833,\n      \"godfather\": 23834,\n      \"##door\": 23835,\n      \"##sell\": 23836,\n      \"djs\": 23837,\n      \"recaptured\": 23838,\n      \"timetable\": 23839,\n      \"vila\": 23840,\n      \"1710\": 23841,\n      \"3a\": 23842,\n      \"aerodrome\": 23843,\n      \"mortals\": 23844,\n      \"scientology\": 23845,\n      \"##orne\": 23846,\n      \"angelina\": 23847,\n      \"mag\": 23848,\n      \"convection\": 23849,\n      \"unpaid\": 23850,\n      \"insertion\": 23851,\n      \"intermittent\": 23852,\n      \"lego\": 23853,\n      \"##nated\": 23854,\n      \"endeavor\": 23855,\n      \"kota\": 23856,\n      \"pereira\": 23857,\n      \"##lz\": 23858,\n      \"304\": 23859,\n      \"bwv\": 23860,\n      \"glamorgan\": 23861,\n      \"insults\": 23862,\n      \"agatha\": 23863,\n      \"fey\": 23864,\n      \"##cend\": 23865,\n      \"fleetwood\": 23866,\n      \"mahogany\": 23867,\n      \"protruding\": 23868,\n      \"steamship\": 23869,\n      \"zeta\": 23870,\n      \"##arty\": 23871,\n      \"mcguire\": 23872,\n      \"suspense\": 23873,\n      \"##sphere\": 23874,\n      \"advising\": 23875,\n      \"urges\": 23876,\n      \"##wala\": 23877,\n      \"hurriedly\": 23878,\n      \"meteor\": 23879,\n      \"gilded\": 23880,\n      \"inline\": 23881,\n      \"arroyo\": 23882,\n      \"stalker\": 23883,\n      \"##oge\": 23884,\n      \"excitedly\": 23885,\n      \"revered\": 23886,\n      \"##cure\": 23887,\n      \"earle\": 23888,\n      \"introductory\": 23889,\n      \"##break\": 23890,\n      \"##ilde\": 23891,\n      \"mutants\": 23892,\n      \"puff\": 23893,\n      \"pulses\": 23894,\n      \"reinforcement\": 23895,\n      \"##haling\": 23896,\n      \"curses\": 23897,\n      \"lizards\": 23898,\n      \"stalk\": 23899,\n      \"correlated\": 23900,\n      \"##fixed\": 23901,\n      \"fallout\": 23902,\n      \"macquarie\": 23903,\n      \"##unas\": 23904,\n      \"bearded\": 23905,\n      \"denton\": 23906,\n      \"heaving\": 23907,\n      \"802\": 23908,\n      \"##ocation\": 23909,\n      \"winery\": 23910,\n      \"assign\": 23911,\n      \"dortmund\": 23912,\n      \"##lkirk\": 23913,\n      \"everest\": 23914,\n      \"invariant\": 23915,\n      \"charismatic\": 23916,\n      \"susie\": 23917,\n      \"##elling\": 23918,\n      \"bled\": 23919,\n      \"lesley\": 23920,\n      \"telegram\": 23921,\n      \"sumner\": 23922,\n      \"bk\": 23923,\n      \"##ogen\": 23924,\n      \"##к\": 23925,\n      \"wilcox\": 23926,\n      \"needy\": 23927,\n      \"colbert\": 23928,\n      \"duval\": 23929,\n      \"##iferous\": 23930,\n      \"##mbled\": 23931,\n      \"allotted\": 23932,\n      \"attends\": 23933,\n      \"imperative\": 23934,\n      \"##hita\": 23935,\n      \"replacements\": 23936,\n      \"hawker\": 23937,\n      \"##inda\": 23938,\n      \"insurgency\": 23939,\n      \"##zee\": 23940,\n      \"##eke\": 23941,\n      \"casts\": 23942,\n      \"##yla\": 23943,\n      \"680\": 23944,\n      \"ives\": 23945,\n      \"transitioned\": 23946,\n      \"##pack\": 23947,\n      \"##powering\": 23948,\n      \"authoritative\": 23949,\n      \"baylor\": 23950,\n      \"flex\": 23951,\n      \"cringed\": 23952,\n      \"plaintiffs\": 23953,\n      \"woodrow\": 23954,\n      \"##skie\": 23955,\n      \"drastic\": 23956,\n      \"ape\": 23957,\n      \"aroma\": 23958,\n      \"unfolded\": 23959,\n      \"commotion\": 23960,\n      \"nt\": 23961,\n      \"preoccupied\": 23962,\n      \"theta\": 23963,\n      \"routines\": 23964,\n      \"lasers\": 23965,\n      \"privatization\": 23966,\n      \"wand\": 23967,\n      \"domino\": 23968,\n      \"ek\": 23969,\n      \"clenching\": 23970,\n      \"nsa\": 23971,\n      \"strategically\": 23972,\n      \"showered\": 23973,\n      \"bile\": 23974,\n      \"handkerchief\": 23975,\n      \"pere\": 23976,\n      \"storing\": 23977,\n      \"christophe\": 23978,\n      \"insulting\": 23979,\n      \"316\": 23980,\n      \"nakamura\": 23981,\n      \"romani\": 23982,\n      \"asiatic\": 23983,\n      \"magdalena\": 23984,\n      \"palma\": 23985,\n      \"cruises\": 23986,\n      \"stripping\": 23987,\n      \"405\": 23988,\n      \"konstantin\": 23989,\n      \"soaring\": 23990,\n      \"##berman\": 23991,\n      \"colloquially\": 23992,\n      \"forerunner\": 23993,\n      \"havilland\": 23994,\n      \"incarcerated\": 23995,\n      \"parasites\": 23996,\n      \"sincerity\": 23997,\n      \"##utus\": 23998,\n      \"disks\": 23999,\n      \"plank\": 24000,\n      \"saigon\": 24001,\n      \"##ining\": 24002,\n      \"corbin\": 24003,\n      \"homo\": 24004,\n      \"ornaments\": 24005,\n      \"powerhouse\": 24006,\n      \"##tlement\": 24007,\n      \"chong\": 24008,\n      \"fastened\": 24009,\n      \"feasibility\": 24010,\n      \"idf\": 24011,\n      \"morphological\": 24012,\n      \"usable\": 24013,\n      \"##nish\": 24014,\n      \"##zuki\": 24015,\n      \"aqueduct\": 24016,\n      \"jaguars\": 24017,\n      \"keepers\": 24018,\n      \"##flies\": 24019,\n      \"aleksandr\": 24020,\n      \"faust\": 24021,\n      \"assigns\": 24022,\n      \"ewing\": 24023,\n      \"bacterium\": 24024,\n      \"hurled\": 24025,\n      \"tricky\": 24026,\n      \"hungarians\": 24027,\n      \"integers\": 24028,\n      \"wallis\": 24029,\n      \"321\": 24030,\n      \"yamaha\": 24031,\n      \"##isha\": 24032,\n      \"hushed\": 24033,\n      \"oblivion\": 24034,\n      \"aviator\": 24035,\n      \"evangelist\": 24036,\n      \"friars\": 24037,\n      \"##eller\": 24038,\n      \"monograph\": 24039,\n      \"ode\": 24040,\n      \"##nary\": 24041,\n      \"airplanes\": 24042,\n      \"labourers\": 24043,\n      \"charms\": 24044,\n      \"##nee\": 24045,\n      \"1661\": 24046,\n      \"hagen\": 24047,\n      \"tnt\": 24048,\n      \"rudder\": 24049,\n      \"fiesta\": 24050,\n      \"transcript\": 24051,\n      \"dorothea\": 24052,\n      \"ska\": 24053,\n      \"inhibitor\": 24054,\n      \"maccabi\": 24055,\n      \"retorted\": 24056,\n      \"raining\": 24057,\n      \"encompassed\": 24058,\n      \"clauses\": 24059,\n      \"menacing\": 24060,\n      \"1642\": 24061,\n      \"lineman\": 24062,\n      \"##gist\": 24063,\n      \"vamps\": 24064,\n      \"##ape\": 24065,\n      \"##dick\": 24066,\n      \"gloom\": 24067,\n      \"##rera\": 24068,\n      \"dealings\": 24069,\n      \"easing\": 24070,\n      \"seekers\": 24071,\n      \"##nut\": 24072,\n      \"##pment\": 24073,\n      \"helens\": 24074,\n      \"unmanned\": 24075,\n      \"##anu\": 24076,\n      \"##isson\": 24077,\n      \"basics\": 24078,\n      \"##amy\": 24079,\n      \"##ckman\": 24080,\n      \"adjustments\": 24081,\n      \"1688\": 24082,\n      \"brutality\": 24083,\n      \"horne\": 24084,\n      \"##zell\": 24085,\n      \"sui\": 24086,\n      \"##55\": 24087,\n      \"##mable\": 24088,\n      \"aggregator\": 24089,\n      \"##thal\": 24090,\n      \"rhino\": 24091,\n      \"##drick\": 24092,\n      \"##vira\": 24093,\n      \"counters\": 24094,\n      \"zoom\": 24095,\n      \"##01\": 24096,\n      \"##rting\": 24097,\n      \"mn\": 24098,\n      \"montenegrin\": 24099,\n      \"packard\": 24100,\n      \"##unciation\": 24101,\n      \"##♭\": 24102,\n      \"##kki\": 24103,\n      \"reclaim\": 24104,\n      \"scholastic\": 24105,\n      \"thugs\": 24106,\n      \"pulsed\": 24107,\n      \"##icia\": 24108,\n      \"syriac\": 24109,\n      \"quan\": 24110,\n      \"saddam\": 24111,\n      \"banda\": 24112,\n      \"kobe\": 24113,\n      \"blaming\": 24114,\n      \"buddies\": 24115,\n      \"dissent\": 24116,\n      \"##lusion\": 24117,\n      \"##usia\": 24118,\n      \"corbett\": 24119,\n      \"jaya\": 24120,\n      \"delle\": 24121,\n      \"erratic\": 24122,\n      \"lexie\": 24123,\n      \"##hesis\": 24124,\n      \"435\": 24125,\n      \"amiga\": 24126,\n      \"hermes\": 24127,\n      \"##pressing\": 24128,\n      \"##leen\": 24129,\n      \"chapels\": 24130,\n      \"gospels\": 24131,\n      \"jamal\": 24132,\n      \"##uating\": 24133,\n      \"compute\": 24134,\n      \"revolving\": 24135,\n      \"warp\": 24136,\n      \"##sso\": 24137,\n      \"##thes\": 24138,\n      \"armory\": 24139,\n      \"##eras\": 24140,\n      \"##gol\": 24141,\n      \"antrim\": 24142,\n      \"loki\": 24143,\n      \"##kow\": 24144,\n      \"##asian\": 24145,\n      \"##good\": 24146,\n      \"##zano\": 24147,\n      \"braid\": 24148,\n      \"handwriting\": 24149,\n      \"subdistrict\": 24150,\n      \"funky\": 24151,\n      \"pantheon\": 24152,\n      \"##iculate\": 24153,\n      \"concurrency\": 24154,\n      \"estimation\": 24155,\n      \"improper\": 24156,\n      \"juliana\": 24157,\n      \"##his\": 24158,\n      \"newcomers\": 24159,\n      \"johnstone\": 24160,\n      \"staten\": 24161,\n      \"communicated\": 24162,\n      \"##oco\": 24163,\n      \"##alle\": 24164,\n      \"sausage\": 24165,\n      \"stormy\": 24166,\n      \"##stered\": 24167,\n      \"##tters\": 24168,\n      \"superfamily\": 24169,\n      \"##grade\": 24170,\n      \"acidic\": 24171,\n      \"collateral\": 24172,\n      \"tabloid\": 24173,\n      \"##oped\": 24174,\n      \"##rza\": 24175,\n      \"bladder\": 24176,\n      \"austen\": 24177,\n      \"##ellant\": 24178,\n      \"mcgraw\": 24179,\n      \"##hay\": 24180,\n      \"hannibal\": 24181,\n      \"mein\": 24182,\n      \"aquino\": 24183,\n      \"lucifer\": 24184,\n      \"wo\": 24185,\n      \"badger\": 24186,\n      \"boar\": 24187,\n      \"cher\": 24188,\n      \"christensen\": 24189,\n      \"greenberg\": 24190,\n      \"interruption\": 24191,\n      \"##kken\": 24192,\n      \"jem\": 24193,\n      \"244\": 24194,\n      \"mocked\": 24195,\n      \"bottoms\": 24196,\n      \"cambridgeshire\": 24197,\n      \"##lide\": 24198,\n      \"sprawling\": 24199,\n      \"##bbly\": 24200,\n      \"eastwood\": 24201,\n      \"ghent\": 24202,\n      \"synth\": 24203,\n      \"##buck\": 24204,\n      \"advisers\": 24205,\n      \"##bah\": 24206,\n      \"nominally\": 24207,\n      \"hapoel\": 24208,\n      \"qu\": 24209,\n      \"daggers\": 24210,\n      \"estranged\": 24211,\n      \"fabricated\": 24212,\n      \"towels\": 24213,\n      \"vinnie\": 24214,\n      \"wcw\": 24215,\n      \"misunderstanding\": 24216,\n      \"anglia\": 24217,\n      \"nothin\": 24218,\n      \"unmistakable\": 24219,\n      \"##dust\": 24220,\n      \"##lova\": 24221,\n      \"chilly\": 24222,\n      \"marquette\": 24223,\n      \"truss\": 24224,\n      \"##edge\": 24225,\n      \"##erine\": 24226,\n      \"reece\": 24227,\n      \"##lty\": 24228,\n      \"##chemist\": 24229,\n      \"##connected\": 24230,\n      \"272\": 24231,\n      \"308\": 24232,\n      \"41st\": 24233,\n      \"bash\": 24234,\n      \"raion\": 24235,\n      \"waterfalls\": 24236,\n      \"##ump\": 24237,\n      \"##main\": 24238,\n      \"labyrinth\": 24239,\n      \"queue\": 24240,\n      \"theorist\": 24241,\n      \"##istle\": 24242,\n      \"bharatiya\": 24243,\n      \"flexed\": 24244,\n      \"soundtracks\": 24245,\n      \"rooney\": 24246,\n      \"leftist\": 24247,\n      \"patrolling\": 24248,\n      \"wharton\": 24249,\n      \"plainly\": 24250,\n      \"alleviate\": 24251,\n      \"eastman\": 24252,\n      \"schuster\": 24253,\n      \"topographic\": 24254,\n      \"engages\": 24255,\n      \"immensely\": 24256,\n      \"unbearable\": 24257,\n      \"fairchild\": 24258,\n      \"1620\": 24259,\n      \"dona\": 24260,\n      \"lurking\": 24261,\n      \"parisian\": 24262,\n      \"oliveira\": 24263,\n      \"ia\": 24264,\n      \"indictment\": 24265,\n      \"hahn\": 24266,\n      \"bangladeshi\": 24267,\n      \"##aster\": 24268,\n      \"vivo\": 24269,\n      \"##uming\": 24270,\n      \"##ential\": 24271,\n      \"antonia\": 24272,\n      \"expects\": 24273,\n      \"indoors\": 24274,\n      \"kildare\": 24275,\n      \"harlan\": 24276,\n      \"##logue\": 24277,\n      \"##ogenic\": 24278,\n      \"##sities\": 24279,\n      \"forgiven\": 24280,\n      \"##wat\": 24281,\n      \"childish\": 24282,\n      \"tavi\": 24283,\n      \"##mide\": 24284,\n      \"##orra\": 24285,\n      \"plausible\": 24286,\n      \"grimm\": 24287,\n      \"successively\": 24288,\n      \"scooted\": 24289,\n      \"##bola\": 24290,\n      \"##dget\": 24291,\n      \"##rith\": 24292,\n      \"spartans\": 24293,\n      \"emery\": 24294,\n      \"flatly\": 24295,\n      \"azure\": 24296,\n      \"epilogue\": 24297,\n      \"##wark\": 24298,\n      \"flourish\": 24299,\n      \"##iny\": 24300,\n      \"##tracted\": 24301,\n      \"##overs\": 24302,\n      \"##oshi\": 24303,\n      \"bestseller\": 24304,\n      \"distressed\": 24305,\n      \"receipt\": 24306,\n      \"spitting\": 24307,\n      \"hermit\": 24308,\n      \"topological\": 24309,\n      \"##cot\": 24310,\n      \"drilled\": 24311,\n      \"subunit\": 24312,\n      \"francs\": 24313,\n      \"##layer\": 24314,\n      \"eel\": 24315,\n      \"##fk\": 24316,\n      \"##itas\": 24317,\n      \"octopus\": 24318,\n      \"footprint\": 24319,\n      \"petitions\": 24320,\n      \"ufo\": 24321,\n      \"##say\": 24322,\n      \"##foil\": 24323,\n      \"interfering\": 24324,\n      \"leaking\": 24325,\n      \"palo\": 24326,\n      \"##metry\": 24327,\n      \"thistle\": 24328,\n      \"valiant\": 24329,\n      \"##pic\": 24330,\n      \"narayan\": 24331,\n      \"mcpherson\": 24332,\n      \"##fast\": 24333,\n      \"gonzales\": 24334,\n      \"##ym\": 24335,\n      \"##enne\": 24336,\n      \"dustin\": 24337,\n      \"novgorod\": 24338,\n      \"solos\": 24339,\n      \"##zman\": 24340,\n      \"doin\": 24341,\n      \"##raph\": 24342,\n      \"##patient\": 24343,\n      \"##meyer\": 24344,\n      \"soluble\": 24345,\n      \"ashland\": 24346,\n      \"cuffs\": 24347,\n      \"carole\": 24348,\n      \"pendleton\": 24349,\n      \"whistling\": 24350,\n      \"vassal\": 24351,\n      \"##river\": 24352,\n      \"deviation\": 24353,\n      \"revisited\": 24354,\n      \"constituents\": 24355,\n      \"rallied\": 24356,\n      \"rotate\": 24357,\n      \"loomed\": 24358,\n      \"##eil\": 24359,\n      \"##nting\": 24360,\n      \"amateurs\": 24361,\n      \"augsburg\": 24362,\n      \"auschwitz\": 24363,\n      \"crowns\": 24364,\n      \"skeletons\": 24365,\n      \"##cona\": 24366,\n      \"bonnet\": 24367,\n      \"257\": 24368,\n      \"dummy\": 24369,\n      \"globalization\": 24370,\n      \"simeon\": 24371,\n      \"sleeper\": 24372,\n      \"mandal\": 24373,\n      \"differentiated\": 24374,\n      \"##crow\": 24375,\n      \"##mare\": 24376,\n      \"milne\": 24377,\n      \"bundled\": 24378,\n      \"exasperated\": 24379,\n      \"talmud\": 24380,\n      \"owes\": 24381,\n      \"segregated\": 24382,\n      \"##feng\": 24383,\n      \"##uary\": 24384,\n      \"dentist\": 24385,\n      \"piracy\": 24386,\n      \"props\": 24387,\n      \"##rang\": 24388,\n      \"devlin\": 24389,\n      \"##torium\": 24390,\n      \"malicious\": 24391,\n      \"paws\": 24392,\n      \"##laid\": 24393,\n      \"dependency\": 24394,\n      \"##ergy\": 24395,\n      \"##fers\": 24396,\n      \"##enna\": 24397,\n      \"258\": 24398,\n      \"pistons\": 24399,\n      \"rourke\": 24400,\n      \"jed\": 24401,\n      \"grammatical\": 24402,\n      \"tres\": 24403,\n      \"maha\": 24404,\n      \"wig\": 24405,\n      \"512\": 24406,\n      \"ghostly\": 24407,\n      \"jayne\": 24408,\n      \"##achal\": 24409,\n      \"##creen\": 24410,\n      \"##ilis\": 24411,\n      \"##lins\": 24412,\n      \"##rence\": 24413,\n      \"designate\": 24414,\n      \"##with\": 24415,\n      \"arrogance\": 24416,\n      \"cambodian\": 24417,\n      \"clones\": 24418,\n      \"showdown\": 24419,\n      \"throttle\": 24420,\n      \"twain\": 24421,\n      \"##ception\": 24422,\n      \"lobes\": 24423,\n      \"metz\": 24424,\n      \"nagoya\": 24425,\n      \"335\": 24426,\n      \"braking\": 24427,\n      \"##furt\": 24428,\n      \"385\": 24429,\n      \"roaming\": 24430,\n      \"##minster\": 24431,\n      \"amin\": 24432,\n      \"crippled\": 24433,\n      \"##37\": 24434,\n      \"##llary\": 24435,\n      \"indifferent\": 24436,\n      \"hoffmann\": 24437,\n      \"idols\": 24438,\n      \"intimidating\": 24439,\n      \"1751\": 24440,\n      \"261\": 24441,\n      \"influenza\": 24442,\n      \"memo\": 24443,\n      \"onions\": 24444,\n      \"1748\": 24445,\n      \"bandage\": 24446,\n      \"consciously\": 24447,\n      \"##landa\": 24448,\n      \"##rage\": 24449,\n      \"clandestine\": 24450,\n      \"observes\": 24451,\n      \"swiped\": 24452,\n      \"tangle\": 24453,\n      \"##ener\": 24454,\n      \"##jected\": 24455,\n      \"##trum\": 24456,\n      \"##bill\": 24457,\n      \"##lta\": 24458,\n      \"hugs\": 24459,\n      \"congresses\": 24460,\n      \"josiah\": 24461,\n      \"spirited\": 24462,\n      \"##dek\": 24463,\n      \"humanist\": 24464,\n      \"managerial\": 24465,\n      \"filmmaking\": 24466,\n      \"inmate\": 24467,\n      \"rhymes\": 24468,\n      \"debuting\": 24469,\n      \"grimsby\": 24470,\n      \"ur\": 24471,\n      \"##laze\": 24472,\n      \"duplicate\": 24473,\n      \"vigor\": 24474,\n      \"##tf\": 24475,\n      \"republished\": 24476,\n      \"bolshevik\": 24477,\n      \"refurbishment\": 24478,\n      \"antibiotics\": 24479,\n      \"martini\": 24480,\n      \"methane\": 24481,\n      \"newscasts\": 24482,\n      \"royale\": 24483,\n      \"horizons\": 24484,\n      \"levant\": 24485,\n      \"iain\": 24486,\n      \"visas\": 24487,\n      \"##ischen\": 24488,\n      \"paler\": 24489,\n      \"##around\": 24490,\n      \"manifestation\": 24491,\n      \"snuck\": 24492,\n      \"alf\": 24493,\n      \"chop\": 24494,\n      \"futile\": 24495,\n      \"pedestal\": 24496,\n      \"rehab\": 24497,\n      \"##kat\": 24498,\n      \"bmg\": 24499,\n      \"kerman\": 24500,\n      \"res\": 24501,\n      \"fairbanks\": 24502,\n      \"jarrett\": 24503,\n      \"abstraction\": 24504,\n      \"saharan\": 24505,\n      \"##zek\": 24506,\n      \"1746\": 24507,\n      \"procedural\": 24508,\n      \"clearer\": 24509,\n      \"kincaid\": 24510,\n      \"sash\": 24511,\n      \"luciano\": 24512,\n      \"##ffey\": 24513,\n      \"crunch\": 24514,\n      \"helmut\": 24515,\n      \"##vara\": 24516,\n      \"revolutionaries\": 24517,\n      \"##tute\": 24518,\n      \"creamy\": 24519,\n      \"leach\": 24520,\n      \"##mmon\": 24521,\n      \"1747\": 24522,\n      \"permitting\": 24523,\n      \"nes\": 24524,\n      \"plight\": 24525,\n      \"wendell\": 24526,\n      \"##lese\": 24527,\n      \"contra\": 24528,\n      \"ts\": 24529,\n      \"clancy\": 24530,\n      \"ipa\": 24531,\n      \"mach\": 24532,\n      \"staples\": 24533,\n      \"autopsy\": 24534,\n      \"disturbances\": 24535,\n      \"nueva\": 24536,\n      \"karin\": 24537,\n      \"pontiac\": 24538,\n      \"##uding\": 24539,\n      \"proxy\": 24540,\n      \"venerable\": 24541,\n      \"haunt\": 24542,\n      \"leto\": 24543,\n      \"bergman\": 24544,\n      \"expands\": 24545,\n      \"##helm\": 24546,\n      \"wal\": 24547,\n      \"##pipe\": 24548,\n      \"canning\": 24549,\n      \"celine\": 24550,\n      \"cords\": 24551,\n      \"obesity\": 24552,\n      \"##enary\": 24553,\n      \"intrusion\": 24554,\n      \"planner\": 24555,\n      \"##phate\": 24556,\n      \"reasoned\": 24557,\n      \"sequencing\": 24558,\n      \"307\": 24559,\n      \"harrow\": 24560,\n      \"##chon\": 24561,\n      \"##dora\": 24562,\n      \"marred\": 24563,\n      \"mcintyre\": 24564,\n      \"repay\": 24565,\n      \"tarzan\": 24566,\n      \"darting\": 24567,\n      \"248\": 24568,\n      \"harrisburg\": 24569,\n      \"margarita\": 24570,\n      \"repulsed\": 24571,\n      \"##hur\": 24572,\n      \"##lding\": 24573,\n      \"belinda\": 24574,\n      \"hamburger\": 24575,\n      \"novo\": 24576,\n      \"compliant\": 24577,\n      \"runways\": 24578,\n      \"bingham\": 24579,\n      \"registrar\": 24580,\n      \"skyscraper\": 24581,\n      \"ic\": 24582,\n      \"cuthbert\": 24583,\n      \"improvisation\": 24584,\n      \"livelihood\": 24585,\n      \"##corp\": 24586,\n      \"##elial\": 24587,\n      \"admiring\": 24588,\n      \"##dened\": 24589,\n      \"sporadic\": 24590,\n      \"believer\": 24591,\n      \"casablanca\": 24592,\n      \"popcorn\": 24593,\n      \"##29\": 24594,\n      \"asha\": 24595,\n      \"shovel\": 24596,\n      \"##bek\": 24597,\n      \"##dice\": 24598,\n      \"coiled\": 24599,\n      \"tangible\": 24600,\n      \"##dez\": 24601,\n      \"casper\": 24602,\n      \"elsie\": 24603,\n      \"resin\": 24604,\n      \"tenderness\": 24605,\n      \"rectory\": 24606,\n      \"##ivision\": 24607,\n      \"avail\": 24608,\n      \"sonar\": 24609,\n      \"##mori\": 24610,\n      \"boutique\": 24611,\n      \"##dier\": 24612,\n      \"guerre\": 24613,\n      \"bathed\": 24614,\n      \"upbringing\": 24615,\n      \"vaulted\": 24616,\n      \"sandals\": 24617,\n      \"blessings\": 24618,\n      \"##naut\": 24619,\n      \"##utnant\": 24620,\n      \"1680\": 24621,\n      \"306\": 24622,\n      \"foxes\": 24623,\n      \"pia\": 24624,\n      \"corrosion\": 24625,\n      \"hesitantly\": 24626,\n      \"confederates\": 24627,\n      \"crystalline\": 24628,\n      \"footprints\": 24629,\n      \"shapiro\": 24630,\n      \"tirana\": 24631,\n      \"valentin\": 24632,\n      \"drones\": 24633,\n      \"45th\": 24634,\n      \"microscope\": 24635,\n      \"shipments\": 24636,\n      \"texted\": 24637,\n      \"inquisition\": 24638,\n      \"wry\": 24639,\n      \"guernsey\": 24640,\n      \"unauthorized\": 24641,\n      \"resigning\": 24642,\n      \"760\": 24643,\n      \"ripple\": 24644,\n      \"schubert\": 24645,\n      \"stu\": 24646,\n      \"reassure\": 24647,\n      \"felony\": 24648,\n      \"##ardo\": 24649,\n      \"brittle\": 24650,\n      \"koreans\": 24651,\n      \"##havan\": 24652,\n      \"##ives\": 24653,\n      \"dun\": 24654,\n      \"implicit\": 24655,\n      \"tyres\": 24656,\n      \"##aldi\": 24657,\n      \"##lth\": 24658,\n      \"magnolia\": 24659,\n      \"##ehan\": 24660,\n      \"##puri\": 24661,\n      \"##poulos\": 24662,\n      \"aggressively\": 24663,\n      \"fei\": 24664,\n      \"gr\": 24665,\n      \"familiarity\": 24666,\n      \"##poo\": 24667,\n      \"indicative\": 24668,\n      \"##trust\": 24669,\n      \"fundamentally\": 24670,\n      \"jimmie\": 24671,\n      \"overrun\": 24672,\n      \"395\": 24673,\n      \"anchors\": 24674,\n      \"moans\": 24675,\n      \"##opus\": 24676,\n      \"britannia\": 24677,\n      \"armagh\": 24678,\n      \"##ggle\": 24679,\n      \"purposely\": 24680,\n      \"seizing\": 24681,\n      \"##vao\": 24682,\n      \"bewildered\": 24683,\n      \"mundane\": 24684,\n      \"avoidance\": 24685,\n      \"cosmopolitan\": 24686,\n      \"geometridae\": 24687,\n      \"quartermaster\": 24688,\n      \"caf\": 24689,\n      \"415\": 24690,\n      \"chatter\": 24691,\n      \"engulfed\": 24692,\n      \"gleam\": 24693,\n      \"purge\": 24694,\n      \"##icate\": 24695,\n      \"juliette\": 24696,\n      \"jurisprudence\": 24697,\n      \"guerra\": 24698,\n      \"revisions\": 24699,\n      \"##bn\": 24700,\n      \"casimir\": 24701,\n      \"brew\": 24702,\n      \"##jm\": 24703,\n      \"1749\": 24704,\n      \"clapton\": 24705,\n      \"cloudy\": 24706,\n      \"conde\": 24707,\n      \"hermitage\": 24708,\n      \"278\": 24709,\n      \"simulations\": 24710,\n      \"torches\": 24711,\n      \"vincenzo\": 24712,\n      \"matteo\": 24713,\n      \"##rill\": 24714,\n      \"hidalgo\": 24715,\n      \"booming\": 24716,\n      \"westbound\": 24717,\n      \"accomplishment\": 24718,\n      \"tentacles\": 24719,\n      \"unaffected\": 24720,\n      \"##sius\": 24721,\n      \"annabelle\": 24722,\n      \"flopped\": 24723,\n      \"sloping\": 24724,\n      \"##litz\": 24725,\n      \"dreamer\": 24726,\n      \"interceptor\": 24727,\n      \"vu\": 24728,\n      \"##loh\": 24729,\n      \"consecration\": 24730,\n      \"copying\": 24731,\n      \"messaging\": 24732,\n      \"breaker\": 24733,\n      \"climates\": 24734,\n      \"hospitalized\": 24735,\n      \"1752\": 24736,\n      \"torino\": 24737,\n      \"afternoons\": 24738,\n      \"winfield\": 24739,\n      \"witnessing\": 24740,\n      \"##teacher\": 24741,\n      \"breakers\": 24742,\n      \"choirs\": 24743,\n      \"sawmill\": 24744,\n      \"coldly\": 24745,\n      \"##ege\": 24746,\n      \"sipping\": 24747,\n      \"haste\": 24748,\n      \"uninhabited\": 24749,\n      \"conical\": 24750,\n      \"bibliography\": 24751,\n      \"pamphlets\": 24752,\n      \"severn\": 24753,\n      \"edict\": 24754,\n      \"##oca\": 24755,\n      \"deux\": 24756,\n      \"illnesses\": 24757,\n      \"grips\": 24758,\n      \"##pl\": 24759,\n      \"rehearsals\": 24760,\n      \"sis\": 24761,\n      \"thinkers\": 24762,\n      \"tame\": 24763,\n      \"##keepers\": 24764,\n      \"1690\": 24765,\n      \"acacia\": 24766,\n      \"reformer\": 24767,\n      \"##osed\": 24768,\n      \"##rys\": 24769,\n      \"shuffling\": 24770,\n      \"##iring\": 24771,\n      \"##shima\": 24772,\n      \"eastbound\": 24773,\n      \"ionic\": 24774,\n      \"rhea\": 24775,\n      \"flees\": 24776,\n      \"littered\": 24777,\n      \"##oum\": 24778,\n      \"rocker\": 24779,\n      \"vomiting\": 24780,\n      \"groaning\": 24781,\n      \"champ\": 24782,\n      \"overwhelmingly\": 24783,\n      \"civilizations\": 24784,\n      \"paces\": 24785,\n      \"sloop\": 24786,\n      \"adoptive\": 24787,\n      \"##tish\": 24788,\n      \"skaters\": 24789,\n      \"##vres\": 24790,\n      \"aiding\": 24791,\n      \"mango\": 24792,\n      \"##joy\": 24793,\n      \"nikola\": 24794,\n      \"shriek\": 24795,\n      \"##ignon\": 24796,\n      \"pharmaceuticals\": 24797,\n      \"##mg\": 24798,\n      \"tuna\": 24799,\n      \"calvert\": 24800,\n      \"gustavo\": 24801,\n      \"stocked\": 24802,\n      \"yearbook\": 24803,\n      \"##urai\": 24804,\n      \"##mana\": 24805,\n      \"computed\": 24806,\n      \"subsp\": 24807,\n      \"riff\": 24808,\n      \"hanoi\": 24809,\n      \"kelvin\": 24810,\n      \"hamid\": 24811,\n      \"moors\": 24812,\n      \"pastures\": 24813,\n      \"summons\": 24814,\n      \"jihad\": 24815,\n      \"nectar\": 24816,\n      \"##ctors\": 24817,\n      \"bayou\": 24818,\n      \"untitled\": 24819,\n      \"pleasing\": 24820,\n      \"vastly\": 24821,\n      \"republics\": 24822,\n      \"intellect\": 24823,\n      \"##η\": 24824,\n      \"##ulio\": 24825,\n      \"##tou\": 24826,\n      \"crumbling\": 24827,\n      \"stylistic\": 24828,\n      \"sb\": 24829,\n      \"##ی\": 24830,\n      \"consolation\": 24831,\n      \"frequented\": 24832,\n      \"h₂o\": 24833,\n      \"walden\": 24834,\n      \"widows\": 24835,\n      \"##iens\": 24836,\n      \"404\": 24837,\n      \"##ignment\": 24838,\n      \"chunks\": 24839,\n      \"improves\": 24840,\n      \"288\": 24841,\n      \"grit\": 24842,\n      \"recited\": 24843,\n      \"##dev\": 24844,\n      \"snarl\": 24845,\n      \"sociological\": 24846,\n      \"##arte\": 24847,\n      \"##gul\": 24848,\n      \"inquired\": 24849,\n      \"##held\": 24850,\n      \"bruise\": 24851,\n      \"clube\": 24852,\n      \"consultancy\": 24853,\n      \"homogeneous\": 24854,\n      \"hornets\": 24855,\n      \"multiplication\": 24856,\n      \"pasta\": 24857,\n      \"prick\": 24858,\n      \"savior\": 24859,\n      \"##grin\": 24860,\n      \"##kou\": 24861,\n      \"##phile\": 24862,\n      \"yoon\": 24863,\n      \"##gara\": 24864,\n      \"grimes\": 24865,\n      \"vanishing\": 24866,\n      \"cheering\": 24867,\n      \"reacting\": 24868,\n      \"bn\": 24869,\n      \"distillery\": 24870,\n      \"##quisite\": 24871,\n      \"##vity\": 24872,\n      \"coe\": 24873,\n      \"dockyard\": 24874,\n      \"massif\": 24875,\n      \"##jord\": 24876,\n      \"escorts\": 24877,\n      \"voss\": 24878,\n      \"##valent\": 24879,\n      \"byte\": 24880,\n      \"chopped\": 24881,\n      \"hawke\": 24882,\n      \"illusions\": 24883,\n      \"workings\": 24884,\n      \"floats\": 24885,\n      \"##koto\": 24886,\n      \"##vac\": 24887,\n      \"kv\": 24888,\n      \"annapolis\": 24889,\n      \"madden\": 24890,\n      \"##onus\": 24891,\n      \"alvaro\": 24892,\n      \"noctuidae\": 24893,\n      \"##cum\": 24894,\n      \"##scopic\": 24895,\n      \"avenge\": 24896,\n      \"steamboat\": 24897,\n      \"forte\": 24898,\n      \"illustrates\": 24899,\n      \"erika\": 24900,\n      \"##trip\": 24901,\n      \"570\": 24902,\n      \"dew\": 24903,\n      \"nationalities\": 24904,\n      \"bran\": 24905,\n      \"manifested\": 24906,\n      \"thirsty\": 24907,\n      \"diversified\": 24908,\n      \"muscled\": 24909,\n      \"reborn\": 24910,\n      \"##standing\": 24911,\n      \"arson\": 24912,\n      \"##lessness\": 24913,\n      \"##dran\": 24914,\n      \"##logram\": 24915,\n      \"##boys\": 24916,\n      \"##kushima\": 24917,\n      \"##vious\": 24918,\n      \"willoughby\": 24919,\n      \"##phobia\": 24920,\n      \"286\": 24921,\n      \"alsace\": 24922,\n      \"dashboard\": 24923,\n      \"yuki\": 24924,\n      \"##chai\": 24925,\n      \"granville\": 24926,\n      \"myspace\": 24927,\n      \"publicized\": 24928,\n      \"tricked\": 24929,\n      \"##gang\": 24930,\n      \"adjective\": 24931,\n      \"##ater\": 24932,\n      \"relic\": 24933,\n      \"reorganisation\": 24934,\n      \"enthusiastically\": 24935,\n      \"indications\": 24936,\n      \"saxe\": 24937,\n      \"##lassified\": 24938,\n      \"consolidate\": 24939,\n      \"iec\": 24940,\n      \"padua\": 24941,\n      \"helplessly\": 24942,\n      \"ramps\": 24943,\n      \"renaming\": 24944,\n      \"regulars\": 24945,\n      \"pedestrians\": 24946,\n      \"accents\": 24947,\n      \"convicts\": 24948,\n      \"inaccurate\": 24949,\n      \"lowers\": 24950,\n      \"mana\": 24951,\n      \"##pati\": 24952,\n      \"barrie\": 24953,\n      \"bjp\": 24954,\n      \"outta\": 24955,\n      \"someplace\": 24956,\n      \"berwick\": 24957,\n      \"flanking\": 24958,\n      \"invoked\": 24959,\n      \"marrow\": 24960,\n      \"sparsely\": 24961,\n      \"excerpts\": 24962,\n      \"clothed\": 24963,\n      \"rei\": 24964,\n      \"##ginal\": 24965,\n      \"wept\": 24966,\n      \"##straße\": 24967,\n      \"##vish\": 24968,\n      \"alexa\": 24969,\n      \"excel\": 24970,\n      \"##ptive\": 24971,\n      \"membranes\": 24972,\n      \"aquitaine\": 24973,\n      \"creeks\": 24974,\n      \"cutler\": 24975,\n      \"sheppard\": 24976,\n      \"implementations\": 24977,\n      \"ns\": 24978,\n      \"##dur\": 24979,\n      \"fragrance\": 24980,\n      \"budge\": 24981,\n      \"concordia\": 24982,\n      \"magnesium\": 24983,\n      \"marcelo\": 24984,\n      \"##antes\": 24985,\n      \"gladly\": 24986,\n      \"vibrating\": 24987,\n      \"##rral\": 24988,\n      \"##ggles\": 24989,\n      \"montrose\": 24990,\n      \"##omba\": 24991,\n      \"lew\": 24992,\n      \"seamus\": 24993,\n      \"1630\": 24994,\n      \"cocky\": 24995,\n      \"##ament\": 24996,\n      \"##uen\": 24997,\n      \"bjorn\": 24998,\n      \"##rrick\": 24999,\n      \"fielder\": 25000,\n      \"fluttering\": 25001,\n      \"##lase\": 25002,\n      \"methyl\": 25003,\n      \"kimberley\": 25004,\n      \"mcdowell\": 25005,\n      \"reductions\": 25006,\n      \"barbed\": 25007,\n      \"##jic\": 25008,\n      \"##tonic\": 25009,\n      \"aeronautical\": 25010,\n      \"condensed\": 25011,\n      \"distracting\": 25012,\n      \"##promising\": 25013,\n      \"huffed\": 25014,\n      \"##cala\": 25015,\n      \"##sle\": 25016,\n      \"claudius\": 25017,\n      \"invincible\": 25018,\n      \"missy\": 25019,\n      \"pious\": 25020,\n      \"balthazar\": 25021,\n      \"ci\": 25022,\n      \"##lang\": 25023,\n      \"butte\": 25024,\n      \"combo\": 25025,\n      \"orson\": 25026,\n      \"##dication\": 25027,\n      \"myriad\": 25028,\n      \"1707\": 25029,\n      \"silenced\": 25030,\n      \"##fed\": 25031,\n      \"##rh\": 25032,\n      \"coco\": 25033,\n      \"netball\": 25034,\n      \"yourselves\": 25035,\n      \"##oza\": 25036,\n      \"clarify\": 25037,\n      \"heller\": 25038,\n      \"peg\": 25039,\n      \"durban\": 25040,\n      \"etudes\": 25041,\n      \"offender\": 25042,\n      \"roast\": 25043,\n      \"blackmail\": 25044,\n      \"curvature\": 25045,\n      \"##woods\": 25046,\n      \"vile\": 25047,\n      \"309\": 25048,\n      \"illicit\": 25049,\n      \"suriname\": 25050,\n      \"##linson\": 25051,\n      \"overture\": 25052,\n      \"1685\": 25053,\n      \"bubbling\": 25054,\n      \"gymnast\": 25055,\n      \"tucking\": 25056,\n      \"##mming\": 25057,\n      \"##ouin\": 25058,\n      \"maldives\": 25059,\n      \"##bala\": 25060,\n      \"gurney\": 25061,\n      \"##dda\": 25062,\n      \"##eased\": 25063,\n      \"##oides\": 25064,\n      \"backside\": 25065,\n      \"pinto\": 25066,\n      \"jars\": 25067,\n      \"racehorse\": 25068,\n      \"tending\": 25069,\n      \"##rdial\": 25070,\n      \"baronetcy\": 25071,\n      \"wiener\": 25072,\n      \"duly\": 25073,\n      \"##rke\": 25074,\n      \"barbarian\": 25075,\n      \"cupping\": 25076,\n      \"flawed\": 25077,\n      \"##thesis\": 25078,\n      \"bertha\": 25079,\n      \"pleistocene\": 25080,\n      \"puddle\": 25081,\n      \"swearing\": 25082,\n      \"##nob\": 25083,\n      \"##tically\": 25084,\n      \"fleeting\": 25085,\n      \"prostate\": 25086,\n      \"amulet\": 25087,\n      \"educating\": 25088,\n      \"##mined\": 25089,\n      \"##iti\": 25090,\n      \"##tler\": 25091,\n      \"75th\": 25092,\n      \"jens\": 25093,\n      \"respondents\": 25094,\n      \"analytics\": 25095,\n      \"cavaliers\": 25096,\n      \"papacy\": 25097,\n      \"raju\": 25098,\n      \"##iente\": 25099,\n      \"##ulum\": 25100,\n      \"##tip\": 25101,\n      \"funnel\": 25102,\n      \"271\": 25103,\n      \"disneyland\": 25104,\n      \"##lley\": 25105,\n      \"sociologist\": 25106,\n      \"##iam\": 25107,\n      \"2500\": 25108,\n      \"faulkner\": 25109,\n      \"louvre\": 25110,\n      \"menon\": 25111,\n      \"##dson\": 25112,\n      \"276\": 25113,\n      \"##ower\": 25114,\n      \"afterlife\": 25115,\n      \"mannheim\": 25116,\n      \"peptide\": 25117,\n      \"referees\": 25118,\n      \"comedians\": 25119,\n      \"meaningless\": 25120,\n      \"##anger\": 25121,\n      \"##laise\": 25122,\n      \"fabrics\": 25123,\n      \"hurley\": 25124,\n      \"renal\": 25125,\n      \"sleeps\": 25126,\n      \"##bour\": 25127,\n      \"##icle\": 25128,\n      \"breakout\": 25129,\n      \"kristin\": 25130,\n      \"roadside\": 25131,\n      \"animator\": 25132,\n      \"clover\": 25133,\n      \"disdain\": 25134,\n      \"unsafe\": 25135,\n      \"redesign\": 25136,\n      \"##urity\": 25137,\n      \"firth\": 25138,\n      \"barnsley\": 25139,\n      \"portage\": 25140,\n      \"reset\": 25141,\n      \"narrows\": 25142,\n      \"268\": 25143,\n      \"commandos\": 25144,\n      \"expansive\": 25145,\n      \"speechless\": 25146,\n      \"tubular\": 25147,\n      \"##lux\": 25148,\n      \"essendon\": 25149,\n      \"eyelashes\": 25150,\n      \"smashwords\": 25151,\n      \"##yad\": 25152,\n      \"##bang\": 25153,\n      \"##claim\": 25154,\n      \"craved\": 25155,\n      \"sprinted\": 25156,\n      \"chet\": 25157,\n      \"somme\": 25158,\n      \"astor\": 25159,\n      \"wrocław\": 25160,\n      \"orton\": 25161,\n      \"266\": 25162,\n      \"bane\": 25163,\n      \"##erving\": 25164,\n      \"##uing\": 25165,\n      \"mischief\": 25166,\n      \"##amps\": 25167,\n      \"##sund\": 25168,\n      \"scaling\": 25169,\n      \"terre\": 25170,\n      \"##xious\": 25171,\n      \"impairment\": 25172,\n      \"offenses\": 25173,\n      \"undermine\": 25174,\n      \"moi\": 25175,\n      \"soy\": 25176,\n      \"contiguous\": 25177,\n      \"arcadia\": 25178,\n      \"inuit\": 25179,\n      \"seam\": 25180,\n      \"##tops\": 25181,\n      \"macbeth\": 25182,\n      \"rebelled\": 25183,\n      \"##icative\": 25184,\n      \"##iot\": 25185,\n      \"590\": 25186,\n      \"elaborated\": 25187,\n      \"frs\": 25188,\n      \"uniformed\": 25189,\n      \"##dberg\": 25190,\n      \"259\": 25191,\n      \"powerless\": 25192,\n      \"priscilla\": 25193,\n      \"stimulated\": 25194,\n      \"980\": 25195,\n      \"qc\": 25196,\n      \"arboretum\": 25197,\n      \"frustrating\": 25198,\n      \"trieste\": 25199,\n      \"bullock\": 25200,\n      \"##nified\": 25201,\n      \"enriched\": 25202,\n      \"glistening\": 25203,\n      \"intern\": 25204,\n      \"##adia\": 25205,\n      \"locus\": 25206,\n      \"nouvelle\": 25207,\n      \"ollie\": 25208,\n      \"ike\": 25209,\n      \"lash\": 25210,\n      \"starboard\": 25211,\n      \"ee\": 25212,\n      \"tapestry\": 25213,\n      \"headlined\": 25214,\n      \"hove\": 25215,\n      \"rigged\": 25216,\n      \"##vite\": 25217,\n      \"pollock\": 25218,\n      \"##yme\": 25219,\n      \"thrive\": 25220,\n      \"clustered\": 25221,\n      \"cas\": 25222,\n      \"roi\": 25223,\n      \"gleamed\": 25224,\n      \"olympiad\": 25225,\n      \"##lino\": 25226,\n      \"pressured\": 25227,\n      \"regimes\": 25228,\n      \"##hosis\": 25229,\n      \"##lick\": 25230,\n      \"ripley\": 25231,\n      \"##ophone\": 25232,\n      \"kickoff\": 25233,\n      \"gallon\": 25234,\n      \"rockwell\": 25235,\n      \"##arable\": 25236,\n      \"crusader\": 25237,\n      \"glue\": 25238,\n      \"revolutions\": 25239,\n      \"scrambling\": 25240,\n      \"1714\": 25241,\n      \"grover\": 25242,\n      \"##jure\": 25243,\n      \"englishman\": 25244,\n      \"aztec\": 25245,\n      \"263\": 25246,\n      \"contemplating\": 25247,\n      \"coven\": 25248,\n      \"ipad\": 25249,\n      \"preach\": 25250,\n      \"triumphant\": 25251,\n      \"tufts\": 25252,\n      \"##esian\": 25253,\n      \"rotational\": 25254,\n      \"##phus\": 25255,\n      \"328\": 25256,\n      \"falkland\": 25257,\n      \"##brates\": 25258,\n      \"strewn\": 25259,\n      \"clarissa\": 25260,\n      \"rejoin\": 25261,\n      \"environmentally\": 25262,\n      \"glint\": 25263,\n      \"banded\": 25264,\n      \"drenched\": 25265,\n      \"moat\": 25266,\n      \"albanians\": 25267,\n      \"johor\": 25268,\n      \"rr\": 25269,\n      \"maestro\": 25270,\n      \"malley\": 25271,\n      \"nouveau\": 25272,\n      \"shaded\": 25273,\n      \"taxonomy\": 25274,\n      \"v6\": 25275,\n      \"adhere\": 25276,\n      \"bunk\": 25277,\n      \"airfields\": 25278,\n      \"##ritan\": 25279,\n      \"1741\": 25280,\n      \"encompass\": 25281,\n      \"remington\": 25282,\n      \"tran\": 25283,\n      \"##erative\": 25284,\n      \"amelie\": 25285,\n      \"mazda\": 25286,\n      \"friar\": 25287,\n      \"morals\": 25288,\n      \"passions\": 25289,\n      \"##zai\": 25290,\n      \"breadth\": 25291,\n      \"vis\": 25292,\n      \"##hae\": 25293,\n      \"argus\": 25294,\n      \"burnham\": 25295,\n      \"caressing\": 25296,\n      \"insider\": 25297,\n      \"rudd\": 25298,\n      \"##imov\": 25299,\n      \"##mini\": 25300,\n      \"##rso\": 25301,\n      \"italianate\": 25302,\n      \"murderous\": 25303,\n      \"textual\": 25304,\n      \"wainwright\": 25305,\n      \"armada\": 25306,\n      \"bam\": 25307,\n      \"weave\": 25308,\n      \"timer\": 25309,\n      \"##taken\": 25310,\n      \"##nh\": 25311,\n      \"fra\": 25312,\n      \"##crest\": 25313,\n      \"ardent\": 25314,\n      \"salazar\": 25315,\n      \"taps\": 25316,\n      \"tunis\": 25317,\n      \"##ntino\": 25318,\n      \"allegro\": 25319,\n      \"gland\": 25320,\n      \"philanthropic\": 25321,\n      \"##chester\": 25322,\n      \"implication\": 25323,\n      \"##optera\": 25324,\n      \"esq\": 25325,\n      \"judas\": 25326,\n      \"noticeably\": 25327,\n      \"wynn\": 25328,\n      \"##dara\": 25329,\n      \"inched\": 25330,\n      \"indexed\": 25331,\n      \"crises\": 25332,\n      \"villiers\": 25333,\n      \"bandit\": 25334,\n      \"royalties\": 25335,\n      \"patterned\": 25336,\n      \"cupboard\": 25337,\n      \"interspersed\": 25338,\n      \"accessory\": 25339,\n      \"isla\": 25340,\n      \"kendrick\": 25341,\n      \"entourage\": 25342,\n      \"stitches\": 25343,\n      \"##esthesia\": 25344,\n      \"headwaters\": 25345,\n      \"##ior\": 25346,\n      \"interlude\": 25347,\n      \"distraught\": 25348,\n      \"draught\": 25349,\n      \"1727\": 25350,\n      \"##basket\": 25351,\n      \"biased\": 25352,\n      \"sy\": 25353,\n      \"transient\": 25354,\n      \"triad\": 25355,\n      \"subgenus\": 25356,\n      \"adapting\": 25357,\n      \"kidd\": 25358,\n      \"shortstop\": 25359,\n      \"##umatic\": 25360,\n      \"dimly\": 25361,\n      \"spiked\": 25362,\n      \"mcleod\": 25363,\n      \"reprint\": 25364,\n      \"nellie\": 25365,\n      \"pretoria\": 25366,\n      \"windmill\": 25367,\n      \"##cek\": 25368,\n      \"singled\": 25369,\n      \"##mps\": 25370,\n      \"273\": 25371,\n      \"reunite\": 25372,\n      \"##orous\": 25373,\n      \"747\": 25374,\n      \"bankers\": 25375,\n      \"outlying\": 25376,\n      \"##omp\": 25377,\n      \"##ports\": 25378,\n      \"##tream\": 25379,\n      \"apologies\": 25380,\n      \"cosmetics\": 25381,\n      \"patsy\": 25382,\n      \"##deh\": 25383,\n      \"##ocks\": 25384,\n      \"##yson\": 25385,\n      \"bender\": 25386,\n      \"nantes\": 25387,\n      \"serene\": 25388,\n      \"##nad\": 25389,\n      \"lucha\": 25390,\n      \"mmm\": 25391,\n      \"323\": 25392,\n      \"##cius\": 25393,\n      \"##gli\": 25394,\n      \"cmll\": 25395,\n      \"coinage\": 25396,\n      \"nestor\": 25397,\n      \"juarez\": 25398,\n      \"##rook\": 25399,\n      \"smeared\": 25400,\n      \"sprayed\": 25401,\n      \"twitching\": 25402,\n      \"sterile\": 25403,\n      \"irina\": 25404,\n      \"embodied\": 25405,\n      \"juveniles\": 25406,\n      \"enveloped\": 25407,\n      \"miscellaneous\": 25408,\n      \"cancers\": 25409,\n      \"dq\": 25410,\n      \"gulped\": 25411,\n      \"luisa\": 25412,\n      \"crested\": 25413,\n      \"swat\": 25414,\n      \"donegal\": 25415,\n      \"ref\": 25416,\n      \"##anov\": 25417,\n      \"##acker\": 25418,\n      \"hearst\": 25419,\n      \"mercantile\": 25420,\n      \"##lika\": 25421,\n      \"doorbell\": 25422,\n      \"ua\": 25423,\n      \"vicki\": 25424,\n      \"##alla\": 25425,\n      \"##som\": 25426,\n      \"bilbao\": 25427,\n      \"psychologists\": 25428,\n      \"stryker\": 25429,\n      \"sw\": 25430,\n      \"horsemen\": 25431,\n      \"turkmenistan\": 25432,\n      \"wits\": 25433,\n      \"##national\": 25434,\n      \"anson\": 25435,\n      \"mathew\": 25436,\n      \"screenings\": 25437,\n      \"##umb\": 25438,\n      \"rihanna\": 25439,\n      \"##agne\": 25440,\n      \"##nessy\": 25441,\n      \"aisles\": 25442,\n      \"##iani\": 25443,\n      \"##osphere\": 25444,\n      \"hines\": 25445,\n      \"kenton\": 25446,\n      \"saskatoon\": 25447,\n      \"tasha\": 25448,\n      \"truncated\": 25449,\n      \"##champ\": 25450,\n      \"##itan\": 25451,\n      \"mildred\": 25452,\n      \"advises\": 25453,\n      \"fredrik\": 25454,\n      \"interpreting\": 25455,\n      \"inhibitors\": 25456,\n      \"##athi\": 25457,\n      \"spectroscopy\": 25458,\n      \"##hab\": 25459,\n      \"##kong\": 25460,\n      \"karim\": 25461,\n      \"panda\": 25462,\n      \"##oia\": 25463,\n      \"##nail\": 25464,\n      \"##vc\": 25465,\n      \"conqueror\": 25466,\n      \"kgb\": 25467,\n      \"leukemia\": 25468,\n      \"##dity\": 25469,\n      \"arrivals\": 25470,\n      \"cheered\": 25471,\n      \"pisa\": 25472,\n      \"phosphorus\": 25473,\n      \"shielded\": 25474,\n      \"##riated\": 25475,\n      \"mammal\": 25476,\n      \"unitarian\": 25477,\n      \"urgently\": 25478,\n      \"chopin\": 25479,\n      \"sanitary\": 25480,\n      \"##mission\": 25481,\n      \"spicy\": 25482,\n      \"drugged\": 25483,\n      \"hinges\": 25484,\n      \"##tort\": 25485,\n      \"tipping\": 25486,\n      \"trier\": 25487,\n      \"impoverished\": 25488,\n      \"westchester\": 25489,\n      \"##caster\": 25490,\n      \"267\": 25491,\n      \"epoch\": 25492,\n      \"nonstop\": 25493,\n      \"##gman\": 25494,\n      \"##khov\": 25495,\n      \"aromatic\": 25496,\n      \"centrally\": 25497,\n      \"cerro\": 25498,\n      \"##tively\": 25499,\n      \"##vio\": 25500,\n      \"billions\": 25501,\n      \"modulation\": 25502,\n      \"sedimentary\": 25503,\n      \"283\": 25504,\n      \"facilitating\": 25505,\n      \"outrageous\": 25506,\n      \"goldstein\": 25507,\n      \"##eak\": 25508,\n      \"##kt\": 25509,\n      \"ld\": 25510,\n      \"maitland\": 25511,\n      \"penultimate\": 25512,\n      \"pollard\": 25513,\n      \"##dance\": 25514,\n      \"fleets\": 25515,\n      \"spaceship\": 25516,\n      \"vertebrae\": 25517,\n      \"##nig\": 25518,\n      \"alcoholism\": 25519,\n      \"als\": 25520,\n      \"recital\": 25521,\n      \"##bham\": 25522,\n      \"##ference\": 25523,\n      \"##omics\": 25524,\n      \"m2\": 25525,\n      \"##bm\": 25526,\n      \"trois\": 25527,\n      \"##tropical\": 25528,\n      \"##в\": 25529,\n      \"commemorates\": 25530,\n      \"##meric\": 25531,\n      \"marge\": 25532,\n      \"##raction\": 25533,\n      \"1643\": 25534,\n      \"670\": 25535,\n      \"cosmetic\": 25536,\n      \"ravaged\": 25537,\n      \"##ige\": 25538,\n      \"catastrophe\": 25539,\n      \"eng\": 25540,\n      \"##shida\": 25541,\n      \"albrecht\": 25542,\n      \"arterial\": 25543,\n      \"bellamy\": 25544,\n      \"decor\": 25545,\n      \"harmon\": 25546,\n      \"##rde\": 25547,\n      \"bulbs\": 25548,\n      \"synchronized\": 25549,\n      \"vito\": 25550,\n      \"easiest\": 25551,\n      \"shetland\": 25552,\n      \"shielding\": 25553,\n      \"wnba\": 25554,\n      \"##glers\": 25555,\n      \"##ssar\": 25556,\n      \"##riam\": 25557,\n      \"brianna\": 25558,\n      \"cumbria\": 25559,\n      \"##aceous\": 25560,\n      \"##rard\": 25561,\n      \"cores\": 25562,\n      \"thayer\": 25563,\n      \"##nsk\": 25564,\n      \"brood\": 25565,\n      \"hilltop\": 25566,\n      \"luminous\": 25567,\n      \"carts\": 25568,\n      \"keynote\": 25569,\n      \"larkin\": 25570,\n      \"logos\": 25571,\n      \"##cta\": 25572,\n      \"##ا\": 25573,\n      \"##mund\": 25574,\n      \"##quay\": 25575,\n      \"lilith\": 25576,\n      \"tinted\": 25577,\n      \"277\": 25578,\n      \"wrestle\": 25579,\n      \"mobilization\": 25580,\n      \"##uses\": 25581,\n      \"sequential\": 25582,\n      \"siam\": 25583,\n      \"bloomfield\": 25584,\n      \"takahashi\": 25585,\n      \"274\": 25586,\n      \"##ieving\": 25587,\n      \"presenters\": 25588,\n      \"ringo\": 25589,\n      \"blazed\": 25590,\n      \"witty\": 25591,\n      \"##oven\": 25592,\n      \"##ignant\": 25593,\n      \"devastation\": 25594,\n      \"haydn\": 25595,\n      \"harmed\": 25596,\n      \"newt\": 25597,\n      \"therese\": 25598,\n      \"##peed\": 25599,\n      \"gershwin\": 25600,\n      \"molina\": 25601,\n      \"rabbis\": 25602,\n      \"sudanese\": 25603,\n      \"001\": 25604,\n      \"innate\": 25605,\n      \"restarted\": 25606,\n      \"##sack\": 25607,\n      \"##fus\": 25608,\n      \"slices\": 25609,\n      \"wb\": 25610,\n      \"##shah\": 25611,\n      \"enroll\": 25612,\n      \"hypothetical\": 25613,\n      \"hysterical\": 25614,\n      \"1743\": 25615,\n      \"fabio\": 25616,\n      \"indefinite\": 25617,\n      \"warped\": 25618,\n      \"##hg\": 25619,\n      \"exchanging\": 25620,\n      \"525\": 25621,\n      \"unsuitable\": 25622,\n      \"##sboro\": 25623,\n      \"gallo\": 25624,\n      \"1603\": 25625,\n      \"bret\": 25626,\n      \"cobalt\": 25627,\n      \"homemade\": 25628,\n      \"##hunter\": 25629,\n      \"mx\": 25630,\n      \"operatives\": 25631,\n      \"##dhar\": 25632,\n      \"terraces\": 25633,\n      \"durable\": 25634,\n      \"latch\": 25635,\n      \"pens\": 25636,\n      \"whorls\": 25637,\n      \"##ctuated\": 25638,\n      \"##eaux\": 25639,\n      \"billing\": 25640,\n      \"ligament\": 25641,\n      \"succumbed\": 25642,\n      \"##gly\": 25643,\n      \"regulators\": 25644,\n      \"spawn\": 25645,\n      \"##brick\": 25646,\n      \"##stead\": 25647,\n      \"filmfare\": 25648,\n      \"rochelle\": 25649,\n      \"##nzo\": 25650,\n      \"1725\": 25651,\n      \"circumstance\": 25652,\n      \"saber\": 25653,\n      \"supplements\": 25654,\n      \"##nsky\": 25655,\n      \"##tson\": 25656,\n      \"crowe\": 25657,\n      \"wellesley\": 25658,\n      \"carrot\": 25659,\n      \"##9th\": 25660,\n      \"##movable\": 25661,\n      \"primate\": 25662,\n      \"drury\": 25663,\n      \"sincerely\": 25664,\n      \"topical\": 25665,\n      \"##mad\": 25666,\n      \"##rao\": 25667,\n      \"callahan\": 25668,\n      \"kyiv\": 25669,\n      \"smarter\": 25670,\n      \"tits\": 25671,\n      \"undo\": 25672,\n      \"##yeh\": 25673,\n      \"announcements\": 25674,\n      \"anthologies\": 25675,\n      \"barrio\": 25676,\n      \"nebula\": 25677,\n      \"##islaus\": 25678,\n      \"##shaft\": 25679,\n      \"##tyn\": 25680,\n      \"bodyguards\": 25681,\n      \"2021\": 25682,\n      \"assassinate\": 25683,\n      \"barns\": 25684,\n      \"emmett\": 25685,\n      \"scully\": 25686,\n      \"##mah\": 25687,\n      \"##yd\": 25688,\n      \"##eland\": 25689,\n      \"##tino\": 25690,\n      \"##itarian\": 25691,\n      \"demoted\": 25692,\n      \"gorman\": 25693,\n      \"lashed\": 25694,\n      \"prized\": 25695,\n      \"adventist\": 25696,\n      \"writ\": 25697,\n      \"##gui\": 25698,\n      \"alla\": 25699,\n      \"invertebrates\": 25700,\n      \"##ausen\": 25701,\n      \"1641\": 25702,\n      \"amman\": 25703,\n      \"1742\": 25704,\n      \"align\": 25705,\n      \"healy\": 25706,\n      \"redistribution\": 25707,\n      \"##gf\": 25708,\n      \"##rize\": 25709,\n      \"insulation\": 25710,\n      \"##drop\": 25711,\n      \"adherents\": 25712,\n      \"hezbollah\": 25713,\n      \"vitro\": 25714,\n      \"ferns\": 25715,\n      \"yanking\": 25716,\n      \"269\": 25717,\n      \"php\": 25718,\n      \"registering\": 25719,\n      \"uppsala\": 25720,\n      \"cheerleading\": 25721,\n      \"confines\": 25722,\n      \"mischievous\": 25723,\n      \"tully\": 25724,\n      \"##ross\": 25725,\n      \"49th\": 25726,\n      \"docked\": 25727,\n      \"roam\": 25728,\n      \"stipulated\": 25729,\n      \"pumpkin\": 25730,\n      \"##bry\": 25731,\n      \"prompt\": 25732,\n      \"##ezer\": 25733,\n      \"blindly\": 25734,\n      \"shuddering\": 25735,\n      \"craftsmen\": 25736,\n      \"frail\": 25737,\n      \"scented\": 25738,\n      \"katharine\": 25739,\n      \"scramble\": 25740,\n      \"shaggy\": 25741,\n      \"sponge\": 25742,\n      \"helix\": 25743,\n      \"zaragoza\": 25744,\n      \"279\": 25745,\n      \"##52\": 25746,\n      \"43rd\": 25747,\n      \"backlash\": 25748,\n      \"fontaine\": 25749,\n      \"seizures\": 25750,\n      \"posse\": 25751,\n      \"cowan\": 25752,\n      \"nonfiction\": 25753,\n      \"telenovela\": 25754,\n      \"wwii\": 25755,\n      \"hammered\": 25756,\n      \"undone\": 25757,\n      \"##gpur\": 25758,\n      \"encircled\": 25759,\n      \"irs\": 25760,\n      \"##ivation\": 25761,\n      \"artefacts\": 25762,\n      \"oneself\": 25763,\n      \"searing\": 25764,\n      \"smallpox\": 25765,\n      \"##belle\": 25766,\n      \"##osaurus\": 25767,\n      \"shandong\": 25768,\n      \"breached\": 25769,\n      \"upland\": 25770,\n      \"blushing\": 25771,\n      \"rankin\": 25772,\n      \"infinitely\": 25773,\n      \"psyche\": 25774,\n      \"tolerated\": 25775,\n      \"docking\": 25776,\n      \"evicted\": 25777,\n      \"##col\": 25778,\n      \"unmarked\": 25779,\n      \"##lving\": 25780,\n      \"gnome\": 25781,\n      \"lettering\": 25782,\n      \"litres\": 25783,\n      \"musique\": 25784,\n      \"##oint\": 25785,\n      \"benevolent\": 25786,\n      \"##jal\": 25787,\n      \"blackened\": 25788,\n      \"##anna\": 25789,\n      \"mccall\": 25790,\n      \"racers\": 25791,\n      \"tingle\": 25792,\n      \"##ocene\": 25793,\n      \"##orestation\": 25794,\n      \"introductions\": 25795,\n      \"radically\": 25796,\n      \"292\": 25797,\n      \"##hiff\": 25798,\n      \"##باد\": 25799,\n      \"1610\": 25800,\n      \"1739\": 25801,\n      \"munchen\": 25802,\n      \"plead\": 25803,\n      \"##nka\": 25804,\n      \"condo\": 25805,\n      \"scissors\": 25806,\n      \"##sight\": 25807,\n      \"##tens\": 25808,\n      \"apprehension\": 25809,\n      \"##cey\": 25810,\n      \"##yin\": 25811,\n      \"hallmark\": 25812,\n      \"watering\": 25813,\n      \"formulas\": 25814,\n      \"sequels\": 25815,\n      \"##llas\": 25816,\n      \"aggravated\": 25817,\n      \"bae\": 25818,\n      \"commencing\": 25819,\n      \"##building\": 25820,\n      \"enfield\": 25821,\n      \"prohibits\": 25822,\n      \"marne\": 25823,\n      \"vedic\": 25824,\n      \"civilized\": 25825,\n      \"euclidean\": 25826,\n      \"jagger\": 25827,\n      \"beforehand\": 25828,\n      \"blasts\": 25829,\n      \"dumont\": 25830,\n      \"##arney\": 25831,\n      \"##nem\": 25832,\n      \"740\": 25833,\n      \"conversions\": 25834,\n      \"hierarchical\": 25835,\n      \"rios\": 25836,\n      \"simulator\": 25837,\n      \"##dya\": 25838,\n      \"##lellan\": 25839,\n      \"hedges\": 25840,\n      \"oleg\": 25841,\n      \"thrusts\": 25842,\n      \"shadowed\": 25843,\n      \"darby\": 25844,\n      \"maximize\": 25845,\n      \"1744\": 25846,\n      \"gregorian\": 25847,\n      \"##nded\": 25848,\n      \"##routed\": 25849,\n      \"sham\": 25850,\n      \"unspecified\": 25851,\n      \"##hog\": 25852,\n      \"emory\": 25853,\n      \"factual\": 25854,\n      \"##smo\": 25855,\n      \"##tp\": 25856,\n      \"fooled\": 25857,\n      \"##rger\": 25858,\n      \"ortega\": 25859,\n      \"wellness\": 25860,\n      \"marlon\": 25861,\n      \"##oton\": 25862,\n      \"##urance\": 25863,\n      \"casket\": 25864,\n      \"keating\": 25865,\n      \"ley\": 25866,\n      \"enclave\": 25867,\n      \"##ayan\": 25868,\n      \"char\": 25869,\n      \"influencing\": 25870,\n      \"jia\": 25871,\n      \"##chenko\": 25872,\n      \"412\": 25873,\n      \"ammonia\": 25874,\n      \"erebidae\": 25875,\n      \"incompatible\": 25876,\n      \"violins\": 25877,\n      \"cornered\": 25878,\n      \"##arat\": 25879,\n      \"grooves\": 25880,\n      \"astronauts\": 25881,\n      \"columbian\": 25882,\n      \"rampant\": 25883,\n      \"fabrication\": 25884,\n      \"kyushu\": 25885,\n      \"mahmud\": 25886,\n      \"vanish\": 25887,\n      \"##dern\": 25888,\n      \"mesopotamia\": 25889,\n      \"##lete\": 25890,\n      \"ict\": 25891,\n      \"##rgen\": 25892,\n      \"caspian\": 25893,\n      \"kenji\": 25894,\n      \"pitted\": 25895,\n      \"##vered\": 25896,\n      \"999\": 25897,\n      \"grimace\": 25898,\n      \"roanoke\": 25899,\n      \"tchaikovsky\": 25900,\n      \"twinned\": 25901,\n      \"##analysis\": 25902,\n      \"##awan\": 25903,\n      \"xinjiang\": 25904,\n      \"arias\": 25905,\n      \"clemson\": 25906,\n      \"kazakh\": 25907,\n      \"sizable\": 25908,\n      \"1662\": 25909,\n      \"##khand\": 25910,\n      \"##vard\": 25911,\n      \"plunge\": 25912,\n      \"tatum\": 25913,\n      \"vittorio\": 25914,\n      \"##nden\": 25915,\n      \"cholera\": 25916,\n      \"##dana\": 25917,\n      \"##oper\": 25918,\n      \"bracing\": 25919,\n      \"indifference\": 25920,\n      \"projectile\": 25921,\n      \"superliga\": 25922,\n      \"##chee\": 25923,\n      \"realises\": 25924,\n      \"upgrading\": 25925,\n      \"299\": 25926,\n      \"porte\": 25927,\n      \"retribution\": 25928,\n      \"##vies\": 25929,\n      \"nk\": 25930,\n      \"stil\": 25931,\n      \"##resses\": 25932,\n      \"ama\": 25933,\n      \"bureaucracy\": 25934,\n      \"blackberry\": 25935,\n      \"bosch\": 25936,\n      \"testosterone\": 25937,\n      \"collapses\": 25938,\n      \"greer\": 25939,\n      \"##pathic\": 25940,\n      \"ioc\": 25941,\n      \"fifties\": 25942,\n      \"malls\": 25943,\n      \"##erved\": 25944,\n      \"bao\": 25945,\n      \"baskets\": 25946,\n      \"adolescents\": 25947,\n      \"siegfried\": 25948,\n      \"##osity\": 25949,\n      \"##tosis\": 25950,\n      \"mantra\": 25951,\n      \"detecting\": 25952,\n      \"existent\": 25953,\n      \"fledgling\": 25954,\n      \"##cchi\": 25955,\n      \"dissatisfied\": 25956,\n      \"gan\": 25957,\n      \"telecommunication\": 25958,\n      \"mingled\": 25959,\n      \"sobbed\": 25960,\n      \"6000\": 25961,\n      \"controversies\": 25962,\n      \"outdated\": 25963,\n      \"taxis\": 25964,\n      \"##raus\": 25965,\n      \"fright\": 25966,\n      \"slams\": 25967,\n      \"##lham\": 25968,\n      \"##fect\": 25969,\n      \"##tten\": 25970,\n      \"detectors\": 25971,\n      \"fetal\": 25972,\n      \"tanned\": 25973,\n      \"##uw\": 25974,\n      \"fray\": 25975,\n      \"goth\": 25976,\n      \"olympian\": 25977,\n      \"skipping\": 25978,\n      \"mandates\": 25979,\n      \"scratches\": 25980,\n      \"sheng\": 25981,\n      \"unspoken\": 25982,\n      \"hyundai\": 25983,\n      \"tracey\": 25984,\n      \"hotspur\": 25985,\n      \"restrictive\": 25986,\n      \"##buch\": 25987,\n      \"americana\": 25988,\n      \"mundo\": 25989,\n      \"##bari\": 25990,\n      \"burroughs\": 25991,\n      \"diva\": 25992,\n      \"vulcan\": 25993,\n      \"##6th\": 25994,\n      \"distinctions\": 25995,\n      \"thumping\": 25996,\n      \"##ngen\": 25997,\n      \"mikey\": 25998,\n      \"sheds\": 25999,\n      \"fide\": 26000,\n      \"rescues\": 26001,\n      \"springsteen\": 26002,\n      \"vested\": 26003,\n      \"valuation\": 26004,\n      \"##ece\": 26005,\n      \"##ely\": 26006,\n      \"pinnacle\": 26007,\n      \"rake\": 26008,\n      \"sylvie\": 26009,\n      \"##edo\": 26010,\n      \"almond\": 26011,\n      \"quivering\": 26012,\n      \"##irus\": 26013,\n      \"alteration\": 26014,\n      \"faltered\": 26015,\n      \"##wad\": 26016,\n      \"51st\": 26017,\n      \"hydra\": 26018,\n      \"ticked\": 26019,\n      \"##kato\": 26020,\n      \"recommends\": 26021,\n      \"##dicated\": 26022,\n      \"antigua\": 26023,\n      \"arjun\": 26024,\n      \"stagecoach\": 26025,\n      \"wilfred\": 26026,\n      \"trickle\": 26027,\n      \"pronouns\": 26028,\n      \"##pon\": 26029,\n      \"aryan\": 26030,\n      \"nighttime\": 26031,\n      \"##anian\": 26032,\n      \"gall\": 26033,\n      \"pea\": 26034,\n      \"stitch\": 26035,\n      \"##hei\": 26036,\n      \"leung\": 26037,\n      \"milos\": 26038,\n      \"##dini\": 26039,\n      \"eritrea\": 26040,\n      \"nexus\": 26041,\n      \"starved\": 26042,\n      \"snowfall\": 26043,\n      \"kant\": 26044,\n      \"parasitic\": 26045,\n      \"cot\": 26046,\n      \"discus\": 26047,\n      \"hana\": 26048,\n      \"strikers\": 26049,\n      \"appleton\": 26050,\n      \"kitchens\": 26051,\n      \"##erina\": 26052,\n      \"##partisan\": 26053,\n      \"##itha\": 26054,\n      \"##vius\": 26055,\n      \"disclose\": 26056,\n      \"metis\": 26057,\n      \"##channel\": 26058,\n      \"1701\": 26059,\n      \"tesla\": 26060,\n      \"##vera\": 26061,\n      \"fitch\": 26062,\n      \"1735\": 26063,\n      \"blooded\": 26064,\n      \"##tila\": 26065,\n      \"decimal\": 26066,\n      \"##tang\": 26067,\n      \"##bai\": 26068,\n      \"cyclones\": 26069,\n      \"eun\": 26070,\n      \"bottled\": 26071,\n      \"peas\": 26072,\n      \"pensacola\": 26073,\n      \"basha\": 26074,\n      \"bolivian\": 26075,\n      \"crabs\": 26076,\n      \"boil\": 26077,\n      \"lanterns\": 26078,\n      \"partridge\": 26079,\n      \"roofed\": 26080,\n      \"1645\": 26081,\n      \"necks\": 26082,\n      \"##phila\": 26083,\n      \"opined\": 26084,\n      \"patting\": 26085,\n      \"##kla\": 26086,\n      \"##lland\": 26087,\n      \"chuckles\": 26088,\n      \"volta\": 26089,\n      \"whereupon\": 26090,\n      \"##nche\": 26091,\n      \"devout\": 26092,\n      \"euroleague\": 26093,\n      \"suicidal\": 26094,\n      \"##dee\": 26095,\n      \"inherently\": 26096,\n      \"involuntary\": 26097,\n      \"knitting\": 26098,\n      \"nasser\": 26099,\n      \"##hide\": 26100,\n      \"puppets\": 26101,\n      \"colourful\": 26102,\n      \"courageous\": 26103,\n      \"southend\": 26104,\n      \"stills\": 26105,\n      \"miraculous\": 26106,\n      \"hodgson\": 26107,\n      \"richer\": 26108,\n      \"rochdale\": 26109,\n      \"ethernet\": 26110,\n      \"greta\": 26111,\n      \"uniting\": 26112,\n      \"prism\": 26113,\n      \"umm\": 26114,\n      \"##haya\": 26115,\n      \"##itical\": 26116,\n      \"##utation\": 26117,\n      \"deterioration\": 26118,\n      \"pointe\": 26119,\n      \"prowess\": 26120,\n      \"##ropriation\": 26121,\n      \"lids\": 26122,\n      \"scranton\": 26123,\n      \"billings\": 26124,\n      \"subcontinent\": 26125,\n      \"##koff\": 26126,\n      \"##scope\": 26127,\n      \"brute\": 26128,\n      \"kellogg\": 26129,\n      \"psalms\": 26130,\n      \"degraded\": 26131,\n      \"##vez\": 26132,\n      \"stanisław\": 26133,\n      \"##ructured\": 26134,\n      \"ferreira\": 26135,\n      \"pun\": 26136,\n      \"astonishing\": 26137,\n      \"gunnar\": 26138,\n      \"##yat\": 26139,\n      \"arya\": 26140,\n      \"prc\": 26141,\n      \"gottfried\": 26142,\n      \"##tight\": 26143,\n      \"excursion\": 26144,\n      \"##ographer\": 26145,\n      \"dina\": 26146,\n      \"##quil\": 26147,\n      \"##nare\": 26148,\n      \"huffington\": 26149,\n      \"illustrious\": 26150,\n      \"wilbur\": 26151,\n      \"gundam\": 26152,\n      \"verandah\": 26153,\n      \"##zard\": 26154,\n      \"naacp\": 26155,\n      \"##odle\": 26156,\n      \"constructive\": 26157,\n      \"fjord\": 26158,\n      \"kade\": 26159,\n      \"##naud\": 26160,\n      \"generosity\": 26161,\n      \"thrilling\": 26162,\n      \"baseline\": 26163,\n      \"cayman\": 26164,\n      \"frankish\": 26165,\n      \"plastics\": 26166,\n      \"accommodations\": 26167,\n      \"zoological\": 26168,\n      \"##fting\": 26169,\n      \"cedric\": 26170,\n      \"qb\": 26171,\n      \"motorized\": 26172,\n      \"##dome\": 26173,\n      \"##otted\": 26174,\n      \"squealed\": 26175,\n      \"tackled\": 26176,\n      \"canucks\": 26177,\n      \"budgets\": 26178,\n      \"situ\": 26179,\n      \"asthma\": 26180,\n      \"dail\": 26181,\n      \"gabled\": 26182,\n      \"grasslands\": 26183,\n      \"whimpered\": 26184,\n      \"writhing\": 26185,\n      \"judgments\": 26186,\n      \"##65\": 26187,\n      \"minnie\": 26188,\n      \"pv\": 26189,\n      \"##carbon\": 26190,\n      \"bananas\": 26191,\n      \"grille\": 26192,\n      \"domes\": 26193,\n      \"monique\": 26194,\n      \"odin\": 26195,\n      \"maguire\": 26196,\n      \"markham\": 26197,\n      \"tierney\": 26198,\n      \"##estra\": 26199,\n      \"##chua\": 26200,\n      \"libel\": 26201,\n      \"poke\": 26202,\n      \"speedy\": 26203,\n      \"atrium\": 26204,\n      \"laval\": 26205,\n      \"notwithstanding\": 26206,\n      \"##edly\": 26207,\n      \"fai\": 26208,\n      \"kala\": 26209,\n      \"##sur\": 26210,\n      \"robb\": 26211,\n      \"##sma\": 26212,\n      \"listings\": 26213,\n      \"luz\": 26214,\n      \"supplementary\": 26215,\n      \"tianjin\": 26216,\n      \"##acing\": 26217,\n      \"enzo\": 26218,\n      \"jd\": 26219,\n      \"ric\": 26220,\n      \"scanner\": 26221,\n      \"croats\": 26222,\n      \"transcribed\": 26223,\n      \"##49\": 26224,\n      \"arden\": 26225,\n      \"cv\": 26226,\n      \"##hair\": 26227,\n      \"##raphy\": 26228,\n      \"##lver\": 26229,\n      \"##uy\": 26230,\n      \"357\": 26231,\n      \"seventies\": 26232,\n      \"staggering\": 26233,\n      \"alam\": 26234,\n      \"horticultural\": 26235,\n      \"hs\": 26236,\n      \"regression\": 26237,\n      \"timbers\": 26238,\n      \"blasting\": 26239,\n      \"##ounded\": 26240,\n      \"montagu\": 26241,\n      \"manipulating\": 26242,\n      \"##cit\": 26243,\n      \"catalytic\": 26244,\n      \"1550\": 26245,\n      \"troopers\": 26246,\n      \"##meo\": 26247,\n      \"condemnation\": 26248,\n      \"fitzpatrick\": 26249,\n      \"##oire\": 26250,\n      \"##roved\": 26251,\n      \"inexperienced\": 26252,\n      \"1670\": 26253,\n      \"castes\": 26254,\n      \"##lative\": 26255,\n      \"outing\": 26256,\n      \"314\": 26257,\n      \"dubois\": 26258,\n      \"flicking\": 26259,\n      \"quarrel\": 26260,\n      \"ste\": 26261,\n      \"learners\": 26262,\n      \"1625\": 26263,\n      \"iq\": 26264,\n      \"whistled\": 26265,\n      \"##class\": 26266,\n      \"282\": 26267,\n      \"classify\": 26268,\n      \"tariffs\": 26269,\n      \"temperament\": 26270,\n      \"355\": 26271,\n      \"folly\": 26272,\n      \"liszt\": 26273,\n      \"##yles\": 26274,\n      \"immersed\": 26275,\n      \"jordanian\": 26276,\n      \"ceasefire\": 26277,\n      \"apparel\": 26278,\n      \"extras\": 26279,\n      \"maru\": 26280,\n      \"fished\": 26281,\n      \"##bio\": 26282,\n      \"harta\": 26283,\n      \"stockport\": 26284,\n      \"assortment\": 26285,\n      \"craftsman\": 26286,\n      \"paralysis\": 26287,\n      \"transmitters\": 26288,\n      \"##cola\": 26289,\n      \"blindness\": 26290,\n      \"##wk\": 26291,\n      \"fatally\": 26292,\n      \"proficiency\": 26293,\n      \"solemnly\": 26294,\n      \"##orno\": 26295,\n      \"repairing\": 26296,\n      \"amore\": 26297,\n      \"groceries\": 26298,\n      \"ultraviolet\": 26299,\n      \"##chase\": 26300,\n      \"schoolhouse\": 26301,\n      \"##tua\": 26302,\n      \"resurgence\": 26303,\n      \"nailed\": 26304,\n      \"##otype\": 26305,\n      \"##×\": 26306,\n      \"ruse\": 26307,\n      \"saliva\": 26308,\n      \"diagrams\": 26309,\n      \"##tructing\": 26310,\n      \"albans\": 26311,\n      \"rann\": 26312,\n      \"thirties\": 26313,\n      \"1b\": 26314,\n      \"antennas\": 26315,\n      \"hilarious\": 26316,\n      \"cougars\": 26317,\n      \"paddington\": 26318,\n      \"stats\": 26319,\n      \"##eger\": 26320,\n      \"breakaway\": 26321,\n      \"ipod\": 26322,\n      \"reza\": 26323,\n      \"authorship\": 26324,\n      \"prohibiting\": 26325,\n      \"scoffed\": 26326,\n      \"##etz\": 26327,\n      \"##ttle\": 26328,\n      \"conscription\": 26329,\n      \"defected\": 26330,\n      \"trondheim\": 26331,\n      \"##fires\": 26332,\n      \"ivanov\": 26333,\n      \"keenan\": 26334,\n      \"##adan\": 26335,\n      \"##ciful\": 26336,\n      \"##fb\": 26337,\n      \"##slow\": 26338,\n      \"locating\": 26339,\n      \"##ials\": 26340,\n      \"##tford\": 26341,\n      \"cadiz\": 26342,\n      \"basalt\": 26343,\n      \"blankly\": 26344,\n      \"interned\": 26345,\n      \"rags\": 26346,\n      \"rattling\": 26347,\n      \"##tick\": 26348,\n      \"carpathian\": 26349,\n      \"reassured\": 26350,\n      \"sync\": 26351,\n      \"bum\": 26352,\n      \"guildford\": 26353,\n      \"iss\": 26354,\n      \"staunch\": 26355,\n      \"##onga\": 26356,\n      \"astronomers\": 26357,\n      \"sera\": 26358,\n      \"sofie\": 26359,\n      \"emergencies\": 26360,\n      \"susquehanna\": 26361,\n      \"##heard\": 26362,\n      \"duc\": 26363,\n      \"mastery\": 26364,\n      \"vh1\": 26365,\n      \"williamsburg\": 26366,\n      \"bayer\": 26367,\n      \"buckled\": 26368,\n      \"craving\": 26369,\n      \"##khan\": 26370,\n      \"##rdes\": 26371,\n      \"bloomington\": 26372,\n      \"##write\": 26373,\n      \"alton\": 26374,\n      \"barbecue\": 26375,\n      \"##bians\": 26376,\n      \"justine\": 26377,\n      \"##hri\": 26378,\n      \"##ndt\": 26379,\n      \"delightful\": 26380,\n      \"smartphone\": 26381,\n      \"newtown\": 26382,\n      \"photon\": 26383,\n      \"retrieval\": 26384,\n      \"peugeot\": 26385,\n      \"hissing\": 26386,\n      \"##monium\": 26387,\n      \"##orough\": 26388,\n      \"flavors\": 26389,\n      \"lighted\": 26390,\n      \"relaunched\": 26391,\n      \"tainted\": 26392,\n      \"##games\": 26393,\n      \"##lysis\": 26394,\n      \"anarchy\": 26395,\n      \"microscopic\": 26396,\n      \"hopping\": 26397,\n      \"adept\": 26398,\n      \"evade\": 26399,\n      \"evie\": 26400,\n      \"##beau\": 26401,\n      \"inhibit\": 26402,\n      \"sinn\": 26403,\n      \"adjustable\": 26404,\n      \"hurst\": 26405,\n      \"intuition\": 26406,\n      \"wilton\": 26407,\n      \"cisco\": 26408,\n      \"44th\": 26409,\n      \"lawful\": 26410,\n      \"lowlands\": 26411,\n      \"stockings\": 26412,\n      \"thierry\": 26413,\n      \"##dalen\": 26414,\n      \"##hila\": 26415,\n      \"##nai\": 26416,\n      \"fates\": 26417,\n      \"prank\": 26418,\n      \"tb\": 26419,\n      \"maison\": 26420,\n      \"lobbied\": 26421,\n      \"provocative\": 26422,\n      \"1724\": 26423,\n      \"4a\": 26424,\n      \"utopia\": 26425,\n      \"##qual\": 26426,\n      \"carbonate\": 26427,\n      \"gujarati\": 26428,\n      \"purcell\": 26429,\n      \"##rford\": 26430,\n      \"curtiss\": 26431,\n      \"##mei\": 26432,\n      \"overgrown\": 26433,\n      \"arenas\": 26434,\n      \"mediation\": 26435,\n      \"swallows\": 26436,\n      \"##rnik\": 26437,\n      \"respectful\": 26438,\n      \"turnbull\": 26439,\n      \"##hedron\": 26440,\n      \"##hope\": 26441,\n      \"alyssa\": 26442,\n      \"ozone\": 26443,\n      \"##ʻi\": 26444,\n      \"ami\": 26445,\n      \"gestapo\": 26446,\n      \"johansson\": 26447,\n      \"snooker\": 26448,\n      \"canteen\": 26449,\n      \"cuff\": 26450,\n      \"declines\": 26451,\n      \"empathy\": 26452,\n      \"stigma\": 26453,\n      \"##ags\": 26454,\n      \"##iner\": 26455,\n      \"##raine\": 26456,\n      \"taxpayers\": 26457,\n      \"gui\": 26458,\n      \"volga\": 26459,\n      \"##wright\": 26460,\n      \"##copic\": 26461,\n      \"lifespan\": 26462,\n      \"overcame\": 26463,\n      \"tattooed\": 26464,\n      \"enactment\": 26465,\n      \"giggles\": 26466,\n      \"##ador\": 26467,\n      \"##camp\": 26468,\n      \"barrington\": 26469,\n      \"bribe\": 26470,\n      \"obligatory\": 26471,\n      \"orbiting\": 26472,\n      \"peng\": 26473,\n      \"##enas\": 26474,\n      \"elusive\": 26475,\n      \"sucker\": 26476,\n      \"##vating\": 26477,\n      \"cong\": 26478,\n      \"hardship\": 26479,\n      \"empowered\": 26480,\n      \"anticipating\": 26481,\n      \"estrada\": 26482,\n      \"cryptic\": 26483,\n      \"greasy\": 26484,\n      \"detainees\": 26485,\n      \"planck\": 26486,\n      \"sudbury\": 26487,\n      \"plaid\": 26488,\n      \"dod\": 26489,\n      \"marriott\": 26490,\n      \"kayla\": 26491,\n      \"##ears\": 26492,\n      \"##vb\": 26493,\n      \"##zd\": 26494,\n      \"mortally\": 26495,\n      \"##hein\": 26496,\n      \"cognition\": 26497,\n      \"radha\": 26498,\n      \"319\": 26499,\n      \"liechtenstein\": 26500,\n      \"meade\": 26501,\n      \"richly\": 26502,\n      \"argyle\": 26503,\n      \"harpsichord\": 26504,\n      \"liberalism\": 26505,\n      \"trumpets\": 26506,\n      \"lauded\": 26507,\n      \"tyrant\": 26508,\n      \"salsa\": 26509,\n      \"tiled\": 26510,\n      \"lear\": 26511,\n      \"promoters\": 26512,\n      \"reused\": 26513,\n      \"slicing\": 26514,\n      \"trident\": 26515,\n      \"##chuk\": 26516,\n      \"##gami\": 26517,\n      \"##lka\": 26518,\n      \"cantor\": 26519,\n      \"checkpoint\": 26520,\n      \"##points\": 26521,\n      \"gaul\": 26522,\n      \"leger\": 26523,\n      \"mammalian\": 26524,\n      \"##tov\": 26525,\n      \"##aar\": 26526,\n      \"##schaft\": 26527,\n      \"doha\": 26528,\n      \"frenchman\": 26529,\n      \"nirvana\": 26530,\n      \"##vino\": 26531,\n      \"delgado\": 26532,\n      \"headlining\": 26533,\n      \"##eron\": 26534,\n      \"##iography\": 26535,\n      \"jug\": 26536,\n      \"tko\": 26537,\n      \"1649\": 26538,\n      \"naga\": 26539,\n      \"intersections\": 26540,\n      \"##jia\": 26541,\n      \"benfica\": 26542,\n      \"nawab\": 26543,\n      \"##suka\": 26544,\n      \"ashford\": 26545,\n      \"gulp\": 26546,\n      \"##deck\": 26547,\n      \"##vill\": 26548,\n      \"##rug\": 26549,\n      \"brentford\": 26550,\n      \"frazier\": 26551,\n      \"pleasures\": 26552,\n      \"dunne\": 26553,\n      \"potsdam\": 26554,\n      \"shenzhen\": 26555,\n      \"dentistry\": 26556,\n      \"##tec\": 26557,\n      \"flanagan\": 26558,\n      \"##dorff\": 26559,\n      \"##hear\": 26560,\n      \"chorale\": 26561,\n      \"dinah\": 26562,\n      \"prem\": 26563,\n      \"quezon\": 26564,\n      \"##rogated\": 26565,\n      \"relinquished\": 26566,\n      \"sutra\": 26567,\n      \"terri\": 26568,\n      \"##pani\": 26569,\n      \"flaps\": 26570,\n      \"##rissa\": 26571,\n      \"poly\": 26572,\n      \"##rnet\": 26573,\n      \"homme\": 26574,\n      \"aback\": 26575,\n      \"##eki\": 26576,\n      \"linger\": 26577,\n      \"womb\": 26578,\n      \"##kson\": 26579,\n      \"##lewood\": 26580,\n      \"doorstep\": 26581,\n      \"orthodoxy\": 26582,\n      \"threaded\": 26583,\n      \"westfield\": 26584,\n      \"##rval\": 26585,\n      \"dioceses\": 26586,\n      \"fridays\": 26587,\n      \"subsided\": 26588,\n      \"##gata\": 26589,\n      \"loyalists\": 26590,\n      \"##biotic\": 26591,\n      \"##ettes\": 26592,\n      \"letterman\": 26593,\n      \"lunatic\": 26594,\n      \"prelate\": 26595,\n      \"tenderly\": 26596,\n      \"invariably\": 26597,\n      \"souza\": 26598,\n      \"thug\": 26599,\n      \"winslow\": 26600,\n      \"##otide\": 26601,\n      \"furlongs\": 26602,\n      \"gogh\": 26603,\n      \"jeopardy\": 26604,\n      \"##runa\": 26605,\n      \"pegasus\": 26606,\n      \"##umble\": 26607,\n      \"humiliated\": 26608,\n      \"standalone\": 26609,\n      \"tagged\": 26610,\n      \"##roller\": 26611,\n      \"freshmen\": 26612,\n      \"klan\": 26613,\n      \"##bright\": 26614,\n      \"attaining\": 26615,\n      \"initiating\": 26616,\n      \"transatlantic\": 26617,\n      \"logged\": 26618,\n      \"viz\": 26619,\n      \"##uance\": 26620,\n      \"1723\": 26621,\n      \"combatants\": 26622,\n      \"intervening\": 26623,\n      \"stephane\": 26624,\n      \"chieftain\": 26625,\n      \"despised\": 26626,\n      \"grazed\": 26627,\n      \"317\": 26628,\n      \"cdc\": 26629,\n      \"galveston\": 26630,\n      \"godzilla\": 26631,\n      \"macro\": 26632,\n      \"simulate\": 26633,\n      \"##planes\": 26634,\n      \"parades\": 26635,\n      \"##esses\": 26636,\n      \"960\": 26637,\n      \"##ductive\": 26638,\n      \"##unes\": 26639,\n      \"equator\": 26640,\n      \"overdose\": 26641,\n      \"##cans\": 26642,\n      \"##hosh\": 26643,\n      \"##lifting\": 26644,\n      \"joshi\": 26645,\n      \"epstein\": 26646,\n      \"sonora\": 26647,\n      \"treacherous\": 26648,\n      \"aquatics\": 26649,\n      \"manchu\": 26650,\n      \"responsive\": 26651,\n      \"##sation\": 26652,\n      \"supervisory\": 26653,\n      \"##christ\": 26654,\n      \"##llins\": 26655,\n      \"##ibar\": 26656,\n      \"##balance\": 26657,\n      \"##uso\": 26658,\n      \"kimball\": 26659,\n      \"karlsruhe\": 26660,\n      \"mab\": 26661,\n      \"##emy\": 26662,\n      \"ignores\": 26663,\n      \"phonetic\": 26664,\n      \"reuters\": 26665,\n      \"spaghetti\": 26666,\n      \"820\": 26667,\n      \"almighty\": 26668,\n      \"danzig\": 26669,\n      \"rumbling\": 26670,\n      \"tombstone\": 26671,\n      \"designations\": 26672,\n      \"lured\": 26673,\n      \"outset\": 26674,\n      \"##felt\": 26675,\n      \"supermarkets\": 26676,\n      \"##wt\": 26677,\n      \"grupo\": 26678,\n      \"kei\": 26679,\n      \"kraft\": 26680,\n      \"susanna\": 26681,\n      \"##blood\": 26682,\n      \"comprehension\": 26683,\n      \"genealogy\": 26684,\n      \"##aghan\": 26685,\n      \"##verted\": 26686,\n      \"redding\": 26687,\n      \"##ythe\": 26688,\n      \"1722\": 26689,\n      \"bowing\": 26690,\n      \"##pore\": 26691,\n      \"##roi\": 26692,\n      \"lest\": 26693,\n      \"sharpened\": 26694,\n      \"fulbright\": 26695,\n      \"valkyrie\": 26696,\n      \"sikhs\": 26697,\n      \"##unds\": 26698,\n      \"swans\": 26699,\n      \"bouquet\": 26700,\n      \"merritt\": 26701,\n      \"##tage\": 26702,\n      \"##venting\": 26703,\n      \"commuted\": 26704,\n      \"redhead\": 26705,\n      \"clerks\": 26706,\n      \"leasing\": 26707,\n      \"cesare\": 26708,\n      \"dea\": 26709,\n      \"hazy\": 26710,\n      \"##vances\": 26711,\n      \"fledged\": 26712,\n      \"greenfield\": 26713,\n      \"servicemen\": 26714,\n      \"##gical\": 26715,\n      \"armando\": 26716,\n      \"blackout\": 26717,\n      \"dt\": 26718,\n      \"sagged\": 26719,\n      \"downloadable\": 26720,\n      \"intra\": 26721,\n      \"potion\": 26722,\n      \"pods\": 26723,\n      \"##4th\": 26724,\n      \"##mism\": 26725,\n      \"xp\": 26726,\n      \"attendants\": 26727,\n      \"gambia\": 26728,\n      \"stale\": 26729,\n      \"##ntine\": 26730,\n      \"plump\": 26731,\n      \"asteroids\": 26732,\n      \"rediscovered\": 26733,\n      \"buds\": 26734,\n      \"flea\": 26735,\n      \"hive\": 26736,\n      \"##neas\": 26737,\n      \"1737\": 26738,\n      \"classifications\": 26739,\n      \"debuts\": 26740,\n      \"##eles\": 26741,\n      \"olympus\": 26742,\n      \"scala\": 26743,\n      \"##eurs\": 26744,\n      \"##gno\": 26745,\n      \"##mute\": 26746,\n      \"hummed\": 26747,\n      \"sigismund\": 26748,\n      \"visuals\": 26749,\n      \"wiggled\": 26750,\n      \"await\": 26751,\n      \"pilasters\": 26752,\n      \"clench\": 26753,\n      \"sulfate\": 26754,\n      \"##ances\": 26755,\n      \"bellevue\": 26756,\n      \"enigma\": 26757,\n      \"trainee\": 26758,\n      \"snort\": 26759,\n      \"##sw\": 26760,\n      \"clouded\": 26761,\n      \"denim\": 26762,\n      \"##rank\": 26763,\n      \"##rder\": 26764,\n      \"churning\": 26765,\n      \"hartman\": 26766,\n      \"lodges\": 26767,\n      \"riches\": 26768,\n      \"sima\": 26769,\n      \"##missible\": 26770,\n      \"accountable\": 26771,\n      \"socrates\": 26772,\n      \"regulates\": 26773,\n      \"mueller\": 26774,\n      \"##cr\": 26775,\n      \"1702\": 26776,\n      \"avoids\": 26777,\n      \"solids\": 26778,\n      \"himalayas\": 26779,\n      \"nutrient\": 26780,\n      \"pup\": 26781,\n      \"##jevic\": 26782,\n      \"squat\": 26783,\n      \"fades\": 26784,\n      \"nec\": 26785,\n      \"##lates\": 26786,\n      \"##pina\": 26787,\n      \"##rona\": 26788,\n      \"##ου\": 26789,\n      \"privateer\": 26790,\n      \"tequila\": 26791,\n      \"##gative\": 26792,\n      \"##mpton\": 26793,\n      \"apt\": 26794,\n      \"hornet\": 26795,\n      \"immortals\": 26796,\n      \"##dou\": 26797,\n      \"asturias\": 26798,\n      \"cleansing\": 26799,\n      \"dario\": 26800,\n      \"##rries\": 26801,\n      \"##anta\": 26802,\n      \"etymology\": 26803,\n      \"servicing\": 26804,\n      \"zhejiang\": 26805,\n      \"##venor\": 26806,\n      \"##nx\": 26807,\n      \"horned\": 26808,\n      \"erasmus\": 26809,\n      \"rayon\": 26810,\n      \"relocating\": 26811,\n      \"£10\": 26812,\n      \"##bags\": 26813,\n      \"escalated\": 26814,\n      \"promenade\": 26815,\n      \"stubble\": 26816,\n      \"2010s\": 26817,\n      \"artisans\": 26818,\n      \"axial\": 26819,\n      \"liquids\": 26820,\n      \"mora\": 26821,\n      \"sho\": 26822,\n      \"yoo\": 26823,\n      \"##tsky\": 26824,\n      \"bundles\": 26825,\n      \"oldies\": 26826,\n      \"##nally\": 26827,\n      \"notification\": 26828,\n      \"bastion\": 26829,\n      \"##ths\": 26830,\n      \"sparkle\": 26831,\n      \"##lved\": 26832,\n      \"1728\": 26833,\n      \"leash\": 26834,\n      \"pathogen\": 26835,\n      \"highs\": 26836,\n      \"##hmi\": 26837,\n      \"immature\": 26838,\n      \"880\": 26839,\n      \"gonzaga\": 26840,\n      \"ignatius\": 26841,\n      \"mansions\": 26842,\n      \"monterrey\": 26843,\n      \"sweets\": 26844,\n      \"bryson\": 26845,\n      \"##loe\": 26846,\n      \"polled\": 26847,\n      \"regatta\": 26848,\n      \"brightest\": 26849,\n      \"pei\": 26850,\n      \"rosy\": 26851,\n      \"squid\": 26852,\n      \"hatfield\": 26853,\n      \"payroll\": 26854,\n      \"addict\": 26855,\n      \"meath\": 26856,\n      \"cornerback\": 26857,\n      \"heaviest\": 26858,\n      \"lodging\": 26859,\n      \"##mage\": 26860,\n      \"capcom\": 26861,\n      \"rippled\": 26862,\n      \"##sily\": 26863,\n      \"barnet\": 26864,\n      \"mayhem\": 26865,\n      \"ymca\": 26866,\n      \"snuggled\": 26867,\n      \"rousseau\": 26868,\n      \"##cute\": 26869,\n      \"blanchard\": 26870,\n      \"284\": 26871,\n      \"fragmented\": 26872,\n      \"leighton\": 26873,\n      \"chromosomes\": 26874,\n      \"risking\": 26875,\n      \"##md\": 26876,\n      \"##strel\": 26877,\n      \"##utter\": 26878,\n      \"corinne\": 26879,\n      \"coyotes\": 26880,\n      \"cynical\": 26881,\n      \"hiroshi\": 26882,\n      \"yeomanry\": 26883,\n      \"##ractive\": 26884,\n      \"ebook\": 26885,\n      \"grading\": 26886,\n      \"mandela\": 26887,\n      \"plume\": 26888,\n      \"agustin\": 26889,\n      \"magdalene\": 26890,\n      \"##rkin\": 26891,\n      \"bea\": 26892,\n      \"femme\": 26893,\n      \"trafford\": 26894,\n      \"##coll\": 26895,\n      \"##lun\": 26896,\n      \"##tance\": 26897,\n      \"52nd\": 26898,\n      \"fourier\": 26899,\n      \"upton\": 26900,\n      \"##mental\": 26901,\n      \"camilla\": 26902,\n      \"gust\": 26903,\n      \"iihf\": 26904,\n      \"islamabad\": 26905,\n      \"longevity\": 26906,\n      \"##kala\": 26907,\n      \"feldman\": 26908,\n      \"netting\": 26909,\n      \"##rization\": 26910,\n      \"endeavour\": 26911,\n      \"foraging\": 26912,\n      \"mfa\": 26913,\n      \"orr\": 26914,\n      \"##open\": 26915,\n      \"greyish\": 26916,\n      \"contradiction\": 26917,\n      \"graz\": 26918,\n      \"##ruff\": 26919,\n      \"handicapped\": 26920,\n      \"marlene\": 26921,\n      \"tweed\": 26922,\n      \"oaxaca\": 26923,\n      \"spp\": 26924,\n      \"campos\": 26925,\n      \"miocene\": 26926,\n      \"pri\": 26927,\n      \"configured\": 26928,\n      \"cooks\": 26929,\n      \"pluto\": 26930,\n      \"cozy\": 26931,\n      \"pornographic\": 26932,\n      \"##entes\": 26933,\n      \"70th\": 26934,\n      \"fairness\": 26935,\n      \"glided\": 26936,\n      \"jonny\": 26937,\n      \"lynne\": 26938,\n      \"rounding\": 26939,\n      \"sired\": 26940,\n      \"##emon\": 26941,\n      \"##nist\": 26942,\n      \"remade\": 26943,\n      \"uncover\": 26944,\n      \"##mack\": 26945,\n      \"complied\": 26946,\n      \"lei\": 26947,\n      \"newsweek\": 26948,\n      \"##jured\": 26949,\n      \"##parts\": 26950,\n      \"##enting\": 26951,\n      \"##pg\": 26952,\n      \"293\": 26953,\n      \"finer\": 26954,\n      \"guerrillas\": 26955,\n      \"athenian\": 26956,\n      \"deng\": 26957,\n      \"disused\": 26958,\n      \"stepmother\": 26959,\n      \"accuse\": 26960,\n      \"gingerly\": 26961,\n      \"seduction\": 26962,\n      \"521\": 26963,\n      \"confronting\": 26964,\n      \"##walker\": 26965,\n      \"##going\": 26966,\n      \"gora\": 26967,\n      \"nostalgia\": 26968,\n      \"sabres\": 26969,\n      \"virginity\": 26970,\n      \"wrenched\": 26971,\n      \"##minated\": 26972,\n      \"syndication\": 26973,\n      \"wielding\": 26974,\n      \"eyre\": 26975,\n      \"##56\": 26976,\n      \"##gnon\": 26977,\n      \"##igny\": 26978,\n      \"behaved\": 26979,\n      \"taxpayer\": 26980,\n      \"sweeps\": 26981,\n      \"##growth\": 26982,\n      \"childless\": 26983,\n      \"gallant\": 26984,\n      \"##ywood\": 26985,\n      \"amplified\": 26986,\n      \"geraldine\": 26987,\n      \"scrape\": 26988,\n      \"##ffi\": 26989,\n      \"babylonian\": 26990,\n      \"fresco\": 26991,\n      \"##rdan\": 26992,\n      \"##kney\": 26993,\n      \"##position\": 26994,\n      \"1718\": 26995,\n      \"restricting\": 26996,\n      \"tack\": 26997,\n      \"fukuoka\": 26998,\n      \"osborn\": 26999,\n      \"selector\": 27000,\n      \"partnering\": 27001,\n      \"##dlow\": 27002,\n      \"318\": 27003,\n      \"gnu\": 27004,\n      \"kia\": 27005,\n      \"tak\": 27006,\n      \"whitley\": 27007,\n      \"gables\": 27008,\n      \"##54\": 27009,\n      \"##mania\": 27010,\n      \"mri\": 27011,\n      \"softness\": 27012,\n      \"immersion\": 27013,\n      \"##bots\": 27014,\n      \"##evsky\": 27015,\n      \"1713\": 27016,\n      \"chilling\": 27017,\n      \"insignificant\": 27018,\n      \"pcs\": 27019,\n      \"##uis\": 27020,\n      \"elites\": 27021,\n      \"lina\": 27022,\n      \"purported\": 27023,\n      \"supplemental\": 27024,\n      \"teaming\": 27025,\n      \"##americana\": 27026,\n      \"##dding\": 27027,\n      \"##inton\": 27028,\n      \"proficient\": 27029,\n      \"rouen\": 27030,\n      \"##nage\": 27031,\n      \"##rret\": 27032,\n      \"niccolo\": 27033,\n      \"selects\": 27034,\n      \"##bread\": 27035,\n      \"fluffy\": 27036,\n      \"1621\": 27037,\n      \"gruff\": 27038,\n      \"knotted\": 27039,\n      \"mukherjee\": 27040,\n      \"polgara\": 27041,\n      \"thrash\": 27042,\n      \"nicholls\": 27043,\n      \"secluded\": 27044,\n      \"smoothing\": 27045,\n      \"thru\": 27046,\n      \"corsica\": 27047,\n      \"loaf\": 27048,\n      \"whitaker\": 27049,\n      \"inquiries\": 27050,\n      \"##rrier\": 27051,\n      \"##kam\": 27052,\n      \"indochina\": 27053,\n      \"289\": 27054,\n      \"marlins\": 27055,\n      \"myles\": 27056,\n      \"peking\": 27057,\n      \"##tea\": 27058,\n      \"extracts\": 27059,\n      \"pastry\": 27060,\n      \"superhuman\": 27061,\n      \"connacht\": 27062,\n      \"vogel\": 27063,\n      \"##ditional\": 27064,\n      \"##het\": 27065,\n      \"##udged\": 27066,\n      \"##lash\": 27067,\n      \"gloss\": 27068,\n      \"quarries\": 27069,\n      \"refit\": 27070,\n      \"teaser\": 27071,\n      \"##alic\": 27072,\n      \"##gaon\": 27073,\n      \"20s\": 27074,\n      \"materialized\": 27075,\n      \"sling\": 27076,\n      \"camped\": 27077,\n      \"pickering\": 27078,\n      \"tung\": 27079,\n      \"tracker\": 27080,\n      \"pursuant\": 27081,\n      \"##cide\": 27082,\n      \"cranes\": 27083,\n      \"soc\": 27084,\n      \"##cini\": 27085,\n      \"##typical\": 27086,\n      \"##viere\": 27087,\n      \"anhalt\": 27088,\n      \"overboard\": 27089,\n      \"workout\": 27090,\n      \"chores\": 27091,\n      \"fares\": 27092,\n      \"orphaned\": 27093,\n      \"stains\": 27094,\n      \"##logie\": 27095,\n      \"fenton\": 27096,\n      \"surpassing\": 27097,\n      \"joyah\": 27098,\n      \"triggers\": 27099,\n      \"##itte\": 27100,\n      \"grandmaster\": 27101,\n      \"##lass\": 27102,\n      \"##lists\": 27103,\n      \"clapping\": 27104,\n      \"fraudulent\": 27105,\n      \"ledger\": 27106,\n      \"nagasaki\": 27107,\n      \"##cor\": 27108,\n      \"##nosis\": 27109,\n      \"##tsa\": 27110,\n      \"eucalyptus\": 27111,\n      \"tun\": 27112,\n      \"##icio\": 27113,\n      \"##rney\": 27114,\n      \"##tara\": 27115,\n      \"dax\": 27116,\n      \"heroism\": 27117,\n      \"ina\": 27118,\n      \"wrexham\": 27119,\n      \"onboard\": 27120,\n      \"unsigned\": 27121,\n      \"##dates\": 27122,\n      \"moshe\": 27123,\n      \"galley\": 27124,\n      \"winnie\": 27125,\n      \"droplets\": 27126,\n      \"exiles\": 27127,\n      \"praises\": 27128,\n      \"watered\": 27129,\n      \"noodles\": 27130,\n      \"##aia\": 27131,\n      \"fein\": 27132,\n      \"adi\": 27133,\n      \"leland\": 27134,\n      \"multicultural\": 27135,\n      \"stink\": 27136,\n      \"bingo\": 27137,\n      \"comets\": 27138,\n      \"erskine\": 27139,\n      \"modernized\": 27140,\n      \"canned\": 27141,\n      \"constraint\": 27142,\n      \"domestically\": 27143,\n      \"chemotherapy\": 27144,\n      \"featherweight\": 27145,\n      \"stifled\": 27146,\n      \"##mum\": 27147,\n      \"darkly\": 27148,\n      \"irresistible\": 27149,\n      \"refreshing\": 27150,\n      \"hasty\": 27151,\n      \"isolate\": 27152,\n      \"##oys\": 27153,\n      \"kitchener\": 27154,\n      \"planners\": 27155,\n      \"##wehr\": 27156,\n      \"cages\": 27157,\n      \"yarn\": 27158,\n      \"implant\": 27159,\n      \"toulon\": 27160,\n      \"elects\": 27161,\n      \"childbirth\": 27162,\n      \"yue\": 27163,\n      \"##lind\": 27164,\n      \"##lone\": 27165,\n      \"cn\": 27166,\n      \"rightful\": 27167,\n      \"sportsman\": 27168,\n      \"junctions\": 27169,\n      \"remodeled\": 27170,\n      \"specifies\": 27171,\n      \"##rgh\": 27172,\n      \"291\": 27173,\n      \"##oons\": 27174,\n      \"complimented\": 27175,\n      \"##urgent\": 27176,\n      \"lister\": 27177,\n      \"ot\": 27178,\n      \"##logic\": 27179,\n      \"bequeathed\": 27180,\n      \"cheekbones\": 27181,\n      \"fontana\": 27182,\n      \"gabby\": 27183,\n      \"##dial\": 27184,\n      \"amadeus\": 27185,\n      \"corrugated\": 27186,\n      \"maverick\": 27187,\n      \"resented\": 27188,\n      \"triangles\": 27189,\n      \"##hered\": 27190,\n      \"##usly\": 27191,\n      \"nazareth\": 27192,\n      \"tyrol\": 27193,\n      \"1675\": 27194,\n      \"assent\": 27195,\n      \"poorer\": 27196,\n      \"sectional\": 27197,\n      \"aegean\": 27198,\n      \"##cous\": 27199,\n      \"296\": 27200,\n      \"nylon\": 27201,\n      \"ghanaian\": 27202,\n      \"##egorical\": 27203,\n      \"##weig\": 27204,\n      \"cushions\": 27205,\n      \"forbid\": 27206,\n      \"fusiliers\": 27207,\n      \"obstruction\": 27208,\n      \"somerville\": 27209,\n      \"##scia\": 27210,\n      \"dime\": 27211,\n      \"earrings\": 27212,\n      \"elliptical\": 27213,\n      \"leyte\": 27214,\n      \"oder\": 27215,\n      \"polymers\": 27216,\n      \"timmy\": 27217,\n      \"atm\": 27218,\n      \"midtown\": 27219,\n      \"piloted\": 27220,\n      \"settles\": 27221,\n      \"continual\": 27222,\n      \"externally\": 27223,\n      \"mayfield\": 27224,\n      \"##uh\": 27225,\n      \"enrichment\": 27226,\n      \"henson\": 27227,\n      \"keane\": 27228,\n      \"persians\": 27229,\n      \"1733\": 27230,\n      \"benji\": 27231,\n      \"braden\": 27232,\n      \"pep\": 27233,\n      \"324\": 27234,\n      \"##efe\": 27235,\n      \"contenders\": 27236,\n      \"pepsi\": 27237,\n      \"valet\": 27238,\n      \"##isches\": 27239,\n      \"298\": 27240,\n      \"##asse\": 27241,\n      \"##earing\": 27242,\n      \"goofy\": 27243,\n      \"stroll\": 27244,\n      \"##amen\": 27245,\n      \"authoritarian\": 27246,\n      \"occurrences\": 27247,\n      \"adversary\": 27248,\n      \"ahmedabad\": 27249,\n      \"tangent\": 27250,\n      \"toppled\": 27251,\n      \"dorchester\": 27252,\n      \"1672\": 27253,\n      \"modernism\": 27254,\n      \"marxism\": 27255,\n      \"islamist\": 27256,\n      \"charlemagne\": 27257,\n      \"exponential\": 27258,\n      \"racks\": 27259,\n      \"unicode\": 27260,\n      \"brunette\": 27261,\n      \"mbc\": 27262,\n      \"pic\": 27263,\n      \"skirmish\": 27264,\n      \"##bund\": 27265,\n      \"##lad\": 27266,\n      \"##powered\": 27267,\n      \"##yst\": 27268,\n      \"hoisted\": 27269,\n      \"messina\": 27270,\n      \"shatter\": 27271,\n      \"##ctum\": 27272,\n      \"jedi\": 27273,\n      \"vantage\": 27274,\n      \"##music\": 27275,\n      \"##neil\": 27276,\n      \"clemens\": 27277,\n      \"mahmoud\": 27278,\n      \"corrupted\": 27279,\n      \"authentication\": 27280,\n      \"lowry\": 27281,\n      \"nils\": 27282,\n      \"##washed\": 27283,\n      \"omnibus\": 27284,\n      \"wounding\": 27285,\n      \"jillian\": 27286,\n      \"##itors\": 27287,\n      \"##opped\": 27288,\n      \"serialized\": 27289,\n      \"narcotics\": 27290,\n      \"handheld\": 27291,\n      \"##arm\": 27292,\n      \"##plicity\": 27293,\n      \"intersecting\": 27294,\n      \"stimulating\": 27295,\n      \"##onis\": 27296,\n      \"crate\": 27297,\n      \"fellowships\": 27298,\n      \"hemingway\": 27299,\n      \"casinos\": 27300,\n      \"climatic\": 27301,\n      \"fordham\": 27302,\n      \"copeland\": 27303,\n      \"drip\": 27304,\n      \"beatty\": 27305,\n      \"leaflets\": 27306,\n      \"robber\": 27307,\n      \"brothel\": 27308,\n      \"madeira\": 27309,\n      \"##hedral\": 27310,\n      \"sphinx\": 27311,\n      \"ultrasound\": 27312,\n      \"##vana\": 27313,\n      \"valor\": 27314,\n      \"forbade\": 27315,\n      \"leonid\": 27316,\n      \"villas\": 27317,\n      \"##aldo\": 27318,\n      \"duane\": 27319,\n      \"marquez\": 27320,\n      \"##cytes\": 27321,\n      \"disadvantaged\": 27322,\n      \"forearms\": 27323,\n      \"kawasaki\": 27324,\n      \"reacts\": 27325,\n      \"consular\": 27326,\n      \"lax\": 27327,\n      \"uncles\": 27328,\n      \"uphold\": 27329,\n      \"##hopper\": 27330,\n      \"concepcion\": 27331,\n      \"dorsey\": 27332,\n      \"lass\": 27333,\n      \"##izan\": 27334,\n      \"arching\": 27335,\n      \"passageway\": 27336,\n      \"1708\": 27337,\n      \"researches\": 27338,\n      \"tia\": 27339,\n      \"internationals\": 27340,\n      \"##graphs\": 27341,\n      \"##opers\": 27342,\n      \"distinguishes\": 27343,\n      \"javanese\": 27344,\n      \"divert\": 27345,\n      \"##uven\": 27346,\n      \"plotted\": 27347,\n      \"##listic\": 27348,\n      \"##rwin\": 27349,\n      \"##erik\": 27350,\n      \"##tify\": 27351,\n      \"affirmative\": 27352,\n      \"signifies\": 27353,\n      \"validation\": 27354,\n      \"##bson\": 27355,\n      \"kari\": 27356,\n      \"felicity\": 27357,\n      \"georgina\": 27358,\n      \"zulu\": 27359,\n      \"##eros\": 27360,\n      \"##rained\": 27361,\n      \"##rath\": 27362,\n      \"overcoming\": 27363,\n      \"##dot\": 27364,\n      \"argyll\": 27365,\n      \"##rbin\": 27366,\n      \"1734\": 27367,\n      \"chiba\": 27368,\n      \"ratification\": 27369,\n      \"windy\": 27370,\n      \"earls\": 27371,\n      \"parapet\": 27372,\n      \"##marks\": 27373,\n      \"hunan\": 27374,\n      \"pristine\": 27375,\n      \"astrid\": 27376,\n      \"punta\": 27377,\n      \"##gart\": 27378,\n      \"brodie\": 27379,\n      \"##kota\": 27380,\n      \"##oder\": 27381,\n      \"malaga\": 27382,\n      \"minerva\": 27383,\n      \"rouse\": 27384,\n      \"##phonic\": 27385,\n      \"bellowed\": 27386,\n      \"pagoda\": 27387,\n      \"portals\": 27388,\n      \"reclamation\": 27389,\n      \"##gur\": 27390,\n      \"##odies\": 27391,\n      \"##⁄₄\": 27392,\n      \"parentheses\": 27393,\n      \"quoting\": 27394,\n      \"allergic\": 27395,\n      \"palette\": 27396,\n      \"showcases\": 27397,\n      \"benefactor\": 27398,\n      \"heartland\": 27399,\n      \"nonlinear\": 27400,\n      \"##tness\": 27401,\n      \"bladed\": 27402,\n      \"cheerfully\": 27403,\n      \"scans\": 27404,\n      \"##ety\": 27405,\n      \"##hone\": 27406,\n      \"1666\": 27407,\n      \"girlfriends\": 27408,\n      \"pedersen\": 27409,\n      \"hiram\": 27410,\n      \"sous\": 27411,\n      \"##liche\": 27412,\n      \"##nator\": 27413,\n      \"1683\": 27414,\n      \"##nery\": 27415,\n      \"##orio\": 27416,\n      \"##umen\": 27417,\n      \"bobo\": 27418,\n      \"primaries\": 27419,\n      \"smiley\": 27420,\n      \"##cb\": 27421,\n      \"unearthed\": 27422,\n      \"uniformly\": 27423,\n      \"fis\": 27424,\n      \"metadata\": 27425,\n      \"1635\": 27426,\n      \"ind\": 27427,\n      \"##oted\": 27428,\n      \"recoil\": 27429,\n      \"##titles\": 27430,\n      \"##tura\": 27431,\n      \"##ια\": 27432,\n      \"406\": 27433,\n      \"hilbert\": 27434,\n      \"jamestown\": 27435,\n      \"mcmillan\": 27436,\n      \"tulane\": 27437,\n      \"seychelles\": 27438,\n      \"##frid\": 27439,\n      \"antics\": 27440,\n      \"coli\": 27441,\n      \"fated\": 27442,\n      \"stucco\": 27443,\n      \"##grants\": 27444,\n      \"1654\": 27445,\n      \"bulky\": 27446,\n      \"accolades\": 27447,\n      \"arrays\": 27448,\n      \"caledonian\": 27449,\n      \"carnage\": 27450,\n      \"optimism\": 27451,\n      \"puebla\": 27452,\n      \"##tative\": 27453,\n      \"##cave\": 27454,\n      \"enforcing\": 27455,\n      \"rotherham\": 27456,\n      \"seo\": 27457,\n      \"dunlop\": 27458,\n      \"aeronautics\": 27459,\n      \"chimed\": 27460,\n      \"incline\": 27461,\n      \"zoning\": 27462,\n      \"archduke\": 27463,\n      \"hellenistic\": 27464,\n      \"##oses\": 27465,\n      \"##sions\": 27466,\n      \"candi\": 27467,\n      \"thong\": 27468,\n      \"##ople\": 27469,\n      \"magnate\": 27470,\n      \"rustic\": 27471,\n      \"##rsk\": 27472,\n      \"projective\": 27473,\n      \"slant\": 27474,\n      \"##offs\": 27475,\n      \"danes\": 27476,\n      \"hollis\": 27477,\n      \"vocalists\": 27478,\n      \"##ammed\": 27479,\n      \"congenital\": 27480,\n      \"contend\": 27481,\n      \"gesellschaft\": 27482,\n      \"##ocating\": 27483,\n      \"##pressive\": 27484,\n      \"douglass\": 27485,\n      \"quieter\": 27486,\n      \"##cm\": 27487,\n      \"##kshi\": 27488,\n      \"howled\": 27489,\n      \"salim\": 27490,\n      \"spontaneously\": 27491,\n      \"townsville\": 27492,\n      \"buena\": 27493,\n      \"southport\": 27494,\n      \"##bold\": 27495,\n      \"kato\": 27496,\n      \"1638\": 27497,\n      \"faerie\": 27498,\n      \"stiffly\": 27499,\n      \"##vus\": 27500,\n      \"##rled\": 27501,\n      \"297\": 27502,\n      \"flawless\": 27503,\n      \"realising\": 27504,\n      \"taboo\": 27505,\n      \"##7th\": 27506,\n      \"bytes\": 27507,\n      \"straightening\": 27508,\n      \"356\": 27509,\n      \"jena\": 27510,\n      \"##hid\": 27511,\n      \"##rmin\": 27512,\n      \"cartwright\": 27513,\n      \"berber\": 27514,\n      \"bertram\": 27515,\n      \"soloists\": 27516,\n      \"411\": 27517,\n      \"noses\": 27518,\n      \"417\": 27519,\n      \"coping\": 27520,\n      \"fission\": 27521,\n      \"hardin\": 27522,\n      \"inca\": 27523,\n      \"##cen\": 27524,\n      \"1717\": 27525,\n      \"mobilized\": 27526,\n      \"vhf\": 27527,\n      \"##raf\": 27528,\n      \"biscuits\": 27529,\n      \"curate\": 27530,\n      \"##85\": 27531,\n      \"##anial\": 27532,\n      \"331\": 27533,\n      \"gaunt\": 27534,\n      \"neighbourhoods\": 27535,\n      \"1540\": 27536,\n      \"##abas\": 27537,\n      \"blanca\": 27538,\n      \"bypassed\": 27539,\n      \"sockets\": 27540,\n      \"behold\": 27541,\n      \"coincidentally\": 27542,\n      \"##bane\": 27543,\n      \"nara\": 27544,\n      \"shave\": 27545,\n      \"splinter\": 27546,\n      \"terrific\": 27547,\n      \"##arion\": 27548,\n      \"##erian\": 27549,\n      \"commonplace\": 27550,\n      \"juris\": 27551,\n      \"redwood\": 27552,\n      \"waistband\": 27553,\n      \"boxed\": 27554,\n      \"caitlin\": 27555,\n      \"fingerprints\": 27556,\n      \"jennie\": 27557,\n      \"naturalized\": 27558,\n      \"##ired\": 27559,\n      \"balfour\": 27560,\n      \"craters\": 27561,\n      \"jody\": 27562,\n      \"bungalow\": 27563,\n      \"hugely\": 27564,\n      \"quilt\": 27565,\n      \"glitter\": 27566,\n      \"pigeons\": 27567,\n      \"undertaker\": 27568,\n      \"bulging\": 27569,\n      \"constrained\": 27570,\n      \"goo\": 27571,\n      \"##sil\": 27572,\n      \"##akh\": 27573,\n      \"assimilation\": 27574,\n      \"reworked\": 27575,\n      \"##person\": 27576,\n      \"persuasion\": 27577,\n      \"##pants\": 27578,\n      \"felicia\": 27579,\n      \"##cliff\": 27580,\n      \"##ulent\": 27581,\n      \"1732\": 27582,\n      \"explodes\": 27583,\n      \"##dun\": 27584,\n      \"##inium\": 27585,\n      \"##zic\": 27586,\n      \"lyman\": 27587,\n      \"vulture\": 27588,\n      \"hog\": 27589,\n      \"overlook\": 27590,\n      \"begs\": 27591,\n      \"northwards\": 27592,\n      \"ow\": 27593,\n      \"spoil\": 27594,\n      \"##urer\": 27595,\n      \"fatima\": 27596,\n      \"favorably\": 27597,\n      \"accumulate\": 27598,\n      \"sargent\": 27599,\n      \"sorority\": 27600,\n      \"corresponded\": 27601,\n      \"dispersal\": 27602,\n      \"kochi\": 27603,\n      \"toned\": 27604,\n      \"##imi\": 27605,\n      \"##lita\": 27606,\n      \"internacional\": 27607,\n      \"newfound\": 27608,\n      \"##agger\": 27609,\n      \"##lynn\": 27610,\n      \"##rigue\": 27611,\n      \"booths\": 27612,\n      \"peanuts\": 27613,\n      \"##eborg\": 27614,\n      \"medicare\": 27615,\n      \"muriel\": 27616,\n      \"nur\": 27617,\n      \"##uram\": 27618,\n      \"crates\": 27619,\n      \"millennia\": 27620,\n      \"pajamas\": 27621,\n      \"worsened\": 27622,\n      \"##breakers\": 27623,\n      \"jimi\": 27624,\n      \"vanuatu\": 27625,\n      \"yawned\": 27626,\n      \"##udeau\": 27627,\n      \"carousel\": 27628,\n      \"##hony\": 27629,\n      \"hurdle\": 27630,\n      \"##ccus\": 27631,\n      \"##mounted\": 27632,\n      \"##pod\": 27633,\n      \"rv\": 27634,\n      \"##eche\": 27635,\n      \"airship\": 27636,\n      \"ambiguity\": 27637,\n      \"compulsion\": 27638,\n      \"recapture\": 27639,\n      \"##claiming\": 27640,\n      \"arthritis\": 27641,\n      \"##osomal\": 27642,\n      \"1667\": 27643,\n      \"asserting\": 27644,\n      \"ngc\": 27645,\n      \"sniffing\": 27646,\n      \"dade\": 27647,\n      \"discontent\": 27648,\n      \"glendale\": 27649,\n      \"ported\": 27650,\n      \"##amina\": 27651,\n      \"defamation\": 27652,\n      \"rammed\": 27653,\n      \"##scent\": 27654,\n      \"fling\": 27655,\n      \"livingstone\": 27656,\n      \"##fleet\": 27657,\n      \"875\": 27658,\n      \"##ppy\": 27659,\n      \"apocalyptic\": 27660,\n      \"comrade\": 27661,\n      \"lcd\": 27662,\n      \"##lowe\": 27663,\n      \"cessna\": 27664,\n      \"eine\": 27665,\n      \"persecuted\": 27666,\n      \"subsistence\": 27667,\n      \"demi\": 27668,\n      \"hoop\": 27669,\n      \"reliefs\": 27670,\n      \"710\": 27671,\n      \"coptic\": 27672,\n      \"progressing\": 27673,\n      \"stemmed\": 27674,\n      \"perpetrators\": 27675,\n      \"1665\": 27676,\n      \"priestess\": 27677,\n      \"##nio\": 27678,\n      \"dobson\": 27679,\n      \"ebony\": 27680,\n      \"rooster\": 27681,\n      \"itf\": 27682,\n      \"tortricidae\": 27683,\n      \"##bbon\": 27684,\n      \"##jian\": 27685,\n      \"cleanup\": 27686,\n      \"##jean\": 27687,\n      \"##øy\": 27688,\n      \"1721\": 27689,\n      \"eighties\": 27690,\n      \"taxonomic\": 27691,\n      \"holiness\": 27692,\n      \"##hearted\": 27693,\n      \"##spar\": 27694,\n      \"antilles\": 27695,\n      \"showcasing\": 27696,\n      \"stabilized\": 27697,\n      \"##nb\": 27698,\n      \"gia\": 27699,\n      \"mascara\": 27700,\n      \"michelangelo\": 27701,\n      \"dawned\": 27702,\n      \"##uria\": 27703,\n      \"##vinsky\": 27704,\n      \"extinguished\": 27705,\n      \"fitz\": 27706,\n      \"grotesque\": 27707,\n      \"£100\": 27708,\n      \"##fera\": 27709,\n      \"##loid\": 27710,\n      \"##mous\": 27711,\n      \"barges\": 27712,\n      \"neue\": 27713,\n      \"throbbed\": 27714,\n      \"cipher\": 27715,\n      \"johnnie\": 27716,\n      \"##a1\": 27717,\n      \"##mpt\": 27718,\n      \"outburst\": 27719,\n      \"##swick\": 27720,\n      \"spearheaded\": 27721,\n      \"administrations\": 27722,\n      \"c1\": 27723,\n      \"heartbreak\": 27724,\n      \"pixels\": 27725,\n      \"pleasantly\": 27726,\n      \"##enay\": 27727,\n      \"lombardy\": 27728,\n      \"plush\": 27729,\n      \"##nsed\": 27730,\n      \"bobbie\": 27731,\n      \"##hly\": 27732,\n      \"reapers\": 27733,\n      \"tremor\": 27734,\n      \"xiang\": 27735,\n      \"minogue\": 27736,\n      \"substantive\": 27737,\n      \"hitch\": 27738,\n      \"barak\": 27739,\n      \"##wyl\": 27740,\n      \"kwan\": 27741,\n      \"##encia\": 27742,\n      \"910\": 27743,\n      \"obscene\": 27744,\n      \"elegance\": 27745,\n      \"indus\": 27746,\n      \"surfer\": 27747,\n      \"bribery\": 27748,\n      \"conserve\": 27749,\n      \"##hyllum\": 27750,\n      \"##masters\": 27751,\n      \"horatio\": 27752,\n      \"##fat\": 27753,\n      \"apes\": 27754,\n      \"rebound\": 27755,\n      \"psychotic\": 27756,\n      \"##pour\": 27757,\n      \"iteration\": 27758,\n      \"##mium\": 27759,\n      \"##vani\": 27760,\n      \"botanic\": 27761,\n      \"horribly\": 27762,\n      \"antiques\": 27763,\n      \"dispose\": 27764,\n      \"paxton\": 27765,\n      \"##hli\": 27766,\n      \"##wg\": 27767,\n      \"timeless\": 27768,\n      \"1704\": 27769,\n      \"disregard\": 27770,\n      \"engraver\": 27771,\n      \"hounds\": 27772,\n      \"##bau\": 27773,\n      \"##version\": 27774,\n      \"looted\": 27775,\n      \"uno\": 27776,\n      \"facilitates\": 27777,\n      \"groans\": 27778,\n      \"masjid\": 27779,\n      \"rutland\": 27780,\n      \"antibody\": 27781,\n      \"disqualification\": 27782,\n      \"decatur\": 27783,\n      \"footballers\": 27784,\n      \"quake\": 27785,\n      \"slacks\": 27786,\n      \"48th\": 27787,\n      \"rein\": 27788,\n      \"scribe\": 27789,\n      \"stabilize\": 27790,\n      \"commits\": 27791,\n      \"exemplary\": 27792,\n      \"tho\": 27793,\n      \"##hort\": 27794,\n      \"##chison\": 27795,\n      \"pantry\": 27796,\n      \"traversed\": 27797,\n      \"##hiti\": 27798,\n      \"disrepair\": 27799,\n      \"identifiable\": 27800,\n      \"vibrated\": 27801,\n      \"baccalaureate\": 27802,\n      \"##nnis\": 27803,\n      \"csa\": 27804,\n      \"interviewing\": 27805,\n      \"##iensis\": 27806,\n      \"##raße\": 27807,\n      \"greaves\": 27808,\n      \"wealthiest\": 27809,\n      \"343\": 27810,\n      \"classed\": 27811,\n      \"jogged\": 27812,\n      \"£5\": 27813,\n      \"##58\": 27814,\n      \"##atal\": 27815,\n      \"illuminating\": 27816,\n      \"knicks\": 27817,\n      \"respecting\": 27818,\n      \"##uno\": 27819,\n      \"scrubbed\": 27820,\n      \"##iji\": 27821,\n      \"##dles\": 27822,\n      \"kruger\": 27823,\n      \"moods\": 27824,\n      \"growls\": 27825,\n      \"raider\": 27826,\n      \"silvia\": 27827,\n      \"chefs\": 27828,\n      \"kam\": 27829,\n      \"vr\": 27830,\n      \"cree\": 27831,\n      \"percival\": 27832,\n      \"##terol\": 27833,\n      \"gunter\": 27834,\n      \"counterattack\": 27835,\n      \"defiant\": 27836,\n      \"henan\": 27837,\n      \"ze\": 27838,\n      \"##rasia\": 27839,\n      \"##riety\": 27840,\n      \"equivalence\": 27841,\n      \"submissions\": 27842,\n      \"##fra\": 27843,\n      \"##thor\": 27844,\n      \"bautista\": 27845,\n      \"mechanically\": 27846,\n      \"##heater\": 27847,\n      \"cornice\": 27848,\n      \"herbal\": 27849,\n      \"templar\": 27850,\n      \"##mering\": 27851,\n      \"outputs\": 27852,\n      \"ruining\": 27853,\n      \"ligand\": 27854,\n      \"renumbered\": 27855,\n      \"extravagant\": 27856,\n      \"mika\": 27857,\n      \"blockbuster\": 27858,\n      \"eta\": 27859,\n      \"insurrection\": 27860,\n      \"##ilia\": 27861,\n      \"darkening\": 27862,\n      \"ferocious\": 27863,\n      \"pianos\": 27864,\n      \"strife\": 27865,\n      \"kinship\": 27866,\n      \"##aer\": 27867,\n      \"melee\": 27868,\n      \"##anor\": 27869,\n      \"##iste\": 27870,\n      \"##may\": 27871,\n      \"##oue\": 27872,\n      \"decidedly\": 27873,\n      \"weep\": 27874,\n      \"##jad\": 27875,\n      \"##missive\": 27876,\n      \"##ppel\": 27877,\n      \"354\": 27878,\n      \"puget\": 27879,\n      \"unease\": 27880,\n      \"##gnant\": 27881,\n      \"1629\": 27882,\n      \"hammering\": 27883,\n      \"kassel\": 27884,\n      \"ob\": 27885,\n      \"wessex\": 27886,\n      \"##lga\": 27887,\n      \"bromwich\": 27888,\n      \"egan\": 27889,\n      \"paranoia\": 27890,\n      \"utilization\": 27891,\n      \"##atable\": 27892,\n      \"##idad\": 27893,\n      \"contradictory\": 27894,\n      \"provoke\": 27895,\n      \"##ols\": 27896,\n      \"##ouring\": 27897,\n      \"##tangled\": 27898,\n      \"knesset\": 27899,\n      \"##very\": 27900,\n      \"##lette\": 27901,\n      \"plumbing\": 27902,\n      \"##sden\": 27903,\n      \"##¹\": 27904,\n      \"greensboro\": 27905,\n      \"occult\": 27906,\n      \"sniff\": 27907,\n      \"338\": 27908,\n      \"zev\": 27909,\n      \"beaming\": 27910,\n      \"gamer\": 27911,\n      \"haggard\": 27912,\n      \"mahal\": 27913,\n      \"##olt\": 27914,\n      \"##pins\": 27915,\n      \"mendes\": 27916,\n      \"utmost\": 27917,\n      \"briefing\": 27918,\n      \"gunnery\": 27919,\n      \"##gut\": 27920,\n      \"##pher\": 27921,\n      \"##zh\": 27922,\n      \"##rok\": 27923,\n      \"1679\": 27924,\n      \"khalifa\": 27925,\n      \"sonya\": 27926,\n      \"##boot\": 27927,\n      \"principals\": 27928,\n      \"urbana\": 27929,\n      \"wiring\": 27930,\n      \"##liffe\": 27931,\n      \"##minating\": 27932,\n      \"##rrado\": 27933,\n      \"dahl\": 27934,\n      \"nyu\": 27935,\n      \"skepticism\": 27936,\n      \"np\": 27937,\n      \"townspeople\": 27938,\n      \"ithaca\": 27939,\n      \"lobster\": 27940,\n      \"somethin\": 27941,\n      \"##fur\": 27942,\n      \"##arina\": 27943,\n      \"##−1\": 27944,\n      \"freighter\": 27945,\n      \"zimmerman\": 27946,\n      \"biceps\": 27947,\n      \"contractual\": 27948,\n      \"##herton\": 27949,\n      \"amend\": 27950,\n      \"hurrying\": 27951,\n      \"subconscious\": 27952,\n      \"##anal\": 27953,\n      \"336\": 27954,\n      \"meng\": 27955,\n      \"clermont\": 27956,\n      \"spawning\": 27957,\n      \"##eia\": 27958,\n      \"##lub\": 27959,\n      \"dignitaries\": 27960,\n      \"impetus\": 27961,\n      \"snacks\": 27962,\n      \"spotting\": 27963,\n      \"twigs\": 27964,\n      \"##bilis\": 27965,\n      \"##cz\": 27966,\n      \"##ouk\": 27967,\n      \"libertadores\": 27968,\n      \"nic\": 27969,\n      \"skylar\": 27970,\n      \"##aina\": 27971,\n      \"##firm\": 27972,\n      \"gustave\": 27973,\n      \"asean\": 27974,\n      \"##anum\": 27975,\n      \"dieter\": 27976,\n      \"legislatures\": 27977,\n      \"flirt\": 27978,\n      \"bromley\": 27979,\n      \"trolls\": 27980,\n      \"umar\": 27981,\n      \"##bbies\": 27982,\n      \"##tyle\": 27983,\n      \"blah\": 27984,\n      \"parc\": 27985,\n      \"bridgeport\": 27986,\n      \"crank\": 27987,\n      \"negligence\": 27988,\n      \"##nction\": 27989,\n      \"46th\": 27990,\n      \"constantin\": 27991,\n      \"molded\": 27992,\n      \"bandages\": 27993,\n      \"seriousness\": 27994,\n      \"00pm\": 27995,\n      \"siegel\": 27996,\n      \"carpets\": 27997,\n      \"compartments\": 27998,\n      \"upbeat\": 27999,\n      \"statehood\": 28000,\n      \"##dner\": 28001,\n      \"##edging\": 28002,\n      \"marko\": 28003,\n      \"730\": 28004,\n      \"platt\": 28005,\n      \"##hane\": 28006,\n      \"paving\": 28007,\n      \"##iy\": 28008,\n      \"1738\": 28009,\n      \"abbess\": 28010,\n      \"impatience\": 28011,\n      \"limousine\": 28012,\n      \"nbl\": 28013,\n      \"##talk\": 28014,\n      \"441\": 28015,\n      \"lucille\": 28016,\n      \"mojo\": 28017,\n      \"nightfall\": 28018,\n      \"robbers\": 28019,\n      \"##nais\": 28020,\n      \"karel\": 28021,\n      \"brisk\": 28022,\n      \"calves\": 28023,\n      \"replicate\": 28024,\n      \"ascribed\": 28025,\n      \"telescopes\": 28026,\n      \"##olf\": 28027,\n      \"intimidated\": 28028,\n      \"##reen\": 28029,\n      \"ballast\": 28030,\n      \"specialization\": 28031,\n      \"##sit\": 28032,\n      \"aerodynamic\": 28033,\n      \"caliphate\": 28034,\n      \"rainer\": 28035,\n      \"visionary\": 28036,\n      \"##arded\": 28037,\n      \"epsilon\": 28038,\n      \"##aday\": 28039,\n      \"##onte\": 28040,\n      \"aggregation\": 28041,\n      \"auditory\": 28042,\n      \"boosted\": 28043,\n      \"reunification\": 28044,\n      \"kathmandu\": 28045,\n      \"loco\": 28046,\n      \"robyn\": 28047,\n      \"402\": 28048,\n      \"acknowledges\": 28049,\n      \"appointing\": 28050,\n      \"humanoid\": 28051,\n      \"newell\": 28052,\n      \"redeveloped\": 28053,\n      \"restraints\": 28054,\n      \"##tained\": 28055,\n      \"barbarians\": 28056,\n      \"chopper\": 28057,\n      \"1609\": 28058,\n      \"italiana\": 28059,\n      \"##lez\": 28060,\n      \"##lho\": 28061,\n      \"investigates\": 28062,\n      \"wrestlemania\": 28063,\n      \"##anies\": 28064,\n      \"##bib\": 28065,\n      \"690\": 28066,\n      \"##falls\": 28067,\n      \"creaked\": 28068,\n      \"dragoons\": 28069,\n      \"gravely\": 28070,\n      \"minions\": 28071,\n      \"stupidity\": 28072,\n      \"volley\": 28073,\n      \"##harat\": 28074,\n      \"##week\": 28075,\n      \"musik\": 28076,\n      \"##eries\": 28077,\n      \"##uously\": 28078,\n      \"fungal\": 28079,\n      \"massimo\": 28080,\n      \"semantics\": 28081,\n      \"malvern\": 28082,\n      \"##ahl\": 28083,\n      \"##pee\": 28084,\n      \"discourage\": 28085,\n      \"embryo\": 28086,\n      \"imperialism\": 28087,\n      \"1910s\": 28088,\n      \"profoundly\": 28089,\n      \"##ddled\": 28090,\n      \"jiangsu\": 28091,\n      \"sparkled\": 28092,\n      \"stat\": 28093,\n      \"##holz\": 28094,\n      \"sweatshirt\": 28095,\n      \"tobin\": 28096,\n      \"##iction\": 28097,\n      \"sneered\": 28098,\n      \"##cheon\": 28099,\n      \"##oit\": 28100,\n      \"brit\": 28101,\n      \"causal\": 28102,\n      \"smyth\": 28103,\n      \"##neuve\": 28104,\n      \"diffuse\": 28105,\n      \"perrin\": 28106,\n      \"silvio\": 28107,\n      \"##ipes\": 28108,\n      \"##recht\": 28109,\n      \"detonated\": 28110,\n      \"iqbal\": 28111,\n      \"selma\": 28112,\n      \"##nism\": 28113,\n      \"##zumi\": 28114,\n      \"roasted\": 28115,\n      \"##riders\": 28116,\n      \"tay\": 28117,\n      \"##ados\": 28118,\n      \"##mament\": 28119,\n      \"##mut\": 28120,\n      \"##rud\": 28121,\n      \"840\": 28122,\n      \"completes\": 28123,\n      \"nipples\": 28124,\n      \"cfa\": 28125,\n      \"flavour\": 28126,\n      \"hirsch\": 28127,\n      \"##laus\": 28128,\n      \"calderon\": 28129,\n      \"sneakers\": 28130,\n      \"moravian\": 28131,\n      \"##ksha\": 28132,\n      \"1622\": 28133,\n      \"rq\": 28134,\n      \"294\": 28135,\n      \"##imeters\": 28136,\n      \"bodo\": 28137,\n      \"##isance\": 28138,\n      \"##pre\": 28139,\n      \"##ronia\": 28140,\n      \"anatomical\": 28141,\n      \"excerpt\": 28142,\n      \"##lke\": 28143,\n      \"dh\": 28144,\n      \"kunst\": 28145,\n      \"##tablished\": 28146,\n      \"##scoe\": 28147,\n      \"biomass\": 28148,\n      \"panted\": 28149,\n      \"unharmed\": 28150,\n      \"gael\": 28151,\n      \"housemates\": 28152,\n      \"montpellier\": 28153,\n      \"##59\": 28154,\n      \"coa\": 28155,\n      \"rodents\": 28156,\n      \"tonic\": 28157,\n      \"hickory\": 28158,\n      \"singleton\": 28159,\n      \"##taro\": 28160,\n      \"451\": 28161,\n      \"1719\": 28162,\n      \"aldo\": 28163,\n      \"breaststroke\": 28164,\n      \"dempsey\": 28165,\n      \"och\": 28166,\n      \"rocco\": 28167,\n      \"##cuit\": 28168,\n      \"merton\": 28169,\n      \"dissemination\": 28170,\n      \"midsummer\": 28171,\n      \"serials\": 28172,\n      \"##idi\": 28173,\n      \"haji\": 28174,\n      \"polynomials\": 28175,\n      \"##rdon\": 28176,\n      \"gs\": 28177,\n      \"enoch\": 28178,\n      \"prematurely\": 28179,\n      \"shutter\": 28180,\n      \"taunton\": 28181,\n      \"£3\": 28182,\n      \"##grating\": 28183,\n      \"##inates\": 28184,\n      \"archangel\": 28185,\n      \"harassed\": 28186,\n      \"##asco\": 28187,\n      \"326\": 28188,\n      \"archway\": 28189,\n      \"dazzling\": 28190,\n      \"##ecin\": 28191,\n      \"1736\": 28192,\n      \"sumo\": 28193,\n      \"wat\": 28194,\n      \"##kovich\": 28195,\n      \"1086\": 28196,\n      \"honneur\": 28197,\n      \"##ently\": 28198,\n      \"##nostic\": 28199,\n      \"##ttal\": 28200,\n      \"##idon\": 28201,\n      \"1605\": 28202,\n      \"403\": 28203,\n      \"1716\": 28204,\n      \"blogger\": 28205,\n      \"rents\": 28206,\n      \"##gnan\": 28207,\n      \"hires\": 28208,\n      \"##ikh\": 28209,\n      \"##dant\": 28210,\n      \"howie\": 28211,\n      \"##rons\": 28212,\n      \"handler\": 28213,\n      \"retracted\": 28214,\n      \"shocks\": 28215,\n      \"1632\": 28216,\n      \"arun\": 28217,\n      \"duluth\": 28218,\n      \"kepler\": 28219,\n      \"trumpeter\": 28220,\n      \"##lary\": 28221,\n      \"peeking\": 28222,\n      \"seasoned\": 28223,\n      \"trooper\": 28224,\n      \"##mara\": 28225,\n      \"laszlo\": 28226,\n      \"##iciencies\": 28227,\n      \"##rti\": 28228,\n      \"heterosexual\": 28229,\n      \"##inatory\": 28230,\n      \"##ssion\": 28231,\n      \"indira\": 28232,\n      \"jogging\": 28233,\n      \"##inga\": 28234,\n      \"##lism\": 28235,\n      \"beit\": 28236,\n      \"dissatisfaction\": 28237,\n      \"malice\": 28238,\n      \"##ately\": 28239,\n      \"nedra\": 28240,\n      \"peeling\": 28241,\n      \"##rgeon\": 28242,\n      \"47th\": 28243,\n      \"stadiums\": 28244,\n      \"475\": 28245,\n      \"vertigo\": 28246,\n      \"##ains\": 28247,\n      \"iced\": 28248,\n      \"restroom\": 28249,\n      \"##plify\": 28250,\n      \"##tub\": 28251,\n      \"illustrating\": 28252,\n      \"pear\": 28253,\n      \"##chner\": 28254,\n      \"##sibility\": 28255,\n      \"inorganic\": 28256,\n      \"rappers\": 28257,\n      \"receipts\": 28258,\n      \"watery\": 28259,\n      \"##kura\": 28260,\n      \"lucinda\": 28261,\n      \"##oulos\": 28262,\n      \"reintroduced\": 28263,\n      \"##8th\": 28264,\n      \"##tched\": 28265,\n      \"gracefully\": 28266,\n      \"saxons\": 28267,\n      \"nutritional\": 28268,\n      \"wastewater\": 28269,\n      \"rained\": 28270,\n      \"favourites\": 28271,\n      \"bedrock\": 28272,\n      \"fisted\": 28273,\n      \"hallways\": 28274,\n      \"likeness\": 28275,\n      \"upscale\": 28276,\n      \"##lateral\": 28277,\n      \"1580\": 28278,\n      \"blinds\": 28279,\n      \"prequel\": 28280,\n      \"##pps\": 28281,\n      \"##tama\": 28282,\n      \"deter\": 28283,\n      \"humiliating\": 28284,\n      \"restraining\": 28285,\n      \"tn\": 28286,\n      \"vents\": 28287,\n      \"1659\": 28288,\n      \"laundering\": 28289,\n      \"recess\": 28290,\n      \"rosary\": 28291,\n      \"tractors\": 28292,\n      \"coulter\": 28293,\n      \"federer\": 28294,\n      \"##ifiers\": 28295,\n      \"##plin\": 28296,\n      \"persistence\": 28297,\n      \"##quitable\": 28298,\n      \"geschichte\": 28299,\n      \"pendulum\": 28300,\n      \"quakers\": 28301,\n      \"##beam\": 28302,\n      \"bassett\": 28303,\n      \"pictorial\": 28304,\n      \"buffet\": 28305,\n      \"koln\": 28306,\n      \"##sitor\": 28307,\n      \"drills\": 28308,\n      \"reciprocal\": 28309,\n      \"shooters\": 28310,\n      \"##57\": 28311,\n      \"##cton\": 28312,\n      \"##tees\": 28313,\n      \"converge\": 28314,\n      \"pip\": 28315,\n      \"dmitri\": 28316,\n      \"donnelly\": 28317,\n      \"yamamoto\": 28318,\n      \"aqua\": 28319,\n      \"azores\": 28320,\n      \"demographics\": 28321,\n      \"hypnotic\": 28322,\n      \"spitfire\": 28323,\n      \"suspend\": 28324,\n      \"wryly\": 28325,\n      \"roderick\": 28326,\n      \"##rran\": 28327,\n      \"sebastien\": 28328,\n      \"##asurable\": 28329,\n      \"mavericks\": 28330,\n      \"##fles\": 28331,\n      \"##200\": 28332,\n      \"himalayan\": 28333,\n      \"prodigy\": 28334,\n      \"##iance\": 28335,\n      \"transvaal\": 28336,\n      \"demonstrators\": 28337,\n      \"handcuffs\": 28338,\n      \"dodged\": 28339,\n      \"mcnamara\": 28340,\n      \"sublime\": 28341,\n      \"1726\": 28342,\n      \"crazed\": 28343,\n      \"##efined\": 28344,\n      \"##till\": 28345,\n      \"ivo\": 28346,\n      \"pondered\": 28347,\n      \"reconciled\": 28348,\n      \"shrill\": 28349,\n      \"sava\": 28350,\n      \"##duk\": 28351,\n      \"bal\": 28352,\n      \"cad\": 28353,\n      \"heresy\": 28354,\n      \"jaipur\": 28355,\n      \"goran\": 28356,\n      \"##nished\": 28357,\n      \"341\": 28358,\n      \"lux\": 28359,\n      \"shelly\": 28360,\n      \"whitehall\": 28361,\n      \"##hre\": 28362,\n      \"israelis\": 28363,\n      \"peacekeeping\": 28364,\n      \"##wled\": 28365,\n      \"1703\": 28366,\n      \"demetrius\": 28367,\n      \"ousted\": 28368,\n      \"##arians\": 28369,\n      \"##zos\": 28370,\n      \"beale\": 28371,\n      \"anwar\": 28372,\n      \"backstroke\": 28373,\n      \"raged\": 28374,\n      \"shrinking\": 28375,\n      \"cremated\": 28376,\n      \"##yck\": 28377,\n      \"benign\": 28378,\n      \"towing\": 28379,\n      \"wadi\": 28380,\n      \"darmstadt\": 28381,\n      \"landfill\": 28382,\n      \"parana\": 28383,\n      \"soothe\": 28384,\n      \"colleen\": 28385,\n      \"sidewalks\": 28386,\n      \"mayfair\": 28387,\n      \"tumble\": 28388,\n      \"hepatitis\": 28389,\n      \"ferrer\": 28390,\n      \"superstructure\": 28391,\n      \"##gingly\": 28392,\n      \"##urse\": 28393,\n      \"##wee\": 28394,\n      \"anthropological\": 28395,\n      \"translators\": 28396,\n      \"##mies\": 28397,\n      \"closeness\": 28398,\n      \"hooves\": 28399,\n      \"##pw\": 28400,\n      \"mondays\": 28401,\n      \"##roll\": 28402,\n      \"##vita\": 28403,\n      \"landscaping\": 28404,\n      \"##urized\": 28405,\n      \"purification\": 28406,\n      \"sock\": 28407,\n      \"thorns\": 28408,\n      \"thwarted\": 28409,\n      \"jalan\": 28410,\n      \"tiberius\": 28411,\n      \"##taka\": 28412,\n      \"saline\": 28413,\n      \"##rito\": 28414,\n      \"confidently\": 28415,\n      \"khyber\": 28416,\n      \"sculptors\": 28417,\n      \"##ij\": 28418,\n      \"brahms\": 28419,\n      \"hammersmith\": 28420,\n      \"inspectors\": 28421,\n      \"battista\": 28422,\n      \"fivb\": 28423,\n      \"fragmentation\": 28424,\n      \"hackney\": 28425,\n      \"##uls\": 28426,\n      \"arresting\": 28427,\n      \"exercising\": 28428,\n      \"antoinette\": 28429,\n      \"bedfordshire\": 28430,\n      \"##zily\": 28431,\n      \"dyed\": 28432,\n      \"##hema\": 28433,\n      \"1656\": 28434,\n      \"racetrack\": 28435,\n      \"variability\": 28436,\n      \"##tique\": 28437,\n      \"1655\": 28438,\n      \"austrians\": 28439,\n      \"deteriorating\": 28440,\n      \"madman\": 28441,\n      \"theorists\": 28442,\n      \"aix\": 28443,\n      \"lehman\": 28444,\n      \"weathered\": 28445,\n      \"1731\": 28446,\n      \"decreed\": 28447,\n      \"eruptions\": 28448,\n      \"1729\": 28449,\n      \"flaw\": 28450,\n      \"quinlan\": 28451,\n      \"sorbonne\": 28452,\n      \"flutes\": 28453,\n      \"nunez\": 28454,\n      \"1711\": 28455,\n      \"adored\": 28456,\n      \"downwards\": 28457,\n      \"fable\": 28458,\n      \"rasped\": 28459,\n      \"1712\": 28460,\n      \"moritz\": 28461,\n      \"mouthful\": 28462,\n      \"renegade\": 28463,\n      \"shivers\": 28464,\n      \"stunts\": 28465,\n      \"dysfunction\": 28466,\n      \"restrain\": 28467,\n      \"translit\": 28468,\n      \"327\": 28469,\n      \"pancakes\": 28470,\n      \"##avio\": 28471,\n      \"##cision\": 28472,\n      \"##tray\": 28473,\n      \"351\": 28474,\n      \"vial\": 28475,\n      \"##lden\": 28476,\n      \"bain\": 28477,\n      \"##maid\": 28478,\n      \"##oxide\": 28479,\n      \"chihuahua\": 28480,\n      \"malacca\": 28481,\n      \"vimes\": 28482,\n      \"##rba\": 28483,\n      \"##rnier\": 28484,\n      \"1664\": 28485,\n      \"donnie\": 28486,\n      \"plaques\": 28487,\n      \"##ually\": 28488,\n      \"337\": 28489,\n      \"bangs\": 28490,\n      \"floppy\": 28491,\n      \"huntsville\": 28492,\n      \"loretta\": 28493,\n      \"nikolay\": 28494,\n      \"##otte\": 28495,\n      \"eater\": 28496,\n      \"handgun\": 28497,\n      \"ubiquitous\": 28498,\n      \"##hett\": 28499,\n      \"eras\": 28500,\n      \"zodiac\": 28501,\n      \"1634\": 28502,\n      \"##omorphic\": 28503,\n      \"1820s\": 28504,\n      \"##zog\": 28505,\n      \"cochran\": 28506,\n      \"##bula\": 28507,\n      \"##lithic\": 28508,\n      \"warring\": 28509,\n      \"##rada\": 28510,\n      \"dalai\": 28511,\n      \"excused\": 28512,\n      \"blazers\": 28513,\n      \"mcconnell\": 28514,\n      \"reeling\": 28515,\n      \"bot\": 28516,\n      \"este\": 28517,\n      \"##abi\": 28518,\n      \"geese\": 28519,\n      \"hoax\": 28520,\n      \"taxon\": 28521,\n      \"##bla\": 28522,\n      \"guitarists\": 28523,\n      \"##icon\": 28524,\n      \"condemning\": 28525,\n      \"hunts\": 28526,\n      \"inversion\": 28527,\n      \"moffat\": 28528,\n      \"taekwondo\": 28529,\n      \"##lvis\": 28530,\n      \"1624\": 28531,\n      \"stammered\": 28532,\n      \"##rest\": 28533,\n      \"##rzy\": 28534,\n      \"sousa\": 28535,\n      \"fundraiser\": 28536,\n      \"marylebone\": 28537,\n      \"navigable\": 28538,\n      \"uptown\": 28539,\n      \"cabbage\": 28540,\n      \"daniela\": 28541,\n      \"salman\": 28542,\n      \"shitty\": 28543,\n      \"whimper\": 28544,\n      \"##kian\": 28545,\n      \"##utive\": 28546,\n      \"programmers\": 28547,\n      \"protections\": 28548,\n      \"rm\": 28549,\n      \"##rmi\": 28550,\n      \"##rued\": 28551,\n      \"forceful\": 28552,\n      \"##enes\": 28553,\n      \"fuss\": 28554,\n      \"##tao\": 28555,\n      \"##wash\": 28556,\n      \"brat\": 28557,\n      \"oppressive\": 28558,\n      \"reykjavik\": 28559,\n      \"spartak\": 28560,\n      \"ticking\": 28561,\n      \"##inkles\": 28562,\n      \"##kiewicz\": 28563,\n      \"adolph\": 28564,\n      \"horst\": 28565,\n      \"maui\": 28566,\n      \"protege\": 28567,\n      \"straighten\": 28568,\n      \"cpc\": 28569,\n      \"landau\": 28570,\n      \"concourse\": 28571,\n      \"clements\": 28572,\n      \"resultant\": 28573,\n      \"##ando\": 28574,\n      \"imaginative\": 28575,\n      \"joo\": 28576,\n      \"reactivated\": 28577,\n      \"##rem\": 28578,\n      \"##ffled\": 28579,\n      \"##uising\": 28580,\n      \"consultative\": 28581,\n      \"##guide\": 28582,\n      \"flop\": 28583,\n      \"kaitlyn\": 28584,\n      \"mergers\": 28585,\n      \"parenting\": 28586,\n      \"somber\": 28587,\n      \"##vron\": 28588,\n      \"supervise\": 28589,\n      \"vidhan\": 28590,\n      \"##imum\": 28591,\n      \"courtship\": 28592,\n      \"exemplified\": 28593,\n      \"harmonies\": 28594,\n      \"medallist\": 28595,\n      \"refining\": 28596,\n      \"##rrow\": 28597,\n      \"##ка\": 28598,\n      \"amara\": 28599,\n      \"##hum\": 28600,\n      \"780\": 28601,\n      \"goalscorer\": 28602,\n      \"sited\": 28603,\n      \"overshadowed\": 28604,\n      \"rohan\": 28605,\n      \"displeasure\": 28606,\n      \"secretive\": 28607,\n      \"multiplied\": 28608,\n      \"osman\": 28609,\n      \"##orth\": 28610,\n      \"engravings\": 28611,\n      \"padre\": 28612,\n      \"##kali\": 28613,\n      \"##veda\": 28614,\n      \"miniatures\": 28615,\n      \"mis\": 28616,\n      \"##yala\": 28617,\n      \"clap\": 28618,\n      \"pali\": 28619,\n      \"rook\": 28620,\n      \"##cana\": 28621,\n      \"1692\": 28622,\n      \"57th\": 28623,\n      \"antennae\": 28624,\n      \"astro\": 28625,\n      \"oskar\": 28626,\n      \"1628\": 28627,\n      \"bulldog\": 28628,\n      \"crotch\": 28629,\n      \"hackett\": 28630,\n      \"yucatan\": 28631,\n      \"##sure\": 28632,\n      \"amplifiers\": 28633,\n      \"brno\": 28634,\n      \"ferrara\": 28635,\n      \"migrating\": 28636,\n      \"##gree\": 28637,\n      \"thanking\": 28638,\n      \"turing\": 28639,\n      \"##eza\": 28640,\n      \"mccann\": 28641,\n      \"ting\": 28642,\n      \"andersson\": 28643,\n      \"onslaught\": 28644,\n      \"gaines\": 28645,\n      \"ganga\": 28646,\n      \"incense\": 28647,\n      \"standardization\": 28648,\n      \"##mation\": 28649,\n      \"sentai\": 28650,\n      \"scuba\": 28651,\n      \"stuffing\": 28652,\n      \"turquoise\": 28653,\n      \"waivers\": 28654,\n      \"alloys\": 28655,\n      \"##vitt\": 28656,\n      \"regaining\": 28657,\n      \"vaults\": 28658,\n      \"##clops\": 28659,\n      \"##gizing\": 28660,\n      \"digger\": 28661,\n      \"furry\": 28662,\n      \"memorabilia\": 28663,\n      \"probing\": 28664,\n      \"##iad\": 28665,\n      \"payton\": 28666,\n      \"rec\": 28667,\n      \"deutschland\": 28668,\n      \"filippo\": 28669,\n      \"opaque\": 28670,\n      \"seamen\": 28671,\n      \"zenith\": 28672,\n      \"afrikaans\": 28673,\n      \"##filtration\": 28674,\n      \"disciplined\": 28675,\n      \"inspirational\": 28676,\n      \"##merie\": 28677,\n      \"banco\": 28678,\n      \"confuse\": 28679,\n      \"grafton\": 28680,\n      \"tod\": 28681,\n      \"##dgets\": 28682,\n      \"championed\": 28683,\n      \"simi\": 28684,\n      \"anomaly\": 28685,\n      \"biplane\": 28686,\n      \"##ceptive\": 28687,\n      \"electrode\": 28688,\n      \"##para\": 28689,\n      \"1697\": 28690,\n      \"cleavage\": 28691,\n      \"crossbow\": 28692,\n      \"swirl\": 28693,\n      \"informant\": 28694,\n      \"##lars\": 28695,\n      \"##osta\": 28696,\n      \"afi\": 28697,\n      \"bonfire\": 28698,\n      \"spec\": 28699,\n      \"##oux\": 28700,\n      \"lakeside\": 28701,\n      \"slump\": 28702,\n      \"##culus\": 28703,\n      \"##lais\": 28704,\n      \"##qvist\": 28705,\n      \"##rrigan\": 28706,\n      \"1016\": 28707,\n      \"facades\": 28708,\n      \"borg\": 28709,\n      \"inwardly\": 28710,\n      \"cervical\": 28711,\n      \"xl\": 28712,\n      \"pointedly\": 28713,\n      \"050\": 28714,\n      \"stabilization\": 28715,\n      \"##odon\": 28716,\n      \"chests\": 28717,\n      \"1699\": 28718,\n      \"hacked\": 28719,\n      \"ctv\": 28720,\n      \"orthogonal\": 28721,\n      \"suzy\": 28722,\n      \"##lastic\": 28723,\n      \"gaulle\": 28724,\n      \"jacobite\": 28725,\n      \"rearview\": 28726,\n      \"##cam\": 28727,\n      \"##erted\": 28728,\n      \"ashby\": 28729,\n      \"##drik\": 28730,\n      \"##igate\": 28731,\n      \"##mise\": 28732,\n      \"##zbek\": 28733,\n      \"affectionately\": 28734,\n      \"canine\": 28735,\n      \"disperse\": 28736,\n      \"latham\": 28737,\n      \"##istles\": 28738,\n      \"##ivar\": 28739,\n      \"spielberg\": 28740,\n      \"##orin\": 28741,\n      \"##idium\": 28742,\n      \"ezekiel\": 28743,\n      \"cid\": 28744,\n      \"##sg\": 28745,\n      \"durga\": 28746,\n      \"middletown\": 28747,\n      \"##cina\": 28748,\n      \"customized\": 28749,\n      \"frontiers\": 28750,\n      \"harden\": 28751,\n      \"##etano\": 28752,\n      \"##zzy\": 28753,\n      \"1604\": 28754,\n      \"bolsheviks\": 28755,\n      \"##66\": 28756,\n      \"coloration\": 28757,\n      \"yoko\": 28758,\n      \"##bedo\": 28759,\n      \"briefs\": 28760,\n      \"slabs\": 28761,\n      \"debra\": 28762,\n      \"liquidation\": 28763,\n      \"plumage\": 28764,\n      \"##oin\": 28765,\n      \"blossoms\": 28766,\n      \"dementia\": 28767,\n      \"subsidy\": 28768,\n      \"1611\": 28769,\n      \"proctor\": 28770,\n      \"relational\": 28771,\n      \"jerseys\": 28772,\n      \"parochial\": 28773,\n      \"ter\": 28774,\n      \"##ici\": 28775,\n      \"esa\": 28776,\n      \"peshawar\": 28777,\n      \"cavalier\": 28778,\n      \"loren\": 28779,\n      \"cpi\": 28780,\n      \"idiots\": 28781,\n      \"shamrock\": 28782,\n      \"1646\": 28783,\n      \"dutton\": 28784,\n      \"malabar\": 28785,\n      \"mustache\": 28786,\n      \"##endez\": 28787,\n      \"##ocytes\": 28788,\n      \"referencing\": 28789,\n      \"terminates\": 28790,\n      \"marche\": 28791,\n      \"yarmouth\": 28792,\n      \"##sop\": 28793,\n      \"acton\": 28794,\n      \"mated\": 28795,\n      \"seton\": 28796,\n      \"subtly\": 28797,\n      \"baptised\": 28798,\n      \"beige\": 28799,\n      \"extremes\": 28800,\n      \"jolted\": 28801,\n      \"kristina\": 28802,\n      \"telecast\": 28803,\n      \"##actic\": 28804,\n      \"safeguard\": 28805,\n      \"waldo\": 28806,\n      \"##baldi\": 28807,\n      \"##bular\": 28808,\n      \"endeavors\": 28809,\n      \"sloppy\": 28810,\n      \"subterranean\": 28811,\n      \"##ensburg\": 28812,\n      \"##itung\": 28813,\n      \"delicately\": 28814,\n      \"pigment\": 28815,\n      \"tq\": 28816,\n      \"##scu\": 28817,\n      \"1626\": 28818,\n      \"##ound\": 28819,\n      \"collisions\": 28820,\n      \"coveted\": 28821,\n      \"herds\": 28822,\n      \"##personal\": 28823,\n      \"##meister\": 28824,\n      \"##nberger\": 28825,\n      \"chopra\": 28826,\n      \"##ricting\": 28827,\n      \"abnormalities\": 28828,\n      \"defective\": 28829,\n      \"galician\": 28830,\n      \"lucie\": 28831,\n      \"##dilly\": 28832,\n      \"alligator\": 28833,\n      \"likened\": 28834,\n      \"##genase\": 28835,\n      \"burundi\": 28836,\n      \"clears\": 28837,\n      \"complexion\": 28838,\n      \"derelict\": 28839,\n      \"deafening\": 28840,\n      \"diablo\": 28841,\n      \"fingered\": 28842,\n      \"champaign\": 28843,\n      \"dogg\": 28844,\n      \"enlist\": 28845,\n      \"isotope\": 28846,\n      \"labeling\": 28847,\n      \"mrna\": 28848,\n      \"##erre\": 28849,\n      \"brilliance\": 28850,\n      \"marvelous\": 28851,\n      \"##ayo\": 28852,\n      \"1652\": 28853,\n      \"crawley\": 28854,\n      \"ether\": 28855,\n      \"footed\": 28856,\n      \"dwellers\": 28857,\n      \"deserts\": 28858,\n      \"hamish\": 28859,\n      \"rubs\": 28860,\n      \"warlock\": 28861,\n      \"skimmed\": 28862,\n      \"##lizer\": 28863,\n      \"870\": 28864,\n      \"buick\": 28865,\n      \"embark\": 28866,\n      \"heraldic\": 28867,\n      \"irregularities\": 28868,\n      \"##ajan\": 28869,\n      \"kiara\": 28870,\n      \"##kulam\": 28871,\n      \"##ieg\": 28872,\n      \"antigen\": 28873,\n      \"kowalski\": 28874,\n      \"##lge\": 28875,\n      \"oakley\": 28876,\n      \"visitation\": 28877,\n      \"##mbit\": 28878,\n      \"vt\": 28879,\n      \"##suit\": 28880,\n      \"1570\": 28881,\n      \"murderers\": 28882,\n      \"##miento\": 28883,\n      \"##rites\": 28884,\n      \"chimneys\": 28885,\n      \"##sling\": 28886,\n      \"condemn\": 28887,\n      \"custer\": 28888,\n      \"exchequer\": 28889,\n      \"havre\": 28890,\n      \"##ghi\": 28891,\n      \"fluctuations\": 28892,\n      \"##rations\": 28893,\n      \"dfb\": 28894,\n      \"hendricks\": 28895,\n      \"vaccines\": 28896,\n      \"##tarian\": 28897,\n      \"nietzsche\": 28898,\n      \"biking\": 28899,\n      \"juicy\": 28900,\n      \"##duced\": 28901,\n      \"brooding\": 28902,\n      \"scrolling\": 28903,\n      \"selangor\": 28904,\n      \"##ragan\": 28905,\n      \"352\": 28906,\n      \"annum\": 28907,\n      \"boomed\": 28908,\n      \"seminole\": 28909,\n      \"sugarcane\": 28910,\n      \"##dna\": 28911,\n      \"departmental\": 28912,\n      \"dismissing\": 28913,\n      \"innsbruck\": 28914,\n      \"arteries\": 28915,\n      \"ashok\": 28916,\n      \"batavia\": 28917,\n      \"daze\": 28918,\n      \"kun\": 28919,\n      \"overtook\": 28920,\n      \"##rga\": 28921,\n      \"##tlan\": 28922,\n      \"beheaded\": 28923,\n      \"gaddafi\": 28924,\n      \"holm\": 28925,\n      \"electronically\": 28926,\n      \"faulty\": 28927,\n      \"galilee\": 28928,\n      \"fractures\": 28929,\n      \"kobayashi\": 28930,\n      \"##lized\": 28931,\n      \"gunmen\": 28932,\n      \"magma\": 28933,\n      \"aramaic\": 28934,\n      \"mala\": 28935,\n      \"eastenders\": 28936,\n      \"inference\": 28937,\n      \"messengers\": 28938,\n      \"bf\": 28939,\n      \"##qu\": 28940,\n      \"407\": 28941,\n      \"bathrooms\": 28942,\n      \"##vere\": 28943,\n      \"1658\": 28944,\n      \"flashbacks\": 28945,\n      \"ideally\": 28946,\n      \"misunderstood\": 28947,\n      \"##jali\": 28948,\n      \"##weather\": 28949,\n      \"mendez\": 28950,\n      \"##grounds\": 28951,\n      \"505\": 28952,\n      \"uncanny\": 28953,\n      \"##iii\": 28954,\n      \"1709\": 28955,\n      \"friendships\": 28956,\n      \"##nbc\": 28957,\n      \"sacrament\": 28958,\n      \"accommodated\": 28959,\n      \"reiterated\": 28960,\n      \"logistical\": 28961,\n      \"pebbles\": 28962,\n      \"thumped\": 28963,\n      \"##escence\": 28964,\n      \"administering\": 28965,\n      \"decrees\": 28966,\n      \"drafts\": 28967,\n      \"##flight\": 28968,\n      \"##cased\": 28969,\n      \"##tula\": 28970,\n      \"futuristic\": 28971,\n      \"picket\": 28972,\n      \"intimidation\": 28973,\n      \"winthrop\": 28974,\n      \"##fahan\": 28975,\n      \"interfered\": 28976,\n      \"339\": 28977,\n      \"afar\": 28978,\n      \"francoise\": 28979,\n      \"morally\": 28980,\n      \"uta\": 28981,\n      \"cochin\": 28982,\n      \"croft\": 28983,\n      \"dwarfs\": 28984,\n      \"##bruck\": 28985,\n      \"##dents\": 28986,\n      \"##nami\": 28987,\n      \"biker\": 28988,\n      \"##hner\": 28989,\n      \"##meral\": 28990,\n      \"nano\": 28991,\n      \"##isen\": 28992,\n      \"##ometric\": 28993,\n      \"##pres\": 28994,\n      \"##ан\": 28995,\n      \"brightened\": 28996,\n      \"meek\": 28997,\n      \"parcels\": 28998,\n      \"securely\": 28999,\n      \"gunners\": 29000,\n      \"##jhl\": 29001,\n      \"##zko\": 29002,\n      \"agile\": 29003,\n      \"hysteria\": 29004,\n      \"##lten\": 29005,\n      \"##rcus\": 29006,\n      \"bukit\": 29007,\n      \"champs\": 29008,\n      \"chevy\": 29009,\n      \"cuckoo\": 29010,\n      \"leith\": 29011,\n      \"sadler\": 29012,\n      \"theologians\": 29013,\n      \"welded\": 29014,\n      \"##section\": 29015,\n      \"1663\": 29016,\n      \"jj\": 29017,\n      \"plurality\": 29018,\n      \"xander\": 29019,\n      \"##rooms\": 29020,\n      \"##formed\": 29021,\n      \"shredded\": 29022,\n      \"temps\": 29023,\n      \"intimately\": 29024,\n      \"pau\": 29025,\n      \"tormented\": 29026,\n      \"##lok\": 29027,\n      \"##stellar\": 29028,\n      \"1618\": 29029,\n      \"charred\": 29030,\n      \"ems\": 29031,\n      \"essen\": 29032,\n      \"##mmel\": 29033,\n      \"alarms\": 29034,\n      \"spraying\": 29035,\n      \"ascot\": 29036,\n      \"blooms\": 29037,\n      \"twinkle\": 29038,\n      \"##abia\": 29039,\n      \"##apes\": 29040,\n      \"internment\": 29041,\n      \"obsidian\": 29042,\n      \"##chaft\": 29043,\n      \"snoop\": 29044,\n      \"##dav\": 29045,\n      \"##ooping\": 29046,\n      \"malibu\": 29047,\n      \"##tension\": 29048,\n      \"quiver\": 29049,\n      \"##itia\": 29050,\n      \"hays\": 29051,\n      \"mcintosh\": 29052,\n      \"travers\": 29053,\n      \"walsall\": 29054,\n      \"##ffie\": 29055,\n      \"1623\": 29056,\n      \"beverley\": 29057,\n      \"schwarz\": 29058,\n      \"plunging\": 29059,\n      \"structurally\": 29060,\n      \"m3\": 29061,\n      \"rosenthal\": 29062,\n      \"vikram\": 29063,\n      \"##tsk\": 29064,\n      \"770\": 29065,\n      \"ghz\": 29066,\n      \"##onda\": 29067,\n      \"##tiv\": 29068,\n      \"chalmers\": 29069,\n      \"groningen\": 29070,\n      \"pew\": 29071,\n      \"reckon\": 29072,\n      \"unicef\": 29073,\n      \"##rvis\": 29074,\n      \"55th\": 29075,\n      \"##gni\": 29076,\n      \"1651\": 29077,\n      \"sulawesi\": 29078,\n      \"avila\": 29079,\n      \"cai\": 29080,\n      \"metaphysical\": 29081,\n      \"screwing\": 29082,\n      \"turbulence\": 29083,\n      \"##mberg\": 29084,\n      \"augusto\": 29085,\n      \"samba\": 29086,\n      \"56th\": 29087,\n      \"baffled\": 29088,\n      \"momentary\": 29089,\n      \"toxin\": 29090,\n      \"##urian\": 29091,\n      \"##wani\": 29092,\n      \"aachen\": 29093,\n      \"condoms\": 29094,\n      \"dali\": 29095,\n      \"steppe\": 29096,\n      \"##3d\": 29097,\n      \"##app\": 29098,\n      \"##oed\": 29099,\n      \"##year\": 29100,\n      \"adolescence\": 29101,\n      \"dauphin\": 29102,\n      \"electrically\": 29103,\n      \"inaccessible\": 29104,\n      \"microscopy\": 29105,\n      \"nikita\": 29106,\n      \"##ega\": 29107,\n      \"atv\": 29108,\n      \"##cel\": 29109,\n      \"##enter\": 29110,\n      \"##oles\": 29111,\n      \"##oteric\": 29112,\n      \"##ы\": 29113,\n      \"accountants\": 29114,\n      \"punishments\": 29115,\n      \"wrongly\": 29116,\n      \"bribes\": 29117,\n      \"adventurous\": 29118,\n      \"clinch\": 29119,\n      \"flinders\": 29120,\n      \"southland\": 29121,\n      \"##hem\": 29122,\n      \"##kata\": 29123,\n      \"gough\": 29124,\n      \"##ciency\": 29125,\n      \"lads\": 29126,\n      \"soared\": 29127,\n      \"##ה\": 29128,\n      \"undergoes\": 29129,\n      \"deformation\": 29130,\n      \"outlawed\": 29131,\n      \"rubbish\": 29132,\n      \"##arus\": 29133,\n      \"##mussen\": 29134,\n      \"##nidae\": 29135,\n      \"##rzburg\": 29136,\n      \"arcs\": 29137,\n      \"##ingdon\": 29138,\n      \"##tituted\": 29139,\n      \"1695\": 29140,\n      \"wheelbase\": 29141,\n      \"wheeling\": 29142,\n      \"bombardier\": 29143,\n      \"campground\": 29144,\n      \"zebra\": 29145,\n      \"##lices\": 29146,\n      \"##oj\": 29147,\n      \"##bain\": 29148,\n      \"lullaby\": 29149,\n      \"##ecure\": 29150,\n      \"donetsk\": 29151,\n      \"wylie\": 29152,\n      \"grenada\": 29153,\n      \"##arding\": 29154,\n      \"##ης\": 29155,\n      \"squinting\": 29156,\n      \"eireann\": 29157,\n      \"opposes\": 29158,\n      \"##andra\": 29159,\n      \"maximal\": 29160,\n      \"runes\": 29161,\n      \"##broken\": 29162,\n      \"##cuting\": 29163,\n      \"##iface\": 29164,\n      \"##ror\": 29165,\n      \"##rosis\": 29166,\n      \"additive\": 29167,\n      \"britney\": 29168,\n      \"adultery\": 29169,\n      \"triggering\": 29170,\n      \"##drome\": 29171,\n      \"detrimental\": 29172,\n      \"aarhus\": 29173,\n      \"containment\": 29174,\n      \"jc\": 29175,\n      \"swapped\": 29176,\n      \"vichy\": 29177,\n      \"##ioms\": 29178,\n      \"madly\": 29179,\n      \"##oric\": 29180,\n      \"##rag\": 29181,\n      \"brant\": 29182,\n      \"##ckey\": 29183,\n      \"##trix\": 29184,\n      \"1560\": 29185,\n      \"1612\": 29186,\n      \"broughton\": 29187,\n      \"rustling\": 29188,\n      \"##stems\": 29189,\n      \"##uder\": 29190,\n      \"asbestos\": 29191,\n      \"mentoring\": 29192,\n      \"##nivorous\": 29193,\n      \"finley\": 29194,\n      \"leaps\": 29195,\n      \"##isan\": 29196,\n      \"apical\": 29197,\n      \"pry\": 29198,\n      \"slits\": 29199,\n      \"substitutes\": 29200,\n      \"##dict\": 29201,\n      \"intuitive\": 29202,\n      \"fantasia\": 29203,\n      \"insistent\": 29204,\n      \"unreasonable\": 29205,\n      \"##igen\": 29206,\n      \"##vna\": 29207,\n      \"domed\": 29208,\n      \"hannover\": 29209,\n      \"margot\": 29210,\n      \"ponder\": 29211,\n      \"##zziness\": 29212,\n      \"impromptu\": 29213,\n      \"jian\": 29214,\n      \"lc\": 29215,\n      \"rampage\": 29216,\n      \"stemming\": 29217,\n      \"##eft\": 29218,\n      \"andrey\": 29219,\n      \"gerais\": 29220,\n      \"whichever\": 29221,\n      \"amnesia\": 29222,\n      \"appropriated\": 29223,\n      \"anzac\": 29224,\n      \"clicks\": 29225,\n      \"modifying\": 29226,\n      \"ultimatum\": 29227,\n      \"cambrian\": 29228,\n      \"maids\": 29229,\n      \"verve\": 29230,\n      \"yellowstone\": 29231,\n      \"##mbs\": 29232,\n      \"conservatoire\": 29233,\n      \"##scribe\": 29234,\n      \"adherence\": 29235,\n      \"dinners\": 29236,\n      \"spectra\": 29237,\n      \"imperfect\": 29238,\n      \"mysteriously\": 29239,\n      \"sidekick\": 29240,\n      \"tatar\": 29241,\n      \"tuba\": 29242,\n      \"##aks\": 29243,\n      \"##ifolia\": 29244,\n      \"distrust\": 29245,\n      \"##athan\": 29246,\n      \"##zle\": 29247,\n      \"c2\": 29248,\n      \"ronin\": 29249,\n      \"zac\": 29250,\n      \"##pse\": 29251,\n      \"celaena\": 29252,\n      \"instrumentalist\": 29253,\n      \"scents\": 29254,\n      \"skopje\": 29255,\n      \"##mbling\": 29256,\n      \"comical\": 29257,\n      \"compensated\": 29258,\n      \"vidal\": 29259,\n      \"condor\": 29260,\n      \"intersect\": 29261,\n      \"jingle\": 29262,\n      \"wavelengths\": 29263,\n      \"##urrent\": 29264,\n      \"mcqueen\": 29265,\n      \"##izzly\": 29266,\n      \"carp\": 29267,\n      \"weasel\": 29268,\n      \"422\": 29269,\n      \"kanye\": 29270,\n      \"militias\": 29271,\n      \"postdoctoral\": 29272,\n      \"eugen\": 29273,\n      \"gunslinger\": 29274,\n      \"##ɛ\": 29275,\n      \"faux\": 29276,\n      \"hospice\": 29277,\n      \"##for\": 29278,\n      \"appalled\": 29279,\n      \"derivation\": 29280,\n      \"dwarves\": 29281,\n      \"##elis\": 29282,\n      \"dilapidated\": 29283,\n      \"##folk\": 29284,\n      \"astoria\": 29285,\n      \"philology\": 29286,\n      \"##lwyn\": 29287,\n      \"##otho\": 29288,\n      \"##saka\": 29289,\n      \"inducing\": 29290,\n      \"philanthropy\": 29291,\n      \"##bf\": 29292,\n      \"##itative\": 29293,\n      \"geek\": 29294,\n      \"markedly\": 29295,\n      \"sql\": 29296,\n      \"##yce\": 29297,\n      \"bessie\": 29298,\n      \"indices\": 29299,\n      \"rn\": 29300,\n      \"##flict\": 29301,\n      \"495\": 29302,\n      \"frowns\": 29303,\n      \"resolving\": 29304,\n      \"weightlifting\": 29305,\n      \"tugs\": 29306,\n      \"cleric\": 29307,\n      \"contentious\": 29308,\n      \"1653\": 29309,\n      \"mania\": 29310,\n      \"rms\": 29311,\n      \"##miya\": 29312,\n      \"##reate\": 29313,\n      \"##ruck\": 29314,\n      \"##tucket\": 29315,\n      \"bien\": 29316,\n      \"eels\": 29317,\n      \"marek\": 29318,\n      \"##ayton\": 29319,\n      \"##cence\": 29320,\n      \"discreet\": 29321,\n      \"unofficially\": 29322,\n      \"##ife\": 29323,\n      \"leaks\": 29324,\n      \"##bber\": 29325,\n      \"1705\": 29326,\n      \"332\": 29327,\n      \"dung\": 29328,\n      \"compressor\": 29329,\n      \"hillsborough\": 29330,\n      \"pandit\": 29331,\n      \"shillings\": 29332,\n      \"distal\": 29333,\n      \"##skin\": 29334,\n      \"381\": 29335,\n      \"##tat\": 29336,\n      \"##you\": 29337,\n      \"nosed\": 29338,\n      \"##nir\": 29339,\n      \"mangrove\": 29340,\n      \"undeveloped\": 29341,\n      \"##idia\": 29342,\n      \"textures\": 29343,\n      \"##inho\": 29344,\n      \"##500\": 29345,\n      \"##rise\": 29346,\n      \"ae\": 29347,\n      \"irritating\": 29348,\n      \"nay\": 29349,\n      \"amazingly\": 29350,\n      \"bancroft\": 29351,\n      \"apologetic\": 29352,\n      \"compassionate\": 29353,\n      \"kata\": 29354,\n      \"symphonies\": 29355,\n      \"##lovic\": 29356,\n      \"airspace\": 29357,\n      \"##lch\": 29358,\n      \"930\": 29359,\n      \"gifford\": 29360,\n      \"precautions\": 29361,\n      \"fulfillment\": 29362,\n      \"sevilla\": 29363,\n      \"vulgar\": 29364,\n      \"martinique\": 29365,\n      \"##urities\": 29366,\n      \"looting\": 29367,\n      \"piccolo\": 29368,\n      \"tidy\": 29369,\n      \"##dermott\": 29370,\n      \"quadrant\": 29371,\n      \"armchair\": 29372,\n      \"incomes\": 29373,\n      \"mathematicians\": 29374,\n      \"stampede\": 29375,\n      \"nilsson\": 29376,\n      \"##inking\": 29377,\n      \"##scan\": 29378,\n      \"foo\": 29379,\n      \"quarterfinal\": 29380,\n      \"##ostal\": 29381,\n      \"shang\": 29382,\n      \"shouldered\": 29383,\n      \"squirrels\": 29384,\n      \"##owe\": 29385,\n      \"344\": 29386,\n      \"vinegar\": 29387,\n      \"##bner\": 29388,\n      \"##rchy\": 29389,\n      \"##systems\": 29390,\n      \"delaying\": 29391,\n      \"##trics\": 29392,\n      \"ars\": 29393,\n      \"dwyer\": 29394,\n      \"rhapsody\": 29395,\n      \"sponsoring\": 29396,\n      \"##gration\": 29397,\n      \"bipolar\": 29398,\n      \"cinder\": 29399,\n      \"starters\": 29400,\n      \"##olio\": 29401,\n      \"##urst\": 29402,\n      \"421\": 29403,\n      \"signage\": 29404,\n      \"##nty\": 29405,\n      \"aground\": 29406,\n      \"figurative\": 29407,\n      \"mons\": 29408,\n      \"acquaintances\": 29409,\n      \"duets\": 29410,\n      \"erroneously\": 29411,\n      \"soyuz\": 29412,\n      \"elliptic\": 29413,\n      \"recreated\": 29414,\n      \"##cultural\": 29415,\n      \"##quette\": 29416,\n      \"##ssed\": 29417,\n      \"##tma\": 29418,\n      \"##zcz\": 29419,\n      \"moderator\": 29420,\n      \"scares\": 29421,\n      \"##itaire\": 29422,\n      \"##stones\": 29423,\n      \"##udence\": 29424,\n      \"juniper\": 29425,\n      \"sighting\": 29426,\n      \"##just\": 29427,\n      \"##nsen\": 29428,\n      \"britten\": 29429,\n      \"calabria\": 29430,\n      \"ry\": 29431,\n      \"bop\": 29432,\n      \"cramer\": 29433,\n      \"forsyth\": 29434,\n      \"stillness\": 29435,\n      \"##л\": 29436,\n      \"airmen\": 29437,\n      \"gathers\": 29438,\n      \"unfit\": 29439,\n      \"##umber\": 29440,\n      \"##upt\": 29441,\n      \"taunting\": 29442,\n      \"##rip\": 29443,\n      \"seeker\": 29444,\n      \"streamlined\": 29445,\n      \"##bution\": 29446,\n      \"holster\": 29447,\n      \"schumann\": 29448,\n      \"tread\": 29449,\n      \"vox\": 29450,\n      \"##gano\": 29451,\n      \"##onzo\": 29452,\n      \"strive\": 29453,\n      \"dil\": 29454,\n      \"reforming\": 29455,\n      \"covent\": 29456,\n      \"newbury\": 29457,\n      \"predicting\": 29458,\n      \"##orro\": 29459,\n      \"decorate\": 29460,\n      \"tre\": 29461,\n      \"##puted\": 29462,\n      \"andover\": 29463,\n      \"ie\": 29464,\n      \"asahi\": 29465,\n      \"dept\": 29466,\n      \"dunkirk\": 29467,\n      \"gills\": 29468,\n      \"##tori\": 29469,\n      \"buren\": 29470,\n      \"huskies\": 29471,\n      \"##stis\": 29472,\n      \"##stov\": 29473,\n      \"abstracts\": 29474,\n      \"bets\": 29475,\n      \"loosen\": 29476,\n      \"##opa\": 29477,\n      \"1682\": 29478,\n      \"yearning\": 29479,\n      \"##glio\": 29480,\n      \"##sir\": 29481,\n      \"berman\": 29482,\n      \"effortlessly\": 29483,\n      \"enamel\": 29484,\n      \"napoli\": 29485,\n      \"persist\": 29486,\n      \"##peration\": 29487,\n      \"##uez\": 29488,\n      \"attache\": 29489,\n      \"elisa\": 29490,\n      \"b1\": 29491,\n      \"invitations\": 29492,\n      \"##kic\": 29493,\n      \"accelerating\": 29494,\n      \"reindeer\": 29495,\n      \"boardwalk\": 29496,\n      \"clutches\": 29497,\n      \"nelly\": 29498,\n      \"polka\": 29499,\n      \"starbucks\": 29500,\n      \"##kei\": 29501,\n      \"adamant\": 29502,\n      \"huey\": 29503,\n      \"lough\": 29504,\n      \"unbroken\": 29505,\n      \"adventurer\": 29506,\n      \"embroidery\": 29507,\n      \"inspecting\": 29508,\n      \"stanza\": 29509,\n      \"##ducted\": 29510,\n      \"naia\": 29511,\n      \"taluka\": 29512,\n      \"##pone\": 29513,\n      \"##roids\": 29514,\n      \"chases\": 29515,\n      \"deprivation\": 29516,\n      \"florian\": 29517,\n      \"##jing\": 29518,\n      \"##ppet\": 29519,\n      \"earthly\": 29520,\n      \"##lib\": 29521,\n      \"##ssee\": 29522,\n      \"colossal\": 29523,\n      \"foreigner\": 29524,\n      \"vet\": 29525,\n      \"freaks\": 29526,\n      \"patrice\": 29527,\n      \"rosewood\": 29528,\n      \"triassic\": 29529,\n      \"upstate\": 29530,\n      \"##pkins\": 29531,\n      \"dominates\": 29532,\n      \"ata\": 29533,\n      \"chants\": 29534,\n      \"ks\": 29535,\n      \"vo\": 29536,\n      \"##400\": 29537,\n      \"##bley\": 29538,\n      \"##raya\": 29539,\n      \"##rmed\": 29540,\n      \"555\": 29541,\n      \"agra\": 29542,\n      \"infiltrate\": 29543,\n      \"##ailing\": 29544,\n      \"##ilation\": 29545,\n      \"##tzer\": 29546,\n      \"##uppe\": 29547,\n      \"##werk\": 29548,\n      \"binoculars\": 29549,\n      \"enthusiast\": 29550,\n      \"fujian\": 29551,\n      \"squeak\": 29552,\n      \"##avs\": 29553,\n      \"abolitionist\": 29554,\n      \"almeida\": 29555,\n      \"boredom\": 29556,\n      \"hampstead\": 29557,\n      \"marsden\": 29558,\n      \"rations\": 29559,\n      \"##ands\": 29560,\n      \"inflated\": 29561,\n      \"334\": 29562,\n      \"bonuses\": 29563,\n      \"rosalie\": 29564,\n      \"patna\": 29565,\n      \"##rco\": 29566,\n      \"329\": 29567,\n      \"detachments\": 29568,\n      \"penitentiary\": 29569,\n      \"54th\": 29570,\n      \"flourishing\": 29571,\n      \"woolf\": 29572,\n      \"##dion\": 29573,\n      \"##etched\": 29574,\n      \"papyrus\": 29575,\n      \"##lster\": 29576,\n      \"##nsor\": 29577,\n      \"##toy\": 29578,\n      \"bobbed\": 29579,\n      \"dismounted\": 29580,\n      \"endelle\": 29581,\n      \"inhuman\": 29582,\n      \"motorola\": 29583,\n      \"tbs\": 29584,\n      \"wince\": 29585,\n      \"wreath\": 29586,\n      \"##ticus\": 29587,\n      \"hideout\": 29588,\n      \"inspections\": 29589,\n      \"sanjay\": 29590,\n      \"disgrace\": 29591,\n      \"infused\": 29592,\n      \"pudding\": 29593,\n      \"stalks\": 29594,\n      \"##urbed\": 29595,\n      \"arsenic\": 29596,\n      \"leases\": 29597,\n      \"##hyl\": 29598,\n      \"##rrard\": 29599,\n      \"collarbone\": 29600,\n      \"##waite\": 29601,\n      \"##wil\": 29602,\n      \"dowry\": 29603,\n      \"##bant\": 29604,\n      \"##edance\": 29605,\n      \"genealogical\": 29606,\n      \"nitrate\": 29607,\n      \"salamanca\": 29608,\n      \"scandals\": 29609,\n      \"thyroid\": 29610,\n      \"necessitated\": 29611,\n      \"##!\": 29612,\n      \"##\\\"\": 29613,\n      \"###\": 29614,\n      \"##$\": 29615,\n      \"##%\": 29616,\n      \"##&\": 29617,\n      \"##'\": 29618,\n      \"##(\": 29619,\n      \"##)\": 29620,\n      \"##*\": 29621,\n      \"##+\": 29622,\n      \"##,\": 29623,\n      \"##-\": 29624,\n      \"##.\": 29625,\n      \"##/\": 29626,\n      \"##:\": 29627,\n      \"##;\": 29628,\n      \"##<\": 29629,\n      \"##=\": 29630,\n      \"##>\": 29631,\n      \"##?\": 29632,\n      \"##@\": 29633,\n      \"##[\": 29634,\n      \"##\\\\\": 29635,\n      \"##]\": 29636,\n      \"##^\": 29637,\n      \"##_\": 29638,\n      \"##`\": 29639,\n      \"##{\": 29640,\n      \"##|\": 29641,\n      \"##}\": 29642,\n      \"##~\": 29643,\n      \"##¡\": 29644,\n      \"##¢\": 29645,\n      \"##£\": 29646,\n      \"##¤\": 29647,\n      \"##¥\": 29648,\n      \"##¦\": 29649,\n      \"##§\": 29650,\n      \"##¨\": 29651,\n      \"##©\": 29652,\n      \"##ª\": 29653,\n      \"##«\": 29654,\n      \"##¬\": 29655,\n      \"##®\": 29656,\n      \"##±\": 29657,\n      \"##´\": 29658,\n      \"##µ\": 29659,\n      \"##¶\": 29660,\n      \"##·\": 29661,\n      \"##º\": 29662,\n      \"##»\": 29663,\n      \"##¼\": 29664,\n      \"##¾\": 29665,\n      \"##¿\": 29666,\n      \"##æ\": 29667,\n      \"##ð\": 29668,\n      \"##÷\": 29669,\n      \"##þ\": 29670,\n      \"##đ\": 29671,\n      \"##ħ\": 29672,\n      \"##ŋ\": 29673,\n      \"##œ\": 29674,\n      \"##ƒ\": 29675,\n      \"##ɐ\": 29676,\n      \"##ɑ\": 29677,\n      \"##ɒ\": 29678,\n      \"##ɔ\": 29679,\n      \"##ɕ\": 29680,\n      \"##ə\": 29681,\n      \"##ɡ\": 29682,\n      \"##ɣ\": 29683,\n      \"##ɨ\": 29684,\n      \"##ɪ\": 29685,\n      \"##ɫ\": 29686,\n      \"##ɬ\": 29687,\n      \"##ɯ\": 29688,\n      \"##ɲ\": 29689,\n      \"##ɴ\": 29690,\n      \"##ɹ\": 29691,\n      \"##ɾ\": 29692,\n      \"##ʀ\": 29693,\n      \"##ʁ\": 29694,\n      \"##ʂ\": 29695,\n      \"##ʃ\": 29696,\n      \"##ʉ\": 29697,\n      \"##ʊ\": 29698,\n      \"##ʋ\": 29699,\n      \"##ʌ\": 29700,\n      \"##ʎ\": 29701,\n      \"##ʐ\": 29702,\n      \"##ʑ\": 29703,\n      \"##ʒ\": 29704,\n      \"##ʔ\": 29705,\n      \"##ʰ\": 29706,\n      \"##ʲ\": 29707,\n      \"##ʳ\": 29708,\n      \"##ʷ\": 29709,\n      \"##ʸ\": 29710,\n      \"##ʻ\": 29711,\n      \"##ʼ\": 29712,\n      \"##ʾ\": 29713,\n      \"##ʿ\": 29714,\n      \"##ˈ\": 29715,\n      \"##ˡ\": 29716,\n      \"##ˢ\": 29717,\n      \"##ˣ\": 29718,\n      \"##ˤ\": 29719,\n      \"##β\": 29720,\n      \"##γ\": 29721,\n      \"##δ\": 29722,\n      \"##ε\": 29723,\n      \"##ζ\": 29724,\n      \"##θ\": 29725,\n      \"##κ\": 29726,\n      \"##λ\": 29727,\n      \"##μ\": 29728,\n      \"##ξ\": 29729,\n      \"##ο\": 29730,\n      \"##π\": 29731,\n      \"##ρ\": 29732,\n      \"##σ\": 29733,\n      \"##τ\": 29734,\n      \"##υ\": 29735,\n      \"##φ\": 29736,\n      \"##χ\": 29737,\n      \"##ψ\": 29738,\n      \"##ω\": 29739,\n      \"##б\": 29740,\n      \"##г\": 29741,\n      \"##д\": 29742,\n      \"##ж\": 29743,\n      \"##з\": 29744,\n      \"##м\": 29745,\n      \"##п\": 29746,\n      \"##с\": 29747,\n      \"##у\": 29748,\n      \"##ф\": 29749,\n      \"##х\": 29750,\n      \"##ц\": 29751,\n      \"##ч\": 29752,\n      \"##ш\": 29753,\n      \"##щ\": 29754,\n      \"##ъ\": 29755,\n      \"##э\": 29756,\n      \"##ю\": 29757,\n      \"##ђ\": 29758,\n      \"##є\": 29759,\n      \"##і\": 29760,\n      \"##ј\": 29761,\n      \"##љ\": 29762,\n      \"##њ\": 29763,\n      \"##ћ\": 29764,\n      \"##ӏ\": 29765,\n      \"##ա\": 29766,\n      \"##բ\": 29767,\n      \"##գ\": 29768,\n      \"##դ\": 29769,\n      \"##ե\": 29770,\n      \"##թ\": 29771,\n      \"##ի\": 29772,\n      \"##լ\": 29773,\n      \"##կ\": 29774,\n      \"##հ\": 29775,\n      \"##մ\": 29776,\n      \"##յ\": 29777,\n      \"##ն\": 29778,\n      \"##ո\": 29779,\n      \"##պ\": 29780,\n      \"##ս\": 29781,\n      \"##վ\": 29782,\n      \"##տ\": 29783,\n      \"##ր\": 29784,\n      \"##ւ\": 29785,\n      \"##ք\": 29786,\n      \"##־\": 29787,\n      \"##א\": 29788,\n      \"##ב\": 29789,\n      \"##ג\": 29790,\n      \"##ד\": 29791,\n      \"##ו\": 29792,\n      \"##ז\": 29793,\n      \"##ח\": 29794,\n      \"##ט\": 29795,\n      \"##י\": 29796,\n      \"##ך\": 29797,\n      \"##כ\": 29798,\n      \"##ל\": 29799,\n      \"##ם\": 29800,\n      \"##מ\": 29801,\n      \"##ן\": 29802,\n      \"##נ\": 29803,\n      \"##ס\": 29804,\n      \"##ע\": 29805,\n      \"##ף\": 29806,\n      \"##פ\": 29807,\n      \"##ץ\": 29808,\n      \"##צ\": 29809,\n      \"##ק\": 29810,\n      \"##ר\": 29811,\n      \"##ש\": 29812,\n      \"##ת\": 29813,\n      \"##،\": 29814,\n      \"##ء\": 29815,\n      \"##ب\": 29816,\n      \"##ت\": 29817,\n      \"##ث\": 29818,\n      \"##ج\": 29819,\n      \"##ح\": 29820,\n      \"##خ\": 29821,\n      \"##ذ\": 29822,\n      \"##ز\": 29823,\n      \"##س\": 29824,\n      \"##ش\": 29825,\n      \"##ص\": 29826,\n      \"##ض\": 29827,\n      \"##ط\": 29828,\n      \"##ظ\": 29829,\n      \"##ع\": 29830,\n      \"##غ\": 29831,\n      \"##ـ\": 29832,\n      \"##ف\": 29833,\n      \"##ق\": 29834,\n      \"##ك\": 29835,\n      \"##و\": 29836,\n      \"##ى\": 29837,\n      \"##ٹ\": 29838,\n      \"##پ\": 29839,\n      \"##چ\": 29840,\n      \"##ک\": 29841,\n      \"##گ\": 29842,\n      \"##ں\": 29843,\n      \"##ھ\": 29844,\n      \"##ہ\": 29845,\n      \"##ے\": 29846,\n      \"##अ\": 29847,\n      \"##आ\": 29848,\n      \"##उ\": 29849,\n      \"##ए\": 29850,\n      \"##क\": 29851,\n      \"##ख\": 29852,\n      \"##ग\": 29853,\n      \"##च\": 29854,\n      \"##ज\": 29855,\n      \"##ट\": 29856,\n      \"##ड\": 29857,\n      \"##ण\": 29858,\n      \"##त\": 29859,\n      \"##थ\": 29860,\n      \"##द\": 29861,\n      \"##ध\": 29862,\n      \"##न\": 29863,\n      \"##प\": 29864,\n      \"##ब\": 29865,\n      \"##भ\": 29866,\n      \"##म\": 29867,\n      \"##य\": 29868,\n      \"##र\": 29869,\n      \"##ल\": 29870,\n      \"##व\": 29871,\n      \"##श\": 29872,\n      \"##ष\": 29873,\n      \"##स\": 29874,\n      \"##ह\": 29875,\n      \"##ा\": 29876,\n      \"##ि\": 29877,\n      \"##ी\": 29878,\n      \"##ो\": 29879,\n      \"##।\": 29880,\n      \"##॥\": 29881,\n      \"##ং\": 29882,\n      \"##অ\": 29883,\n      \"##আ\": 29884,\n      \"##ই\": 29885,\n      \"##উ\": 29886,\n      \"##এ\": 29887,\n      \"##ও\": 29888,\n      \"##ক\": 29889,\n      \"##খ\": 29890,\n      \"##গ\": 29891,\n      \"##চ\": 29892,\n      \"##ছ\": 29893,\n      \"##জ\": 29894,\n      \"##ট\": 29895,\n      \"##ড\": 29896,\n      \"##ণ\": 29897,\n      \"##ত\": 29898,\n      \"##থ\": 29899,\n      \"##দ\": 29900,\n      \"##ধ\": 29901,\n      \"##ন\": 29902,\n      \"##প\": 29903,\n      \"##ব\": 29904,\n      \"##ভ\": 29905,\n      \"##ম\": 29906,\n      \"##য\": 29907,\n      \"##র\": 29908,\n      \"##ল\": 29909,\n      \"##শ\": 29910,\n      \"##ষ\": 29911,\n      \"##স\": 29912,\n      \"##হ\": 29913,\n      \"##া\": 29914,\n      \"##ি\": 29915,\n      \"##ী\": 29916,\n      \"##ে\": 29917,\n      \"##க\": 29918,\n      \"##ச\": 29919,\n      \"##ட\": 29920,\n      \"##த\": 29921,\n      \"##ந\": 29922,\n      \"##ன\": 29923,\n      \"##ப\": 29924,\n      \"##ம\": 29925,\n      \"##ய\": 29926,\n      \"##ர\": 29927,\n      \"##ல\": 29928,\n      \"##ள\": 29929,\n      \"##வ\": 29930,\n      \"##ா\": 29931,\n      \"##ி\": 29932,\n      \"##ு\": 29933,\n      \"##ே\": 29934,\n      \"##ை\": 29935,\n      \"##ನ\": 29936,\n      \"##ರ\": 29937,\n      \"##ಾ\": 29938,\n      \"##ක\": 29939,\n      \"##ය\": 29940,\n      \"##ර\": 29941,\n      \"##ල\": 29942,\n      \"##ව\": 29943,\n      \"##ා\": 29944,\n      \"##ก\": 29945,\n      \"##ง\": 29946,\n      \"##ต\": 29947,\n      \"##ท\": 29948,\n      \"##น\": 29949,\n      \"##พ\": 29950,\n      \"##ม\": 29951,\n      \"##ย\": 29952,\n      \"##ร\": 29953,\n      \"##ล\": 29954,\n      \"##ว\": 29955,\n      \"##ส\": 29956,\n      \"##อ\": 29957,\n      \"##า\": 29958,\n      \"##เ\": 29959,\n      \"##་\": 29960,\n      \"##།\": 29961,\n      \"##ག\": 29962,\n      \"##ང\": 29963,\n      \"##ད\": 29964,\n      \"##ན\": 29965,\n      \"##པ\": 29966,\n      \"##བ\": 29967,\n      \"##མ\": 29968,\n      \"##འ\": 29969,\n      \"##ར\": 29970,\n      \"##ལ\": 29971,\n      \"##ས\": 29972,\n      \"##မ\": 29973,\n      \"##ა\": 29974,\n      \"##ბ\": 29975,\n      \"##გ\": 29976,\n      \"##დ\": 29977,\n      \"##ე\": 29978,\n      \"##ვ\": 29979,\n      \"##თ\": 29980,\n      \"##ი\": 29981,\n      \"##კ\": 29982,\n      \"##ლ\": 29983,\n      \"##მ\": 29984,\n      \"##ნ\": 29985,\n      \"##ო\": 29986,\n      \"##რ\": 29987,\n      \"##ს\": 29988,\n      \"##ტ\": 29989,\n      \"##უ\": 29990,\n      \"##ᄀ\": 29991,\n      \"##ᄂ\": 29992,\n      \"##ᄃ\": 29993,\n      \"##ᄅ\": 29994,\n      \"##ᄆ\": 29995,\n      \"##ᄇ\": 29996,\n      \"##ᄉ\": 29997,\n      \"##ᄊ\": 29998,\n      \"##ᄋ\": 29999,\n      \"##ᄌ\": 30000,\n      \"##ᄎ\": 30001,\n      \"##ᄏ\": 30002,\n      \"##ᄐ\": 30003,\n      \"##ᄑ\": 30004,\n      \"##ᄒ\": 30005,\n      \"##ᅡ\": 30006,\n      \"##ᅢ\": 30007,\n      \"##ᅥ\": 30008,\n      \"##ᅦ\": 30009,\n      \"##ᅧ\": 30010,\n      \"##ᅩ\": 30011,\n      \"##ᅪ\": 30012,\n      \"##ᅭ\": 30013,\n      \"##ᅮ\": 30014,\n      \"##ᅯ\": 30015,\n      \"##ᅲ\": 30016,\n      \"##ᅳ\": 30017,\n      \"##ᅴ\": 30018,\n      \"##ᅵ\": 30019,\n      \"##ᆨ\": 30020,\n      \"##ᆫ\": 30021,\n      \"##ᆯ\": 30022,\n      \"##ᆷ\": 30023,\n      \"##ᆸ\": 30024,\n      \"##ᆼ\": 30025,\n      \"##ᴬ\": 30026,\n      \"##ᴮ\": 30027,\n      \"##ᴰ\": 30028,\n      \"##ᴵ\": 30029,\n      \"##ᴺ\": 30030,\n      \"##ᵀ\": 30031,\n      \"##ᵃ\": 30032,\n      \"##ᵇ\": 30033,\n      \"##ᵈ\": 30034,\n      \"##ᵉ\": 30035,\n      \"##ᵍ\": 30036,\n      \"##ᵏ\": 30037,\n      \"##ᵐ\": 30038,\n      \"##ᵒ\": 30039,\n      \"##ᵖ\": 30040,\n      \"##ᵗ\": 30041,\n      \"##ᵘ\": 30042,\n      \"##ᵣ\": 30043,\n      \"##ᵤ\": 30044,\n      \"##ᵥ\": 30045,\n      \"##ᶜ\": 30046,\n      \"##ᶠ\": 30047,\n      \"##‐\": 30048,\n      \"##‑\": 30049,\n      \"##‒\": 30050,\n      \"##–\": 30051,\n      \"##—\": 30052,\n      \"##―\": 30053,\n      \"##‖\": 30054,\n      \"##‘\": 30055,\n      \"##’\": 30056,\n      \"##‚\": 30057,\n      \"##“\": 30058,\n      \"##”\": 30059,\n      \"##„\": 30060,\n      \"##†\": 30061,\n      \"##‡\": 30062,\n      \"##•\": 30063,\n      \"##…\": 30064,\n      \"##‰\": 30065,\n      \"##′\": 30066,\n      \"##″\": 30067,\n      \"##›\": 30068,\n      \"##‿\": 30069,\n      \"##⁄\": 30070,\n      \"##⁰\": 30071,\n      \"##ⁱ\": 30072,\n      \"##⁴\": 30073,\n      \"##⁵\": 30074,\n      \"##⁶\": 30075,\n      \"##⁷\": 30076,\n      \"##⁸\": 30077,\n      \"##⁹\": 30078,\n      \"##⁻\": 30079,\n      \"##ⁿ\": 30080,\n      \"##₅\": 30081,\n      \"##₆\": 30082,\n      \"##₇\": 30083,\n      \"##₈\": 30084,\n      \"##₉\": 30085,\n      \"##₊\": 30086,\n      \"##₍\": 30087,\n      \"##₎\": 30088,\n      \"##ₐ\": 30089,\n      \"##ₑ\": 30090,\n      \"##ₒ\": 30091,\n      \"##ₓ\": 30092,\n      \"##ₕ\": 30093,\n      \"##ₖ\": 30094,\n      \"##ₗ\": 30095,\n      \"##ₘ\": 30096,\n      \"##ₚ\": 30097,\n      \"##ₛ\": 30098,\n      \"##ₜ\": 30099,\n      \"##₤\": 30100,\n      \"##₩\": 30101,\n      \"##€\": 30102,\n      \"##₱\": 30103,\n      \"##₹\": 30104,\n      \"##ℓ\": 30105,\n      \"##№\": 30106,\n      \"##ℝ\": 30107,\n      \"##™\": 30108,\n      \"##⅓\": 30109,\n      \"##⅔\": 30110,\n      \"##←\": 30111,\n      \"##↑\": 30112,\n      \"##→\": 30113,\n      \"##↓\": 30114,\n      \"##↔\": 30115,\n      \"##↦\": 30116,\n      \"##⇄\": 30117,\n      \"##⇌\": 30118,\n      \"##⇒\": 30119,\n      \"##∂\": 30120,\n      \"##∅\": 30121,\n      \"##∆\": 30122,\n      \"##∇\": 30123,\n      \"##∈\": 30124,\n      \"##∗\": 30125,\n      \"##∘\": 30126,\n      \"##√\": 30127,\n      \"##∞\": 30128,\n      \"##∧\": 30129,\n      \"##∨\": 30130,\n      \"##∩\": 30131,\n      \"##∪\": 30132,\n      \"##≈\": 30133,\n      \"##≡\": 30134,\n      \"##≤\": 30135,\n      \"##≥\": 30136,\n      \"##⊂\": 30137,\n      \"##⊆\": 30138,\n      \"##⊕\": 30139,\n      \"##⊗\": 30140,\n      \"##⋅\": 30141,\n      \"##─\": 30142,\n      \"##│\": 30143,\n      \"##■\": 30144,\n      \"##▪\": 30145,\n      \"##●\": 30146,\n      \"##★\": 30147,\n      \"##☆\": 30148,\n      \"##☉\": 30149,\n      \"##♠\": 30150,\n      \"##♣\": 30151,\n      \"##♥\": 30152,\n      \"##♦\": 30153,\n      \"##♯\": 30154,\n      \"##⟨\": 30155,\n      \"##⟩\": 30156,\n      \"##ⱼ\": 30157,\n      \"##⺩\": 30158,\n      \"##⺼\": 30159,\n      \"##⽥\": 30160,\n      \"##、\": 30161,\n      \"##。\": 30162,\n      \"##〈\": 30163,\n      \"##〉\": 30164,\n      \"##《\": 30165,\n      \"##》\": 30166,\n      \"##「\": 30167,\n      \"##」\": 30168,\n      \"##『\": 30169,\n      \"##』\": 30170,\n      \"##〜\": 30171,\n      \"##あ\": 30172,\n      \"##い\": 30173,\n      \"##う\": 30174,\n      \"##え\": 30175,\n      \"##お\": 30176,\n      \"##か\": 30177,\n      \"##き\": 30178,\n      \"##く\": 30179,\n      \"##け\": 30180,\n      \"##こ\": 30181,\n      \"##さ\": 30182,\n      \"##し\": 30183,\n      \"##す\": 30184,\n      \"##せ\": 30185,\n      \"##そ\": 30186,\n      \"##た\": 30187,\n      \"##ち\": 30188,\n      \"##っ\": 30189,\n      \"##つ\": 30190,\n      \"##て\": 30191,\n      \"##と\": 30192,\n      \"##な\": 30193,\n      \"##に\": 30194,\n      \"##ぬ\": 30195,\n      \"##ね\": 30196,\n      \"##の\": 30197,\n      \"##は\": 30198,\n      \"##ひ\": 30199,\n      \"##ふ\": 30200,\n      \"##へ\": 30201,\n      \"##ほ\": 30202,\n      \"##ま\": 30203,\n      \"##み\": 30204,\n      \"##む\": 30205,\n      \"##め\": 30206,\n      \"##も\": 30207,\n      \"##や\": 30208,\n      \"##ゆ\": 30209,\n      \"##よ\": 30210,\n      \"##ら\": 30211,\n      \"##り\": 30212,\n      \"##る\": 30213,\n      \"##れ\": 30214,\n      \"##ろ\": 30215,\n      \"##を\": 30216,\n      \"##ん\": 30217,\n      \"##ァ\": 30218,\n      \"##ア\": 30219,\n      \"##ィ\": 30220,\n      \"##イ\": 30221,\n      \"##ウ\": 30222,\n      \"##ェ\": 30223,\n      \"##エ\": 30224,\n      \"##オ\": 30225,\n      \"##カ\": 30226,\n      \"##キ\": 30227,\n      \"##ク\": 30228,\n      \"##ケ\": 30229,\n      \"##コ\": 30230,\n      \"##サ\": 30231,\n      \"##シ\": 30232,\n      \"##ス\": 30233,\n      \"##セ\": 30234,\n      \"##タ\": 30235,\n      \"##チ\": 30236,\n      \"##ッ\": 30237,\n      \"##ツ\": 30238,\n      \"##テ\": 30239,\n      \"##ト\": 30240,\n      \"##ナ\": 30241,\n      \"##ニ\": 30242,\n      \"##ノ\": 30243,\n      \"##ハ\": 30244,\n      \"##ヒ\": 30245,\n      \"##フ\": 30246,\n      \"##ヘ\": 30247,\n      \"##ホ\": 30248,\n      \"##マ\": 30249,\n      \"##ミ\": 30250,\n      \"##ム\": 30251,\n      \"##メ\": 30252,\n      \"##モ\": 30253,\n      \"##ャ\": 30254,\n      \"##ュ\": 30255,\n      \"##ョ\": 30256,\n      \"##ラ\": 30257,\n      \"##リ\": 30258,\n      \"##ル\": 30259,\n      \"##レ\": 30260,\n      \"##ロ\": 30261,\n      \"##ワ\": 30262,\n      \"##ン\": 30263,\n      \"##・\": 30264,\n      \"##ー\": 30265,\n      \"##一\": 30266,\n      \"##三\": 30267,\n      \"##上\": 30268,\n      \"##下\": 30269,\n      \"##不\": 30270,\n      \"##世\": 30271,\n      \"##中\": 30272,\n      \"##主\": 30273,\n      \"##久\": 30274,\n      \"##之\": 30275,\n      \"##也\": 30276,\n      \"##事\": 30277,\n      \"##二\": 30278,\n      \"##五\": 30279,\n      \"##井\": 30280,\n      \"##京\": 30281,\n      \"##人\": 30282,\n      \"##亻\": 30283,\n      \"##仁\": 30284,\n      \"##介\": 30285,\n      \"##代\": 30286,\n      \"##仮\": 30287,\n      \"##伊\": 30288,\n      \"##会\": 30289,\n      \"##佐\": 30290,\n      \"##侍\": 30291,\n      \"##保\": 30292,\n      \"##信\": 30293,\n      \"##健\": 30294,\n      \"##元\": 30295,\n      \"##光\": 30296,\n      \"##八\": 30297,\n      \"##公\": 30298,\n      \"##内\": 30299,\n      \"##出\": 30300,\n      \"##分\": 30301,\n      \"##前\": 30302,\n      \"##劉\": 30303,\n      \"##力\": 30304,\n      \"##加\": 30305,\n      \"##勝\": 30306,\n      \"##北\": 30307,\n      \"##区\": 30308,\n      \"##十\": 30309,\n      \"##千\": 30310,\n      \"##南\": 30311,\n      \"##博\": 30312,\n      \"##原\": 30313,\n      \"##口\": 30314,\n      \"##古\": 30315,\n      \"##史\": 30316,\n      \"##司\": 30317,\n      \"##合\": 30318,\n      \"##吉\": 30319,\n      \"##同\": 30320,\n      \"##名\": 30321,\n      \"##和\": 30322,\n      \"##囗\": 30323,\n      \"##四\": 30324,\n      \"##国\": 30325,\n      \"##國\": 30326,\n      \"##土\": 30327,\n      \"##地\": 30328,\n      \"##坂\": 30329,\n      \"##城\": 30330,\n      \"##堂\": 30331,\n      \"##場\": 30332,\n      \"##士\": 30333,\n      \"##夏\": 30334,\n      \"##外\": 30335,\n      \"##大\": 30336,\n      \"##天\": 30337,\n      \"##太\": 30338,\n      \"##夫\": 30339,\n      \"##奈\": 30340,\n      \"##女\": 30341,\n      \"##子\": 30342,\n      \"##学\": 30343,\n      \"##宀\": 30344,\n      \"##宇\": 30345,\n      \"##安\": 30346,\n      \"##宗\": 30347,\n      \"##定\": 30348,\n      \"##宣\": 30349,\n      \"##宮\": 30350,\n      \"##家\": 30351,\n      \"##宿\": 30352,\n      \"##寺\": 30353,\n      \"##將\": 30354,\n      \"##小\": 30355,\n      \"##尚\": 30356,\n      \"##山\": 30357,\n      \"##岡\": 30358,\n      \"##島\": 30359,\n      \"##崎\": 30360,\n      \"##川\": 30361,\n      \"##州\": 30362,\n      \"##巿\": 30363,\n      \"##帝\": 30364,\n      \"##平\": 30365,\n      \"##年\": 30366,\n      \"##幸\": 30367,\n      \"##广\": 30368,\n      \"##弘\": 30369,\n      \"##張\": 30370,\n      \"##彳\": 30371,\n      \"##後\": 30372,\n      \"##御\": 30373,\n      \"##德\": 30374,\n      \"##心\": 30375,\n      \"##忄\": 30376,\n      \"##志\": 30377,\n      \"##忠\": 30378,\n      \"##愛\": 30379,\n      \"##成\": 30380,\n      \"##我\": 30381,\n      \"##戦\": 30382,\n      \"##戸\": 30383,\n      \"##手\": 30384,\n      \"##扌\": 30385,\n      \"##政\": 30386,\n      \"##文\": 30387,\n      \"##新\": 30388,\n      \"##方\": 30389,\n      \"##日\": 30390,\n      \"##明\": 30391,\n      \"##星\": 30392,\n      \"##春\": 30393,\n      \"##昭\": 30394,\n      \"##智\": 30395,\n      \"##曲\": 30396,\n      \"##書\": 30397,\n      \"##月\": 30398,\n      \"##有\": 30399,\n      \"##朝\": 30400,\n      \"##木\": 30401,\n      \"##本\": 30402,\n      \"##李\": 30403,\n      \"##村\": 30404,\n      \"##東\": 30405,\n      \"##松\": 30406,\n      \"##林\": 30407,\n      \"##森\": 30408,\n      \"##楊\": 30409,\n      \"##樹\": 30410,\n      \"##橋\": 30411,\n      \"##歌\": 30412,\n      \"##止\": 30413,\n      \"##正\": 30414,\n      \"##武\": 30415,\n      \"##比\": 30416,\n      \"##氏\": 30417,\n      \"##民\": 30418,\n      \"##水\": 30419,\n      \"##氵\": 30420,\n      \"##氷\": 30421,\n      \"##永\": 30422,\n      \"##江\": 30423,\n      \"##沢\": 30424,\n      \"##河\": 30425,\n      \"##治\": 30426,\n      \"##法\": 30427,\n      \"##海\": 30428,\n      \"##清\": 30429,\n      \"##漢\": 30430,\n      \"##瀬\": 30431,\n      \"##火\": 30432,\n      \"##版\": 30433,\n      \"##犬\": 30434,\n      \"##王\": 30435,\n      \"##生\": 30436,\n      \"##田\": 30437,\n      \"##男\": 30438,\n      \"##疒\": 30439,\n      \"##発\": 30440,\n      \"##白\": 30441,\n      \"##的\": 30442,\n      \"##皇\": 30443,\n      \"##目\": 30444,\n      \"##相\": 30445,\n      \"##省\": 30446,\n      \"##真\": 30447,\n      \"##石\": 30448,\n      \"##示\": 30449,\n      \"##社\": 30450,\n      \"##神\": 30451,\n      \"##福\": 30452,\n      \"##禾\": 30453,\n      \"##秀\": 30454,\n      \"##秋\": 30455,\n      \"##空\": 30456,\n      \"##立\": 30457,\n      \"##章\": 30458,\n      \"##竹\": 30459,\n      \"##糹\": 30460,\n      \"##美\": 30461,\n      \"##義\": 30462,\n      \"##耳\": 30463,\n      \"##良\": 30464,\n      \"##艹\": 30465,\n      \"##花\": 30466,\n      \"##英\": 30467,\n      \"##華\": 30468,\n      \"##葉\": 30469,\n      \"##藤\": 30470,\n      \"##行\": 30471,\n      \"##街\": 30472,\n      \"##西\": 30473,\n      \"##見\": 30474,\n      \"##訁\": 30475,\n      \"##語\": 30476,\n      \"##谷\": 30477,\n      \"##貝\": 30478,\n      \"##貴\": 30479,\n      \"##車\": 30480,\n      \"##軍\": 30481,\n      \"##辶\": 30482,\n      \"##道\": 30483,\n      \"##郎\": 30484,\n      \"##郡\": 30485,\n      \"##部\": 30486,\n      \"##都\": 30487,\n      \"##里\": 30488,\n      \"##野\": 30489,\n      \"##金\": 30490,\n      \"##鈴\": 30491,\n      \"##镇\": 30492,\n      \"##長\": 30493,\n      \"##門\": 30494,\n      \"##間\": 30495,\n      \"##阝\": 30496,\n      \"##阿\": 30497,\n      \"##陳\": 30498,\n      \"##陽\": 30499,\n      \"##雄\": 30500,\n      \"##青\": 30501,\n      \"##面\": 30502,\n      \"##風\": 30503,\n      \"##食\": 30504,\n      \"##香\": 30505,\n      \"##馬\": 30506,\n      \"##高\": 30507,\n      \"##龍\": 30508,\n      \"##龸\": 30509,\n      \"##ﬁ\": 30510,\n      \"##ﬂ\": 30511,\n      \"##！\": 30512,\n      \"##（\": 30513,\n      \"##）\": 30514,\n      \"##，\": 30515,\n      \"##－\": 30516,\n      \"##．\": 30517,\n      \"##／\": 30518,\n      \"##：\": 30519,\n      \"##？\": 30520,\n      \"##～\": 30521\n    }\n  }\n}"
  },
  {
    "path": "main.py",
    "content": "from commands.cli import cli\nfrom commands.llm import llm\n\nif __name__ == '__main__':\n    cli()\n    "
  },
  {
    "path": "nginx.conf",
    "content": "# Define the user and worker processes\nuser  nginx;\nworker_processes  auto;\n\n# Set the error log and pid file locations\nerror_log  /var/log/nginx/error.log warn;\npid        /var/run/nginx.pid;\n\n# Main HTTP block\n\nevents {}\nhttp {\n    include       /etc/nginx/mime.types;\n    default_type  application/octet-stream;\n\n    # Access and error log\n    access_log /var/log/nginx/access.log;\n\n    upstream zitadel {\n        server zitadel:8080;  # This references the 'zitedal' service by its name and internal port 8080\n    }\n\n    upstream backend {\n        server backend:8001;  # This references the 'backend' service by its name and internal port 8080\n    }\n\n\n    # Server block for HTTP (port 80)\n    server {\n        listen       80;                                                                                                                                                                                                                                                                 \n        client_max_body_size 100M;  # Set to 10 MB or your desired size                                                                                                                                                                                                           \n        # server_name  20.84.41.108;\n\n        # Set the root directory for static files\n        root   /usr/share/nginx/html;\n        index  index.html index.htm;\n\n        location /api/ {\n            proxy_pass http://backend/api/;  # Forward to ZiteDal\n            proxy_set_header Host $host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto $scheme;\n        }\n        location / {\n            proxy_pass http://backend/;  # Forward to ZiteDal\n            proxy_set_header Host $host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto $scheme;\n        }\n\n        # Handle 404 errors for any unknown routes\n        error_page 404 /404.html;\n        location = /404.html {\n            root /usr/share/nginx/html;\n        }\n\n        # Handle 50x errors\n        error_page 500 502 503 504 /50x.html;\n        location = /50x.html {\n            root /usr/share/nginx/html;\n        }\n    }\n\n    server {\n        listen       82;\n        # server_name  20.84.41.108;\n\n        # Set the root directory for static files\n        root   /usr/share/nginx/html;\n        index  index.html index.htm;\n\n        location /ui/ {\n            proxy_pass http://zitadel/ui/;  # Forward to ZiteDal\n            proxy_set_header Host $host:$server_port;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto $scheme;\n        }\n\n        location /oauth/ {\n            proxy_pass http://zitadel/oauth/;  # Forward to ZiteDal\n            proxy_set_header Host $host:$server_port;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto $scheme;\n        }\n       \n\n        location / {\n            proxy_pass http://zitadel/;  # Forward to ZiteDal\n            proxy_set_header Host $host:$server_port;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto $scheme;\n            # proxy_set_header X-Forwarded-Uri $request_uri;\n        }\n\n\n        # Handle 404 errors for any unknown routes\n        error_page 404 /404.html;\n        location = /404.html {\n            root /usr/share/nginx/html;\n        }\n\n        # Handle 50x errors\n        error_page 500 502 503 504 /50x.html;\n        location = /50x.html {\n            root /usr/share/nginx/html;\n        }\n    }\n}\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[tool.poetry]\nname = \"raggenie\"\nversion = \"0.0.1\"\ndescription = \"Raggenie is a platform for easy RAG building and integration.\"\nauthors = [\"Sirocco ventures <info@siroccoventures.com>\"]\nlicense = \"MIT\"\nreadme = \"README.md\"\n\n[tool.poetry.dependencies]\npython = \"^3.11\"\naiofiles = \"23.2.1\"\naiohappyeyeballs = \"2.4.0\"\naiohttp = \"3.10.5\"\naiosignal = \"1.3.1\"\nannotated-types = \"0.7.0\"\nanyio = \"4.4.0\"\napscheduler = \"3.10.4\"\nargcomplete = \"3.5.0\"\nasgiref = \"3.8.1\"\nasyncer = \"0.0.7\"\nattrs = \"24.2.0\"\nbackoff = \"2.2.1\"\nbcrypt = \"4.2.0\"\nbeautifulsoup4 = \"4.12.3\"\nbidict = \"0.23.1\"\nbuild = \"1.2.2\"\ncachetools = \"5.5.0\"\ncertifi = \"2024.8.30\"\ncffi = \"1.17.1\"\nchainlit = \"1.1.404\"\nchardet = \"5.2.0\"\ncharset-normalizer = \"3.3.2\"\nchevron = \"0.14.0\"\nchroma-hnswlib = \"0.7.6\"\nchromadb = \"0.5.5\"\nclick = \"8.1.7\"\ncoloredlogs = \"15.0.1\"\ncryptography = \"43.0.1\"\ndependency-injector = \"4.42.0\"\ndeprecated = \"1.2.14\"\ndeprecation = \"2.1.0\"\ndocx2txt = \"0.8\"\nebooklib = \"0.18\"\net-xmlfile = \"1.1.0\"\nfastapi = \"0.110.3\"\nfilelock = \"3.16.0\"\nfiletype = \"1.2.0\"\nflatbuffers = \"24.3.25\"\nflatdict = \"4.0.1\"\nfrozenlist = \"1.4.1\"\nfsspec = \"2024.9.0\"\ngoogle-api-core = \"2.19.2\"\ngoogle-auth = \"2.34.0\"\ngoogle-cloud = \"0.34.0\"\ngoogle-cloud-bigquery = \"3.25.0\"\ngoogle-cloud-core = \"2.4.1\"\ngoogle-crc32c = \"1.6.0\"\ngoogle-resumable-media = \"2.7.2\"\ngoogleapis-common-protos = \"1.65.0\"\ngrpcio = \"1.66.1\"\ngrpcio-status = \"1.62.3\"\nh11 = \"0.14.0\"\nhttpcore = \"1.0.5\"\nhttptools = \"0.6.1\"\nhttpx = \"0.27.2\"\nhuggingface-hub = \"0.24.7\"\nhumanfriendly = \"10.0\"\nidna = \"3.10\"\nimportlib-metadata = \"8.4.0\"\nimportlib-resources = \"6.4.5\"\njsonpatch = \"1.33\"\njsonpointer = \"3.0.0\"\nkubernetes = \"30.1.0\"\nlangchain = \"0.3.0\"\nlangchain-core = \"0.3.0\"\nlangchain-text-splitters = \"0.3.0\"\nlangsmith = \"0.1.120\"\nlazify = \"0.4.0\"\nliteralai = \"0.0.607\"\nloguru = \"0.7.2\"\nlxml = \"5.3.0\"\nmarkdown-it-py = \"3.0.0\"\nmarshmallow = \"3.22.0\"\nmdurl = \"0.1.2\"\nmmh3 = \"4.1.0\"\nmonotonic = \"1.6\"\nmpmath = \"1.3.0\"\nmultidict = \"6.1.0\"\nmypy-extensions = \"1.0.0\"\nmysql-connector-python = \"9.0.0\"\nnest-asyncio = \"1.6.0\"\nnumpy = \"1.26.4\"\noauthlib = \"3.2.2\"\nonnxruntime = \"1.19.2\"\nopenpyxl = \"3.1.5\"\noracledb = \"^2.4.1\"\norjson = \"3.10.7\"\noverrides = \"7.7.0\"\npackaging = \"23.2\"\npillow = \"10.4.0\"\nposthog = \"3.6.5\"\nproto-plus = \"1.24.0\"\nprotobuf = \"4.25.4\"\npsycopg2-binary = \"2.9.9\"\npyasn1 = \"0.6.1\"\npyasn1-modules = \"0.4.1\"\npycparser = \"2.22\"\npydantic = \"2.9.1\"\npydantic-settings = \"2.5.2\"\npydantic-core = \"2.23.3\"\npygments = \"2.18.0\"\npyjwt = \"2.9.0\"\npymupdf = \"1.24.10\"\npymupdfb = \"1.24.10\"\npymysql = \"1.1.1\"\npypika = \"0.48.9\"\npyproject-hooks = \"1.1.0\"\npython-dateutil = \"2.9.0.post0\"\npython-dotenv = \"1.0.1\"\npython-engineio = \"4.9.1\"\npython-multipart = \"0.0.9\"\npython-pptx = \"1.0.2\"\npython-socketio = \"5.11.4\"\npytz = \"2024.2\"\npyyaml = \"6.0.2\"\nrequests = \"2.32.3\"\nrequests-oauthlib = \"2.0.0\"\nrich = \"13.8.1\"\nrsa = \"4.9\"\nsetuptools = \"75.0.0\"\nshellingham = \"1.5.4\"\nsimple-websocket = \"1.0.0\"\nsix = \"1.16.0\"\nsniffio = \"1.3.1\"\nsoupsieve = \"2.6\"\nspeechrecognition = \"3.10.4\"\nsplunk-sdk = \"2.0.2\"\nsqlalchemy = \"2.0.34\"\nsqlparse = \"0.5.1\"\nsqlvalidator = \"0.0.20\"\nstarlette = \"0.37.2\"\nsympy = \"1.13.2\"\nsyncer = \"2.0.3\"\ntenacity = \"8.5.0\"\ntextract = \"1.5.0\"\ntokenizers = \"0.20.0\"\ntomark = \"0.1.4\"\ntomli = \"2.0.1\"\ntqdm = \"4.66.5\"\ntyper = \"0.12.5\"\ntyping-inspect = \"0.9.0\"\ntyping-extensions = \"4.12.2\"\ntzlocal = \"5.2\"\nuptrace = \"1.26.0\"\nurllib3 = \"2.2.3\"\nuvicorn = \"0.25.0\"\nuvloop = \"0.20.0\"\nwatchfiles = \"0.20.0\"\nwebsocket-client = \"1.8.0\"\nwebsockets = \"13.0.1\"\nwrapt = \"1.16.0\"\nwsproto = \"1.2.0\"\nxlrd = \"2.0.1\"\nxlsxwriter = \"3.2.0\"\nxmltodict = \"0.13.0\"\nyarl = \"1.11.1\"\nzipp = \"3.20.2\"\npymongo = \"4.8.0\"\npoetry = \"^1.8.3\"\npre-commit = \"^3.8.0\"\ncodespell = \"^2.3.0\"\nflake8 = \"^7.1.1\"\npep8-naming = \"^0.14.1\"\n\n\n[build-system]\nrequires = [\"poetry-core\"]\nbuild-backend = \"poetry.core.masonry.api\"\n"
  },
  {
    "path": "requirements.txt",
    "content": "aiofiles==23.2.1\naiohappyeyeballs==2.4.0\naiohttp==3.10.5\naiosignal==1.3.1\nannotated-types==0.7.0\nanyio==4.4.0\nAPScheduler==3.10.4\nargcomplete==3.5.0\nasgiref==3.8.1\nasyncer==0.0.7\nattrs==24.2.0\nbackoff==2.2.1\nbcrypt==4.2.0\nbeautifulsoup4==4.12.3\nbidict==0.23.1\nbuild==1.2.2\ncachetools==5.5.0\ncertifi==2024.8.30\ncffi==1.17.1\nchainlit==1.1.404\nchardet==5.2.0\ncharset-normalizer==3.3.2\nchevron==0.14.0\nchroma-hnswlib==0.7.6\nchromadb==0.5.5\nclick==8.1.7\ncoloredlogs==15.0.1\ncryptography==43.0.1\ndependency-injector==4.42.0\nDeprecated==1.2.14\ndeprecation==2.1.0\ndocx2txt==0.8\nEbookLib==0.18\net-xmlfile==1.1.0\nfastapi==0.110.3\nfilelock==3.16.0\nfiletype==1.2.0\nflatbuffers==24.3.25\nflatdict==4.0.1\nfrozenlist==1.4.1\nfsspec==2024.9.0\ngoogle-api-core==2.19.2\ngoogle-auth==2.34.0\ngoogle-cloud==0.34.0\ngoogle-cloud-bigquery==3.25.0\ngoogle-cloud-core==2.4.1\ngoogle-crc32c==1.6.0\ngoogle-resumable-media==2.7.2\ngoogleapis-common-protos==1.65.0\ngrpcio==1.66.1\ngrpcio-status==1.62.3\nh11==0.14.0\nhttpcore==1.0.5\nhttptools==0.6.1\nhttpx==0.27.2\nhuggingface-hub==0.24.7\nhumanfriendly==10.0\nidna==3.10\nimportlib_metadata==8.4.0\nimportlib_resources==6.4.5\njsonpatch==1.33\njsonpointer==3.0.0\nkubernetes==30.1.0\nlangchain==0.3.0\nlangchain-core==0.3.0\nlangchain-text-splitters==0.3.0\nlangsmith==0.1.120\nLazify==0.4.0\nliteralai==0.0.607\nloguru==0.7.2\nlxml==5.3.0\nmarkdown-it-py==3.0.0\nmarshmallow==3.22.0\nmdurl==0.1.2\nmmh3==4.1.0\nmonotonic==1.6\nmpmath==1.3.0\nmultidict==6.1.0\nmypy-extensions==1.0.0\nmysql-connector-python==9.0.0\nnest-asyncio==1.6.0\nnumpy==1.26.4\noauthlib==3.2.2\nonnxruntime==1.20.0\nopenpyxl==3.1.5\noracledb==2.4.1\norjson==3.10.7\noverrides==7.7.0\npackaging==23.2\npandas==2.2.3\npillow==10.4.0\nposthog==3.6.5\nproto-plus==1.24.0\npsycopg2-binary==2.9.9\npyasn1==0.6.1\npyasn1_modules==0.4.1\npycparser==2.22\npydantic==2.9.1\npydantic-settings==2.5.2\npydantic_core==2.23.3\nPygments==2.18.0\nPyJWT==2.9.0\nPyMySQL==1.1.1\npyodbc==5.2.0\nPyPika==0.48.9\npyproject_hooks==1.1.0\npytest==8.3.3\npytest-cov==5.0.0\npython-dateutil==2.9.0.post0\npython-dotenv==1.0.1\npython-engineio==4.9.1\npython-multipart==0.0.9\npython-pptx==1.0.2\npython-socketio==5.11.4\npytz==2024.2\nPyYAML==6.0.2\nrequests==2.32.3\nrequests-oauthlib==2.0.0\nrich==13.8.1\nrsa==4.9\nsetuptools==75.0.0\nshellingham==1.5.4\nsimple-websocket==1.0.0\nsix==1.16.0\nsniffio==1.3.1\nsoupsieve==2.6\nSpeechRecognition==3.10.4\nsplunk-sdk==2.0.2\nSQLAlchemy==2.0.34\nsqlparse==0.5.1\nsqlvalidator==0.0.20\nstarlette==0.37.2\nsympy==1.13.2\nsyncer==2.0.3\ntenacity==8.5.0\ntextract==1.5.0\noracledb\ntokenizers==0.20.0\ntomark==0.1.4\ntomli==2.0.1\ntqdm==4.66.5\ntyper==0.12.5\ntyping-inspect==0.9.0\ntyping_extensions==4.12.2\ntzlocal==5.2\nuptrace==1.26.0\nurllib3==2.2.3\nuvicorn==0.25.0\nwatchfiles==0.20.0\nwebsocket-client==1.8.0\nwebsockets==13.0.1\nwrapt==1.16.0\nwsproto==1.2.0\nxlrd==2.0.1\nXlsxWriter==3.2.0\nxmltodict==0.13.0\nyarl==1.11.1\nzipp==3.20.2\npymongo==4.8.0\npoetry==1.8.3\npre-commit==3.8.0\ncodespell==2.3.0\nflake8==7.1.1\npep8-naming==0.14.1\nuvloop==0.20.0; sys_platform != 'win32'\nJinja2==3.1.4\ndocling==2.39.0\nmariadb==1.1.12\nrapidocr_onnxruntime==1.4.4"
  },
  {
    "path": "setup.py",
    "content": "import os\nfrom setuptools import setup, find_packages\n\n\n\n\ndef read(fname):\n    return open(os.path.join(os.path.dirname(__file__), fname)).read()\n\n\n\n\n# Function to read requirements from requirements.txt\ndef parse_requirements(filename):\n    with open(filename, 'r') as f:\n        return f.read().splitlines()\n\n\nsetup(\n    name='raggenie',\n    version='0.0.1',\n    author='sirocco ventures',\n    author_email='info@siroccoventures.com',\n    description='Raggenie is a platform for easy RAG building and integration.',\n    long_description=open('README.md').read(),\n    long_description_content_type='text/markdown',\n    url=\"https://github.com/sirocco-ventures/raggenie\",\n    license='MIT',\n    packages=find_packages(),\n    install_requires=parse_requirements('requirements.txt'),  # Pulls dependencies from requirements.txt\n)"
  },
  {
    "path": "tests/README.md",
    "content": "## Getting Started\n\nThis 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.\n\n### Project Structure\n- `functional/`: Contains functional tests (`test_*.py`).\n- `integration/`: Contains integration tests (`test_*.py`).\n- `unittest/`: Contains unit tests (`test_*.py`).\n\n## Requirements\n- `pip install pytest pytest-cov`\n\n\n### Running Tests\n- Run all tests: `pytest`\n- To run specific tests:\n  - Functional tests: `pytest functional/`\n  - Integration tests: `pytest integration/`\n  - Unit tests: pytest `unittest/`\n\n### Test Coverage\nTo measure test coverage using pytest-cov:\n- Run tests with coverage: `pytest --cov=.`\n- To view detailed missing line coverage in the terminal: `pytest --cov=. --cov-report=term-missing`\n- To generate an HTML coverage report: `pytest --cov=. --cov-report=term-missing --cov-report=html`\n\n\n\n### Configuration\nTest configurations and database setups are defined in conftest.py. The test environment uses SQLite for isolated testing."
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/conftest.py",
    "content": "from typing import Generator, Any\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom sqlalchemy import create_engine\nfrom sqlalchemy.orm import sessionmaker\nfrom sqlalchemy.orm import Session\nfrom app.models.provider import Provider\nfrom app.utils.database import Base\nfrom app.utils.database import get_db\nfrom app.api.v1.provider import router\nfrom app.api.v1.llmchat import chat_router\nfrom app.api.v1.connector import router as ConnectorRouter\nfrom app.api.v1.connector import cap_router as capabilityrouter\nfrom app.api.v1.connector import inference_router as inference_router\nfrom app.api.v1.connector import actions as actions\nfrom app.api.v1.main_router import MainRouter\nfrom app.api.v1.provider import sample as sample_sql\n\n# Function to initialize the FastAPI application with all necessary routers\ndef start_application() -> FastAPI:\n    app = FastAPI()\n    app.include_router(MainRouter, prefix=\"/api/v1/query\")\n    app.include_router(router, prefix=\"/api/v1/provider\")\n    app.include_router(chat_router, prefix=\"/api/v1/chat\")\n    app.include_router(capabilityrouter, prefix=\"/api/v1/capability\")\n    app.include_router(inference_router, prefix=\"/api/v1/inference\")\n    app.include_router(ConnectorRouter, prefix=\"/api/v1/connector\")\n    app.include_router(actions, prefix=\"/api/v1/actions\")\n    app.include_router(sample_sql, prefix=\"/api/v1/sql\")\n\n    return app\n\n# Database URL for testing with SQLite\nSQLALCHEMY_DATABASE_URL = \"sqlite:///./test_db.db\"\n# Create a SQLAlchemy engine for testing\nengine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={\"check_same_thread\": False})\nSessionTesting = sessionmaker(autocommit=False, autoflush=False, bind=engine)\n\n# Fixture to create a fresh database for each test case\n@pytest.fixture(scope=\"function\")\ndef app() -> Generator[FastAPI, None, None]:\n    \"\"\"\n    Create a fresh database on each test case.\n    \"\"\"\n    Base.metadata.create_all(engine)  # Create the database tables\n    _app = start_application()  # Initialize the FastAPI application\n    yield _app  # Yield the application instance for use in tests\n    Base.metadata.drop_all(engine)  # Drop the database tables after tests\n\n# Fixture to manage database sessions for tests\n@pytest.fixture(scope=\"function\")\ndef db_session(app: FastAPI) -> Generator[Session, None, None]:\n    # Connect to the database and begin a transaction for testing\n    connection = engine.connect()\n    transaction = connection.begin()\n    session = SessionTesting(bind=connection)  # Create a new session\n    yield session  # Yield the session for use in tests\n    session.close()  # Close the session after tests\n    transaction.rollback()  # Roll back the transaction to maintain isolation\n    connection.close()  # Close the database connection\n\n# Fixture to create a FastAPI TestClient for sending requests in tests\n@pytest.fixture(scope=\"function\")\ndef client(app: FastAPI, db_session: Session) -> Generator[TestClient, None, None]:\n    \"\"\"\n    Create a new FastAPI TestClient that uses the `db_session` fixture to override\n    the `get_db` dependency that is injected into routes.\n    \"\"\"\n\n    # Override the get_db dependency to use the test database session\n    def _get_test_db():\n        try:\n            yield db_session  # Yield the test database session\n        finally:\n            pass\n\n    app.dependency_overrides[get_db] = _get_test_db  # Apply the dependency override\n    with TestClient(app) as client:\n        yield client  # Yield the TestClient for use in tests\n\n# Fixture to create a sample Provider for testing\n@pytest.fixture\ndef provider_fixture(db_session: Session) -> Provider:\n    # Sample provider data for creating a Provider instance\n    provider_data = {\n        \"name\": \"website provider\",\n        \"description\": \"Provider for website connectors\",\n        \"enable\": True,\n        \"icon\": \"website.png\",\n        \"category_id\": 1,\n        \"key\": \"website\",\n    }\n    new_provider = Provider(**provider_data)  # Create a new Provider instance\n    db_session.add(new_provider)  # Add the provider to the session\n    db_session.commit()  # Commit the session to save the provider\n    db_session.refresh(new_provider)  # Refresh the provider instance to get updated data\n    return new_provider  # Return the created Provider instance\n"
  },
  {
    "path": "tests/functional/test_commons.py",
    "content": ""
  },
  {
    "path": "tests/functional/test_connectors.py",
    "content": "import pytest\nfrom unittest.mock import patch\nfrom fastapi.testclient import TestClient\n\n# Use the pytest fixture for the FastAPI test client\n@pytest.mark.usefixtures(\"client\")\nclass TestConnectorAPI:\n\n    # Parameterized test for listing connectors\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: valid connector data returned\n            ([{\"id\": 1, \"name\": \"Connector A\"}], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"connectors\": [{\"id\": 1, \"name\": \"Connector A\"}]},\n                \"message\": \"Connectors Found\",\n                \"error\": None\n            }, 200),\n            # Empty connector case: no connectors found\n            ([], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"connectors\": []},\n                \"message\": \"Connector Not Found\",\n                \"error\": \"Not Found\"\n            }, 200),\n            # Database error case: simulate a database error\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"data\": {\"connectors\": []},\n                \"message\": \"DB Error\",\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.list_connectors')\n    def test_list_connectors(self, mock_list_connectors, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Mock the list_connectors service to return the specified value and error\n        mock_list_connectors.return_value = (mock_return_value, error)\n\n        # Make a GET request to the list connectors endpoint\n        response = client.get(\"/api/v1/connector/list\")\n\n        # Assert the response status code and content\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Parameterized test for getting a specific connector\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: valid connector data returned\n            ({\"id\": 1, \"name\": \"Connector A\"}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"connector\": {\"id\": 1, \"name\": \"Connector A\"}},\n                \"message\": \"Connector Found\",\n                \"error\": None\n            }, 200),\n            # Connector not found case: empty response\n            ({}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"connector\": {}},\n                \"message\": \"Connector Not Found\",\n                \"error\": \"Not Found\"\n            }, 200),\n            # Database error case: simulate a database error\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"data\": {\"connector\": {}},\n                \"message\": \"DB Error\",\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.get_connector')\n    def test_get_connector(self, mock_get_connector, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Mock the get_connector service to return the specified value and error\n        mock_get_connector.return_value = (mock_return_value, error)\n\n        # Make a GET request to the get connector endpoint\n        response = client.get(\"/api/v1/connector/get/1\")\n\n        # Assert the response status code and content\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Parameterized test for creating a new connector\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: valid connector creation\n            ({\"id\": 1, \"name\": \"Connector A\", \"type\": 1, \"config\": {\"type\": \"Config A\"}}, None, {\n                \"status\": True,\n                \"status_code\": 201,\n                \"data\": {\"connector\": {\"id\": 1, \"name\": \"Connector A\", \"type\": 1, \"config\": {\"type\": \"Config A\"}}},\n                \"message\": \"Connector Created\",\n                \"error\": None\n            }, 200),\n            # Database error case: simulate a database error\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"data\": {\"connector\": {}},\n                \"message\": \"Connector Not Created\",\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.create_connector')\n    def test_create_connector(self, mock_create_connector, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Mock the create_connector service to return the specified value and error\n        mock_create_connector.return_value = (mock_return_value, error)\n\n        # Make a POST request to the create connector endpoint with the connector data\n        response = client.post(\"/api/v1/connector/create\", json={\n            \"name\": \"Connector A\",\n            \"connector_type\": 1,\n            \"connector_name\": \"Connector A\",\n            \"connector_config\": {\"type\": \"Config A\"}\n        })\n\n        # Assert the response status code and content\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Parameterized test for updating an existing connector\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: valid connector updated\n            ({\"id\": 1, \"name\": \"Connector A\"}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"connector\": {\"id\": 1, \"name\": \"Connector A\"}},\n                \"message\": \"Connector Updated\",\n                \"error\": None\n            }, 200),\n            # Connector not found case: no connector returned\n            (None, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"connector\": {}},\n                \"message\": \"Connector Not Found\",\n                \"error\": \"Not Found\"\n            }, 200),\n            # Database error case: simulate a database error\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"data\": {\"connector\": {}},\n                \"message\": \"DB Error\",\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.update_connector')\n    def test_update_connector(self, mock_update_connector, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Mock the update_connector service to return the specified value and error\n        mock_update_connector.return_value = (mock_return_value, error)\n\n        # Make a POST request to the update connector endpoint with the updated data\n        response = client.post(\"/api/v1/connector/update/1\", json={\"name\": \"Connector A\"})\n\n        # Assert the response status code and content\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Parameterized test for deleting a connector\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: valid connector deleted\n            ({\"id\": 1, \"name\": \"Connector A\"}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"connector\": {\"id\": 1, \"name\": \"Connector A\"}},\n                \"message\": \"Connector Deleted\",\n                \"error\": None\n            }, 200),\n            # Connector not found case: no connector returned\n            (None, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"connector\": {}},\n                \"message\": \"Connector Not Found\",\n                \"error\": \"Not Found\"\n            }, 200),\n            # Database error case: simulate a database error\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"data\": {\"connector\": {}},\n                \"message\": \"DB Error\",\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.delete_connector')\n    def test_delete_connector(self, mock_delete_connector, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Mock the delete_connector service to return the specified value and error\n        mock_delete_connector.return_value = (mock_return_value, error)\n\n        # Make a DELETE request to the delete connector endpoint\n        response = client.delete(\"/api/v1/connector/delete/1\")\n\n        # Assert the response status code and content\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Parameterized test for the update_schemas function\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case\n            ({\"id\": 1, \"schema_config\": [{\"key\": \"value\"}]}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"schemas\": {\"id\": 1, \"schema_config\": [{\"key\": \"value\"}]}},\n                \"message\": \"Schema Updated\",\n                \"error\": None\n            }, 200),\n            # Connector not found case\n            (None, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"schemas\": {}},\n                \"message\": \"Connector Not Found\",\n                \"error\": \"Not Found\"\n            }, 200),\n            # Database error case\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"data\": {\"schemas\": {}},\n                \"message\": \"DB Error\",\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.updateschemas')  # Mock the updateschemas function\n    def test_update_schemas(self, mock_updateschemas, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        mock_updateschemas.return_value = (mock_return_value, error)  # Set mock return value\n\n        # Make a POST request to update schemas\n        response = client.post(\"/api/v1/connector/schema/update/1\", json={\n            \"schema_config\": [{\"key\": \"value\"}]\n        })\n\n        # Assert the status code and response JSON\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Parameterized test for the list_configurations function\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case\n            ([{\"id\": 1, \"name\": \"Config A\"}], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Configurations retrieved successfully\",\n                \"error\": None,\n                \"data\": {\"configurations\": [{\"id\": 1, \"name\": \"Config A\"}]}\n            }, 200),\n            # No configurations found case\n            ([], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Configurations Not Found\",\n                \"error\": \"Not Found\",\n                \"data\": {\"configurations\": []}\n            }, 200),\n            # Database error case\n            (\"DB error\", \"DB error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB error\",\n                \"error\": \"DB error\",\n                \"data\": {\"configurations\": []}\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.list_configurations')  # Mock the list_configurations function\n    def test_list_configurations(self, mock_list_configurations, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        mock_list_configurations.return_value = (mock_return_value, error)  # Set mock return value\n\n        # Make a GET request to list configurations\n        response = client.get(\"/api/v1/connector/configuration/list\")\n\n        # Assert the status code and response JSON\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Parameterized test for the create_configuration function\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case\n            ({\"id\": 1, \"name\": \"Config A\"}, None, {\n                \"status\": True,\n                \"status_code\": 201,\n                \"message\": \"Configuration created successfully\",\n                \"error\": None,\n                \"data\": {\"configuration\": {\"id\": 1, \"name\": \"Config A\"}}\n            }, 200),\n            # Database error case\n            (\"DB error\", \"DB error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB error\",\n                \"error\": \"DB error\",\n                \"data\": {\"configuration\": []}\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.create_configuration')  # Mock the create_configuration function\n    def test_create_configuration(self, mock_create_configuration, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        mock_create_configuration.return_value = (mock_return_value, error)  # Set mock return value\n\n        # Make a POST request to create a new configuration\n        response = client.post(\"/api/v1/connector/configuration/create\", json={\n            \"name\": \"Config A\",\n            \"short_description\": \"Short description\",\n            \"long_description\": \"Long description\",\n            \"status\": 1,\n            \"capabilities\": [1, 2]\n        })\n\n        # Assert the status code and response JSON\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Parameterized test for the update_configuration function\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case\n            ({\"id\": 1, \"name\": \"Config A\"}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Configuration updated successfully\",\n                \"error\": None,\n                \"data\": {\"configuration\": {\"id\": 1, \"name\": \"Config A\"}}\n            }, 200),\n            # Database error case\n            (\"DB error\", \"DB error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB error\",\n                \"error\": \"DB error\",\n                \"data\": {\"configuration\": []}\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.update_configuration')  # Mock the update_configuration function\n    def test_update_configuration(self, mock_update_configuration, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        mock_update_configuration.return_value = (mock_return_value, error)  # Set mock return value\n\n        # Make a POST request to update a configuration\n        response = client.post(\"/api/v1/connector/configuration/update/1\", json={\n            \"name\": \"Config A Updated\",\n            \"short_description\": \"Updated short description\",\n            \"long_description\": \"Updated long description\",\n            \"status\": 1\n        })\n\n        # Assert the status code and response JSON\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: A capability is created successfully\n            ({\"id\": 1, \"name\": \"Capability A\"}, None, {\n                \"status\": True,\n                \"status_code\": 201,\n                \"message\": \"Capabilities created successfully\",\n                \"error\": None,\n                \"data\": {\"capability\": {\"id\": 1, \"name\": \"Capability A\"}}\n            }, 200),\n            # Database error case: Simulating a database error during capability creation\n            (\"DB error\", \"DB error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB error\",\n                \"error\": \"DB error\",\n                \"data\": {\"capability\": {}}\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.create_capabilities')\n    def test_create_capability(self, mock_create_capabilities, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Mock the create_capabilities function to return the specified mock_return_value and error\n        mock_create_capabilities.return_value = (mock_return_value, error)\n\n        # Send a POST request to create a new capability\n        response = client.post(\"/api/v1/capability/create\", json={\n            \"name\": \"Capability A\",\n            \"description\": \"Description for Capability A\",\n            \"requirements\": [{\"key\": \"value\"}]\n        })\n\n        # Assert that the response status code and JSON match the expected values\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: List of capabilities is retrieved successfully\n            ([{\"id\": 1, \"name\": \"Capability A\"}], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Capabilities retrieved successfully\",\n                \"error\": None,\n                \"data\": {\"capabilities\": [{\"id\": 1, \"name\": \"Capability A\"}]}\n            }, 200),\n            # Database error case: Simulating a database error while retrieving capabilities\n            (\"DB error\", \"DB error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB error\",\n                \"error\": \"DB error\",\n                \"data\": {\"capabilities\": []}\n            }, 200),\n            # Not found case: No capabilities are found\n            ([], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Capabilities Not Found\",\n                \"error\": \"Not Found\",\n                \"data\": {\"capabilities\": []}\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.get_all_capabilities')\n    def test_list_capabilities(self, mock_get_all_capabilities, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Mock the get_all_capabilities function to return the specified mock_return_value and error\n        mock_get_all_capabilities.return_value = (mock_return_value, error)\n\n        # Send a GET request to retrieve all capabilities\n        response = client.get(\"/api/v1/capability/all\")\n\n        # Assert that the response status code and JSON match the expected values\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: A capability is updated successfully\n            ({\"id\": 1, \"name\": \"Capability A Updated\"}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Capability updated successfully\",\n                \"error\": None,\n                \"data\": {\"capability\": {\"id\": 1, \"name\": \"Capability A Updated\"}}\n            }, 200),\n            # Database error case: Simulating a database error during capability update\n            (\"DB error\", \"DB error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB error\",\n                \"error\": \"DB error\",\n                \"data\": {\"capability\": {}}\n            }, 200),\n            # Not found case: Capability not found during update\n            (None, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Capability Not Found\",\n                \"error\": \"Not Found\",\n                \"data\": {\"capability\": {}}\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.update_capability')\n    def test_update_capability(self, mock_update_capability, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Mock the update_capability function to return the specified mock_return_value and error\n        mock_update_capability.return_value = (mock_return_value, error)\n\n        # Send a POST request to update a capability\n        response = client.post(\"/api/v1/capability/update/1\", json={\n            \"name\": \"Capability A Updated\",\n            \"description\": \"Updated description\",\n            \"requirements\": [{\"key\": \"new_value\"}]\n        })\n\n        # Assert that the response status code and JSON match the expected values\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: A capability is deleted successfully\n            ({\"id\": 1, \"name\": \"Capability\"}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Capability deleted successfully\",\n                \"error\": None,\n                \"data\": {\"capability\": {}}\n            }, 200),\n            # Database error case: Simulating a database error during capability deletion\n            (\"DB error\", \"DB error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB error\",\n                \"error\": \"DB error\",\n                \"data\": {\"capability\": {}}\n            }, 200),\n            # Not found case: Capability not found during deletion\n            (None, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Capability Not Found\",\n                \"error\": \"Not Found\",\n                \"data\": {\"capability\": {}}\n            }, 200)\n        ]\n    )\n    @patch('app.services.connector.delete_capability')\n    def test_delete_capability(self, mock_delete_capability, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Mock the delete_capability function to return the specified mock_return_value and error\n        mock_delete_capability.return_value = (mock_return_value, error)\n\n        # Send a DELETE request to delete a capability\n        response = client.delete(\"/api/v1/capability/delete/1\")\n\n        # Assert that the response status code and JSON match the expected values\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n"
  },
  {
    "path": "tests/functional/test_llmchat.py",
    "content": "import pytest\nfrom unittest.mock import patch\nfrom fastapi.testclient import TestClient\n\n@pytest.mark.usefixtures(\"client\")\nclass TestLLMChat:\n\n    # Fixture to provide a sample chat payload for tests\n    @pytest.fixture\n    def chat_payload(self):\n        return {\n            \"chat_context_id\": \"context_1\",\n            \"chat_query\": \"What is AI?\",\n            \"chat_answer\": {\"response\": \"Artificial Intelligence\"},\n            \"chat_summary\": \"Summary\",\n            \"user_id\": 123,\n            \"primary_chat\": True\n        }\n\n    # Fixture to provide a sample feedback payload for tests\n    @pytest.fixture\n    def feedback_payload(self):\n        return {\n            \"chat_context_id\": \"context_1\",\n            \"chat_id\": 1,\n            \"feedback_status\": 1,\n            \"feedback_json\": {\"feedback\": \"Good\"}\n        }\n\n    # Test case for creating a chat\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            ({\"chat_id\": 1}, None, {\n                \"status\": True,\n                \"status_code\": 201,\n                \"message\": \"Chat created successfully\",\n                \"data\": {\"chat\": {\"chat_id\": 1}},\n                \"error\": None\n            }, 200),\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB Error\",\n                \"data\": {\"chat\": {}},\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.llmchat.create_chat')  # Mock the create_chat function\n    def test_create_chat(self, mock_create_chat, client: TestClient, chat_payload, mock_return_value, error, expected_response, expected_status_code):\n        mock_create_chat.return_value = (mock_return_value, error)  # Set mock return values\n\n        response = client.post(\"/api/v1/chat/create\", json=chat_payload)  # Make POST request\n\n        # Assertions to verify the response status code and body\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Test case for creating feedback\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            ({\"chat_id\": 1}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Feedback updated successfully\",\n                \"data\": {\"chat\": {\"chat_id\": 1}},\n                \"error\": None\n            }, 200),\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB Error\",\n                \"data\": {\"chat\": {}},\n                \"error\": \"DB Error\"\n            }, 200),\n            (None, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Chat Not Found\",\n                \"data\": {\"chat\": {}},\n                \"error\": \"Not Found\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.llmchat.create_feedback')  # Mock the create_feedback function\n    def test_create_feedback(self, mock_create_feedback, client: TestClient, feedback_payload, mock_return_value, error, expected_response, expected_status_code):\n        mock_create_feedback.return_value = (mock_return_value, error)  # Set mock return values\n\n        response = client.post(\"/api/v1/chat/feedback/create\", json=feedback_payload)  # Make POST request\n\n        # Assertions to verify the response status code and body\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Test case for listing chats by context\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            ([{\"key\": \"value\"}], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Primary chats found\",\n                \"data\": {\"chats\": [{\"key\": \"value\"}]},\n                \"error\": None\n            }, 200),\n            ([], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Context Not found\",\n                \"data\": {\"chats\": []},\n                \"error\": \"Not Found\"\n            }, 200),\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB Error\",\n                \"data\": {\"chats\": []},\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.llmchat.list_chats_by_context')  # Mock the list_chats_by_context function\n    def test_list_chats_by_context(self, mock_list_chats_by_context, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        mock_list_chats_by_context.return_value = (mock_return_value, error)  # Set mock return values\n\n        response = client.get(\"/api/v1/chat/list/context/all\")  # Make GET request\n\n        # Assertions to verify the response status code and body\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    # Test case for getting chat by context ID\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            ([{\"key\": \"value\"}], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Chat found\",\n                \"data\": {\"chats\": [{\"key\": \"value\"}]},\n                \"error\": None\n            }, 200),\n            ([], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Chat not found\",\n                \"data\": {\"chats\": []},\n                \"error\": \"Not Found\"\n            }, 200),\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"DB Error\",\n                \"data\": {\"chats\": []},\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.llmchat.list_all_chats_by_context_id')  # Mock the list_all_chats_by_context_id function\n    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):\n        mock_list_all_chats_by_context_id.return_value = (mock_return_value, error)  # Set mock return values\n\n        response = client.get(\"/api/v1/chat/get/context_1\")  # Make GET request\n\n        # Assertions to verify the response status code and body\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n"
  },
  {
    "path": "tests/functional/test_provider.py",
    "content": "import pytest\nfrom unittest.mock import patch\nfrom fastapi.testclient import TestClient\nfrom app.schemas.provider import CredentialsHelper\n\n# Use fixtures for client management in tests\n@pytest.mark.usefixtures(\"client\")\nclass TestProviderAPI:\n\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: provider found\n            ([{\"id\": 1, \"name\": \"Provider A\"}], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"providers\": [{\"id\": 1, \"name\": \"Provider A\"}]},\n                \"message\": \"Providers Found\",\n                \"error\": None\n            }, 200),\n            # Empty provider case: no providers found\n            ([], None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"providers\": []},\n                \"message\": \"Providers Not Found\",\n                \"error\": \"Not Found\"\n            }, 200),\n            # Database error case: simulates a database error\n            (\"SQL Error\", \"DB error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"data\": {\"providers\": []},\n                \"message\": \"DB error\",\n                \"error\": \"SQL Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.provider.list_providers')  # Mock the list_providers function\n    def test_list_providers(self, mock_list_providers, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Set the mock return value for list_providers\n        mock_list_providers.return_value = (mock_return_value, error)\n\n        # Send a GET request to the endpoint\n        response = client.get(\"/api/v1/provider/list\")\n\n        # Assert the status code and response data match expected values\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: specific provider found\n            ({\"id\": 1, \"name\": \"Provider A\"}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"provider\": {\"id\": 1, \"name\": \"Provider A\"}},\n                \"message\": \"Provider Found\",\n                \"error\": None\n            }, 200),\n            # Provider not found case: no provider data returned\n            ({}, None, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"data\": {\"provider\": {}},\n                \"message\": \"Providers Not Found\",\n                \"error\": \"Not Found\"\n            }, 200),\n            # Database error case: simulates a database error\n            (\"DB Error\", \"DB Error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"data\": {\"provider\": {}},\n                \"message\": \"DB error\",\n                \"error\": \"DB Error\"\n            }, 200)\n        ]\n    )\n    @patch('app.services.provider.get_provider')  # Mock the get_provider function\n    def test_get_provider(self, mock_get_provider, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Set the mock return value for get_provider\n        mock_get_provider.return_value = (mock_return_value, error)\n\n        # Send a GET request to the endpoint for a specific provider\n        response = client.get(\"/api/v1/provider/get/1\")\n\n        # Assert the status code and response data match expected values\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    @pytest.mark.parametrize(\n        \"mock_return_value, error, expected_response, expected_status_code\",\n        [\n            # Success case: credentials test passes\n            (True, \"Test Credentials successfully completed\", {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"Test Credentials successfully completed\",\n                \"error\": None,\n                \"data\": None,\n            }, 200),\n            # Provider not found case: simulates provider not found\n            (None, \"Provider Not Found\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"Provider Not Found\",\n                \"error\": \"Provider Not Found\",\n                \"data\": None,\n            }, 200),\n            # Failed to get provider configurations case\n            (None, \"Failed to get provider configurations\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"Failed to get provider configurations\",\n                \"error\": \"Failed to get provider configurations\",\n                \"data\": None,\n            }, 200),\n            # Unsupported provider case: tests for unsupported provider response\n            (None, \"Unsupported Provider\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"Unsupported Provider\",\n                \"error\": \"Unsupported Provider\",\n                \"data\": None,\n            }, 200),\n            # Missing required key case: checks for missing config key\n            (None, \"Missing required config key: key\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"Missing required config key: key\",\n                \"error\": \"Missing required config key: key\",\n                \"data\": None,\n            }, 200),\n            # Failed to connect case: simulates a connection error during credentials testing\n            (None, \"Test Credentials Failed: Connection error\", {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"Test Credentials Failed: Connection error\",\n                \"error\": \"Test Credentials Failed: Connection error\",\n                \"data\": None,\n            }, 200),\n        ]\n    )\n    @patch('app.services.provider.test_credentials')  # Mock the test_credentials function\n    def test_test_connections(self, mock_test_credentials, client: TestClient, mock_return_value, error, expected_response, expected_status_code):\n        # Set the mock return value for test_credentials\n        mock_test_credentials.return_value = (mock_return_value, error)\n\n        # Create credentials data using the CredentialsHelper\n        credentials = CredentialsHelper(provider_config={\"key\": \"value\"})\n        # Send a POST request to test credentials\n        response = client.post(\"/api/v1/provider/1/test-credentials\", json=credentials.model_dump())\n\n        # Assert the status code and response data match expected values\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n\n    @pytest.mark.parametrize(\n        \"mock_return_value, is_error, expected_response, expected_status_code\",\n        [\n            # Success case: LLM providers found\n            ({\"llm_providers\": [\"Provider A\"]}, False, {\n                \"status\": True,\n                \"status_code\": 200,\n                \"message\": \"LLM providers found\",\n                \"data\": {\"llm_providers\": [\"Provider A\"]},\n                \"error\": None\n            }, 200),\n            # Not found case: no LLM providers returned\n            (None, True, {\n                \"status\": False,\n                \"status_code\": 422,\n                \"message\": \"LLM providers not found\",\n                \"data\": None,\n                \"error\": None\n            }, 200),\n        ]\n    )\n    @patch('app.services.provider.getllmproviders')  # Mock the getllmproviders function\n    def test_getllmproviders(self, mock_getllmproviders, client: TestClient, mock_return_value, is_error, expected_response, expected_status_code):\n        # Set the mock return value for getllmproviders\n        mock_getllmproviders.return_value = (mock_return_value, is_error)\n\n        # Send a GET request to fetch LLM providers\n        response = client.get(\"/api/v1/provider/llmproviders\")\n\n        # Assert the status code and response data match expected values\n        assert response.status_code == expected_status_code\n        assert response.json() == expected_response\n"
  },
  {
    "path": "tests/integration/test_integration_connector.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom sqlalchemy.orm import Session\nfrom app.models.connector import Connector\nfrom app.models.provider import Provider, ProviderConfig\nfrom unittest.mock import patch\n\n# Use pytest fixtures for client and database session management\n@pytest.mark.usefixtures(\"client\", \"db_session\")\nclass TestConnectorAPI:\n\n    # Integration testing for creating a PDF-based connector\n    @patch('app.repository.provider.get_config_types')  # Mock the get_config_types function to return predefined values\n    def test_create_connector_type_2(self, mock_get_config_types, client: TestClient, db_session: Session, provider_fixture: Provider):\n\n        # Mocking the return value of get_config_types to simulate a response from the provider config\n        mock_get_config_types.return_value = (\n            [\n                ProviderConfig(slug=\"website_url\", field=\"website_url\"),\n            ],\n            False\n        )\n\n        # Prepare the connector data for the POST request\n        connector_data = {\n            \"connector_type\": provider_fixture.id,  # Use the provider ID from the fixture\n            \"connector_name\": \"Test Website Connector\",  # Name of the connector\n            \"connector_description\": \"Connector for Website database\",  # Description of the connector\n            \"connector_config\": {\n                \"website_url\":\"https://www.siroccoventures.com/\"\n            }\n        }\n\n        # Perform the POST request to create the connector\n        response = client.post(\"/api/v1/connector/create\", json=connector_data)\n\n        # Check the response from the API\n        response_data = response.json()  # Get the JSON response data\n\n        # Assert that the response status code is 200 (OK)\n        assert response.status_code == 200\n        # Assert that the status in the response data is True\n        assert response_data[\"status\"] is True\n        # Assert that the message indicates the connector was created\n        assert response_data[\"message\"] == \"Connector Created\"\n        # Assert that the returned connector name matches the input data\n        assert response_data[\"data\"][\"connector\"][\"connector_name\"] == connector_data[\"connector_name\"]\n        # Assert that the returned connector type matches the provider ID\n        assert response_data[\"data\"][\"connector\"][\"connector_type\"] == provider_fixture.id\n\n        # Verify that the connector has been created in the database\n        created_connector = db_session.query(Connector).filter(Connector.connector_name == connector_data[\"connector_name\"]).first()\n        # Assert that the created connector is not None (it should exist in the database)\n        assert created_connector is not None\n"
  },
  {
    "path": "tests/unittest/test_svc/test_svc_provider.py",
    "content": "from fastapi.testclient import TestClient\nfrom sqlalchemy.orm import Session\nfrom app.models.provider import Provider\nfrom app.api.v1.provider import router\nfrom app.services import provider as svc\nfrom app.schemas.provider import ProviderResp\nfrom unittest.mock import patch\nimport pytest\n\n# Use the pytest fixture for client management\n@pytest.mark.usefixtures(\"client\")\nclass TestProviderAPI:\n\n    # Test case for successfully retrieving a provider by ID\n    @patch('app.services.provider.repo')  # Mock the repository layer for the test\n    def test_get_provider_success(self, mock_repo, db_session: Session):\n        # Create a mock provider instance to simulate a successful database return\n        provider = Provider(\n            id=1,\n            name=\"Test Provider\",\n            description=\"A test provider\",\n            enable=True,\n            icon=\"icon.png\",\n            category_id=1,\n            key=\"test_provider\"\n        )\n        provider.providerconfig = []  # Initialize an empty list for provider config\n\n        # Set the mock return value for the repo method\n        mock_repo.get_provider_by_id.return_value = (provider, False)\n\n        # Call the service method to get the provider\n        result, error = svc.get_provider(1, db_session)\n\n        # Assertions to verify the correct behavior\n        assert error is None  # No error should occur\n        assert isinstance(result, ProviderResp)  # Result should be an instance of ProviderResp\n        assert result.id == 1  # ID should match the mock provider's ID\n        assert result.name == \"Test Provider\"  # Name should match the mock provider's name\n\n    # Test case for handling a database error when retrieving a provider\n    @patch('app.services.provider.repo')  # Mock the repository layer for the test\n    def test_get_provider_db_error(self, mock_repo, db_session: Session):\n        # Simulate a database error by returning None and an error message\n        mock_repo.get_provider_by_id.return_value = (None, \"DB Error\")\n\n        # Call the service method to get the provider\n        result, error = svc.get_provider(1, db_session)\n\n        # Assertions to verify the correct error handling\n        assert error == \"DB Error\"  # Error should match the simulated database error\n        assert result is None  # Result should be None due to the error\n\n    # Test case for handling a case where a provider is not found\n    @patch('app.services.provider.repo')  # Mock the repository layer for the test\n    def test_get_provider_not_found(self, mock_repo, db_session: Session):\n        # Simulate a case where no provider is found by returning an empty dict and no error\n        mock_repo.get_provider_by_id.return_value = ({}, None)\n\n        # Call the service method to get the provider\n        result, error = svc.get_provider(1, db_session)\n\n        # Assertions to verify the correct handling of a not found case\n        assert error is None  # No error should occur\n        assert result == {}  # Result should be an empty dict\n"
  },
  {
    "path": "ui/.dockerignore",
    "content": "\r\nnode_modules"
  },
  {
    "path": "ui/Dockerfile",
    "content": "FROM node:20-alpine AS build\n\nARG BACKEND_URL\n\nWORKDIR /app\n\nCOPY package.json ./\nRUN npm install\n\nCOPY . .\n\nENV VITE_BACKEND_URL=$BACKEND_URL\n\nRUN npm run build\n\nFROM nginx:stable-alpine\n\nCOPY --from=build /app/dist /usr/share/nginx/html\n\nCOPY --from=build /app/dist-library /usr/share/nginx/html\n\nCOPY nginx.conf /etc/nginx/conf.d/default.conf\n\nEXPOSE 5000\n\n# Start Nginx\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n"
  },
  {
    "path": "ui/README.md",
    "content": "# Ragginie Frontend\n\n\n## Run Locally\n\nClone the project\n\n```bash\n  git clone https://github.com/sirocco-ventures/raggenie\n```\n\nGo to the project directory\n\n```bash\n  cd raggenie/ui\n```\n\nInstall dependencies\n\n```bash\n  npm install\n```\n\n\nCreate a .env file add the following env variables\n\n```env\n    VITE_BACKEND_URL=${BACKEND_URL}\n```\n\nStart the server\n\n```bash\n  npm run dev\n```\n\n"
  },
  {
    "path": "ui/eslint.config.js",
    "content": "import globals from \"globals\";\nimport pluginJs from \"@eslint/js\";\nimport pluginReact from \"eslint-plugin-react\";\n\n\nexport default [\n  {\n    files: [\"**/*.{js,mjs,cjs,jsx}\"]\n  },\n  {\n    languageOptions: { \n      globals: globals.browser \n    }\n  },\n  pluginJs.configs.recommended,\n  pluginReact.configs.flat.recommended,\n  {\n    \"rules\": {\n      \"no-console\": \"error\",\n      \"no-multiple-empty-lines\": \"error\",\n      \"react/react-in-jsx-scope\": \"off\",\n      \"react/prop-types\": \"off\",\n      \"react/jsx-uses-react\": \"off\",\n    }\n  }\n  \n];"
  },
  {
    "path": "ui/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/raggenie.svg\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Raggenie</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/main.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "ui/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"src/*\": [\"./src/*\"],\n    }\n  }\n}"
  },
  {
    "path": "ui/nginx.conf",
    "content": "server {\n    listen 5000;server_name localhost;\n    location / {\n        root /usr/share/nginx/html;\n        index index.html;\n        try_files $uri $uri/ /index.html;\n    }\n}"
  },
  {
    "path": "ui/package.json",
    "content": "{\n  \"name\": \"raggenie\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\",\n    \"prebuild\": \"vite build --config vite.library.config.js\",\n    \"lint\": \"eslint .\",\n    \"preview\": \"vite preview\",\n    \"test\": \"vitest\"\n  },\n  \"dependencies\": {\n    \"axios\": \"^1.7.2\",\n    \"eslint\": \"^9.11.0\",\n    \"react\": \"^18.3.1\",\n    \"react-confirm-alert\": \"^2.0.0\",\n    \"react-data-table-component\": \"^7.6.2\",\n    \"react-dom\": \"^18.3.1\",\n    \"react-hook-form\": \"^7.53.0\",\n    \"react-icons\": \"^5.2.1\",\n    \"react-markdown\": \"^9.0.1\",\n    \"react-router-dom\": \"^6.24.1\",\n    \"react-select\": \"^5.8.0\",\n    \"react-syntax-highlighter\": \"^15.5.0\",\n    \"react-toastify\": \"^10.0.5\",\n    \"recharts\": \"^2.12.7\",\n    \"styled-components\": \"^6.1.12\",\n    \"uuid\": \"^10.0.0\",\n    \"zustand\": \"^5.0.0-rc.2\"\n  },\n  \"devDependencies\": {\n    \"@testing-library/jest-dom\": \"^6.5.0\",\n    \"@testing-library/react\": \"^16.0.1\",\n    \"@types/react\": \"^18.3.3\",\n    \"@types/react-dom\": \"^18.3.0\",\n    \"@vitejs/plugin-react-swc\": \"^3.5.0\",\n    \"eslint-plugin-react\": \"^7.37.1\",\n    \"jsdom\": \"^25.0.1\",\n    \"vite\": \"^5.3.1\",\n    \"vite-plugin-css-injected-by-js\": \"^3.5.2\",\n    \"vitest\": \"^2.1.3\"\n  }\n}\n"
  },
  {
    "path": "ui/src/App.jsx",
    "content": "import MainRoute from './routes/MainRoute'\n\nfunction App() {\n  return (\n    <>\n      <MainRoute/>\n    </>\n  )\n}\n\nexport default App\n"
  },
  {
    "path": "ui/src/components/Breadcrumbs/Breadcrumbs.jsx",
    "content": ""
  },
  {
    "path": "ui/src/components/Breadcrumbs/Breadcrumbs.module.css",
    "content": ""
  },
  {
    "path": "ui/src/components/Button/Button.jsx",
    "content": "import style from \"./Button.module.css\"\n\nconst Button = ({\n        children, \n        buttonType=\"button\",\n        type = \"solid\",\n        variant = \"primary\", \n        className = \"\",\n        ...props\n    })=>{\n\n\n    return(\n        <button type={buttonType} className={`${style.Button} ${style[`${type}-${variant}`]} ${className}`} {...props}>{children}</button>\n    )\n}\n\nconst BUTTON_TYPE = {\n    SOLID: \"solid\",\n    TRANSPARENT: \"transparent\"\n}\n\n\nconst BUTTON_VARIANT = {\n    PRIMARY: \"primary\",\n    WARNING: \"warning\",\n    DANGER: \"danger\",\n\n    PRIMARY_SECONDARY: \"primary-secondary\",\n    DANGER_SECONDARY: \"danger-secondary\",\n}\n\n\nexport default Button\nexport { BUTTON_TYPE, BUTTON_VARIANT}"
  },
  {
    "path": "ui/src/components/Button/Button.module.css",
    "content": ".Button {\n    gap: 6px;\n    display: inline-flex;\n    padding: 3px 13px;\n    text-align: left;\n    border-radius: 4px;\n    cursor: pointer;\n    border: 0px;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 150%;\n    align-content: center;\n    align-items: center;\n\n}\n\n.Button:disabled {\n    background: #C1C1C1;\n    color: #888787;\n}\n\n\n\n.solid-primary {\n    background: #3893FF;\n    color : #FFF\n}\n\n.solid-primary:not(:disabled):hover {\n    background: #84BCFF;\n    color : #FFF\n}\n\n.solid-secondary {\n    background: #ECF5FF;;\n    color : #3893FF\n}\n\n.solid-secondary:not(:disabled):hover {\n    background: #CDE5FF;;\n    color : #3893FF;\n}\n\n\n\n.solid-danger {\n    background: #FF7F6D;\n    color : #FFF\n}\n\n.solid-danger:not(:disabled):hover {\n    background: #FFB9AF;\n    color : #FFF\n}\n\n.solid-secondary-danger {\n    background: #FFF2F0;;\n    color : #FF7F6D\n}\n\n.solid-secondary-danger:not(:disabled):hover {\n    background: #FFDDD9;\n    color : #FF7F6D;\n}\n\n\n/* transparent */\n\n.transparent-primary {\n    background-color: transparent !important;\n    color: #3893FF;\n}\n\n.transparent-primary:not(:disabled):hover {\n    color: #84BCFF;;\n}\n"
  },
  {
    "path": "ui/src/components/Button/Button.test.jsx",
    "content": "import { describe, it, expect } from 'vitest';\nimport { render, screen } from '@testing-library/react';\nimport Button, { BUTTON_TYPE, BUTTON_VARIANT } from './Button';\n\ndescribe('Button', () => {\n  it('renders with default props', () => {\n    render(<Button>Click me</Button>);\n    const button = screen.getByRole('button', { name: /click me/i });\n    expect(button).toBeInTheDocument();\n    expect(button).toHaveAttribute('type', 'button');\n    expect(button.className).toContain('Button');\n    expect(button.className).toContain('solid-primary');\n  });\n\n  it('renders with custom type and variant', () => {\n    render(<Button type={BUTTON_TYPE.TRANSPARENT} variant={BUTTON_VARIANT.WARNING}>Warning</Button>);\n    const button = screen.getByRole('button', { name: /warning/i });\n    expect(button).toHaveAttribute('type', 'button');\n    expect(button.className).toContain('Button');\n    expect(button.className).toContain('transparent-warning');\n  });\n\n  it('applies custom className', () => {\n    render(<Button className=\"custom-class\">Custom</Button>);\n    const button = screen.getByRole('button', { name: /custom/i });\n    expect(button).toHaveAttribute('type', 'button');\n    expect(button.className).toContain('Button');\n    expect(button.className).toContain('solid-primary');\n    expect(button.className).toContain('custom-class');\n  });\n\n  it('renders as submit button', () => {\n    render(<Button buttonType=\"submit\">Submit</Button>);\n    const button = screen.getByRole('button', { name: /submit/i });\n    expect(button).toHaveAttribute('type', 'submit');\n    expect(button.className).toContain('Button');\n    expect(button.className).toContain('solid-primary');\n  });\n\n  it('renders with danger variant', () => {\n    render(<Button variant={BUTTON_VARIANT.DANGER}>Danger</Button>);\n    const button = screen.getByRole('button', { name: /danger/i });\n    expect(button).toHaveAttribute('type', 'button');\n    expect(button.className).toContain('Button');\n    expect(button.className).toContain('solid-danger');\n  });\n\n  it('passes additional props to button element', () => {\n    render(<Button disabled>Disabled</Button>);\n    const button = screen.getByRole('button', { name: /disabled/i });\n    expect(button).toBeDisabled();\n    expect(button).toHaveAttribute('type', 'button');\n    expect(button.className).toContain('Button');\n    expect(button.className).toContain('solid-primary');\n  });\n});\n"
  },
  {
    "path": "ui/src/components/Chart/AreaChart/AreaChart.jsx",
    "content": "import style from \"../style.module.css\";\nimport { AreaChart as ReAreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts';\n\nfunction AreaChart({ title = \"Area Chart\", data = [], xAxis = \"name\", yAxis = \"value\"},  dataLength = 12) {\n  return (\n    <>\n      <div className={style.ChartContainer}>\n        <span className={style.ChartTitle}>{title}</span>\n        <div className={style.BarChartResponsive}>\n          <ReAreaChart data={data.slice(0, dataLength)}  width={450} height={183}>\n            <CartesianGrid vertical={false} strokeDasharray=\"3 3\" />\n            <XAxis dataKey={xAxis} axisLine={false} tickLine={false} tick={<CustomTick axis=\"x\" />} />\n            <YAxis axisLine={false} tickLine={false} tick={<CustomTick axis=\"y\" />} />\n            <Tooltip />\n            <Area type=\"monotone\" dataKey={yAxis} strokeWidth={3} stroke=\"#3893FF\" fillOpacity={0.1} fill=\"#3893FF\" />\n          </ReAreaChart>\n        </div>\n      </div></>\n  );\n}\n\nconst CustomTick = ({ x, y, payload, axis }) => {\n  const commonProps = {\n    color: \"rgba(28, 28, 28, 0.40\",\n    textAlign: \"center\",\n    opacity: \"40%\",\n    fontFamily: \"Inter\",\n    fontSize: \"11px\",\n    fontStyle: \"normal\",\n    fontWeight: \"400\",\n    lineHeight: \"18px\", /* 180% */\n  };\n\n  return (\n    <text\n      x={axis === 'x' ? x : x - (axis === 'y' ? 5 : 0)} // Adjust horizontal position for Y-axis\n      y={axis === 'x' ? y + 15 : y} // Adjust vertical position for X-axis\n      textAnchor={axis === 'y' ? \"end\" : \"middle\"} // Text alignment for Y and X axis\n      {...commonProps}\n    >\n     <tspan> {payload.value}</tspan>\n    </text>\n  );\n};\n\n\nexport default AreaChart;\n"
  },
  {
    "path": "ui/src/components/Chart/BarChart/BarChart.jsx",
    "content": "\nimport { Bar, BarChart as ReBarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from \"recharts\"\nimport style from \"../style.module.css\"\n\nconst BarChart = ({title =\"Bar Chart\", data = [], xAxis = \"name\", yAxis = \"value\",  dataLength = 12,})=>{\n\n\n    const customBar = (props)=>{\n        const {x, y, height } = props;\n       return (\n            <rect width={\"28\"} height={height} x={x + 10} y={y} fill=\"#74B3FF\" rx=\"4\"></rect>\n        )\n    }\n\n    const customAxisLabel = ({ payload, x, y, width, height })=>{\n        return(\n            <text orientation=\"bottom\" width={width} height={height} stroke=\"none\" x={x} y={y + 40}  textAnchor=\"middle\" style={{fontSize:\"11px\",fontFamily:\"Inter\",color:\"rgba(28, 28, 28, 0.40\",textAlign:\"center\",fontStyle:\"normal\", fontWeight:\"300\", lineHeight:\"18px\",opacity:\"60%\"}} fill=\"#888787\">\n                <tspan x={x} y={y + 12}>{payload.value}</tspan>\n            </text>\n        )\n    }\n\n    return(\n        <>\n            <div className={style.ChartContainer}>\n                <span className={style.ChartTitle}>{title}</span>\n               \n                <div className={style.BarChartResponsive}>\n                <ResponsiveContainer width={500} height={183}>\n                        <ReBarChart  data={data.slice(0, dataLength)} barCategoryGap={0} barGap={5}>\n                            <XAxis dataKey={xAxis} axisLine={false} tickLine={false} tick={customAxisLabel} />\n                            <YAxis axisLine={false} tickLine={false} tick={customAxisLabel} />\n                            <Bar dataKey={yAxis} shape={customBar} />\n                            <Tooltip cursor={false}  />\n                        </ReBarChart>\n                    </ResponsiveContainer>\n                </div>\n                \n            </div>\n        \n        </>\n    )\n\n}\n\n\nexport default BarChart"
  },
  {
    "path": "ui/src/components/Chart/LineChart/LineChart.jsx",
    "content": "\nimport { LineChart as ReLineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';\nimport style from \"../style.module.css\"\n\n\nconst LineChart = ({title =\"Line Chart\", data = [], xAxis = \"name\", yAxis = \"value\", dataLength = 12})=>{\n\n    const customXAxisLabel = ({ payload, x, y, width, height })=>{\n       \n        return(\n            <text orientation=\"bottom\" width={width} height={height} stroke=\"none\" x={x} y={y + 10}  style={{direction:\"rtl\",fontSize:\"11px\",fontFamily:\"Inter\",color:\"rgba(28, 28, 28, 0.40\",textAlign:\"center\",fontStyle:\"normal\", fontWeight:\"300\", lineHeight:\"18px\",opacity:\"60%\"}} fill=\"#888787\" >\n                <tspan x={x+20} y={y+10}>{payload.value}</tspan>\n            </text>\n        )\n    }\n\n    const customYAxisLabel = ({ payload, x, y, width, height })=>{\n        \n        return(\n            <text orientation=\"bottom\" width={width} height={height} stroke=\"none\" x={x} y={y + 10}  style={{direction:\"rtl\", fontSize:\"11px\",fontFamily:\"Inter\",color:\"rgba(28, 28, 28, 0.40\",textAlign:\"center\",fontStyle:\"normal\",fontWeight:\"300\", lineHeight:\"18px\", opacity:\"60%\"}} fill=\"#888787\">\n                <tspan x={x-5} y={y}>{payload.value}</tspan>\n            </text>\n        )\n    }\n\n\n    return(\n        <>\n            <div className={style.ChartContainer}>\n                <span className={style.ChartTitle}>{title}</span>\n                <div className={style.BarChartResponsive}>\n                <ResponsiveContainer  width={450} height={183} >\n                    <ReLineChart  data={data.slice(0, dataLength)}>\n                        <CartesianGrid vertical={false} strokeDasharray=\"3 3\" />\n                        <XAxis dataKey={xAxis}   axisLine={false} tickLine={false} tick={customXAxisLabel} />\n                        <YAxis  axisLine={false} tickLine={false} tick={customYAxisLabel} />\n                        <Tooltip/>\n                        <Line type=\"monotone\" dataKey={yAxis} stroke=\"#3893FF\" strokeWidth={3} />\n                    </ReLineChart>\n                </ResponsiveContainer>\n                </div>\n            </div>\n        \n        </>\n    )\n\n}\n\n\nexport default LineChart"
  },
  {
    "path": "ui/src/components/Chart/PieChart/PieChart.jsx",
    "content": "import { PieChart as RePieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend } from 'recharts';\nimport style from '../style.module.css';\n\n\nconst COLORS = ['#3893FF', '#84BCFF', '#CDE5FF', '#FF8042'];\n\nconst CustomLegend = (props) => {\n    const { payload, label } = props;\n    return (\n        <div>\n            {payload.map((entry, index) => (\n                <div key={`item-${index}`} className={style.PieLegend}>\n                    <div>\n                        <svg width={20} height={20} style={{ borderRadius:\"3px\", display: 'inline-block', marginRight: '5px' }}>\n                            <rect width={20} height={20} fill={entry.color} />\n                        </svg>\n                    </div>\n                    <div>\n                        {entry.payload[label]}\n                    </div>\n                </div>\n            ))}\n        </div>\n    );\n};\n\n\nconst PieChart = ({ title = \"Pie Chart\", data = [] , dataKey= \"value\", labelKey=\"label\", dataLength = 12 }) => {\n  return (\n    <>\n         <div className={style.ChartContainer}>\n        <span className={style.ChartTitle}>{title}</span>\n          <div className={style.BarChartResponsive}>\n            <ResponsiveContainer width={450} height={183}>\n              <RePieChart>\n                <Pie\n                  data={data?.slice(0, dataLength)}\n                  labelLine={false}\n                  innerRadius={0}\n                  dataKey={dataKey}\n                  stroke=\"\"\n                >\n                  {data.map((entry, index) => (\n                    <Cell key={entry[labelKey]} fill={COLORS[index % COLORS.length]} />\n                  ))}\n                </Pie>\n                <Tooltip />\n                <Legend content={<CustomLegend label={labelKey} />} layout=\"vertical\" align=\"right\" verticalAlign=\"middle\"  wrapperStyle={{top: \"0px\", height: \"200px\", overflow: \"auto\"}} />\n              </RePieChart>\n            </ResponsiveContainer>  \n          </div>\n        </div>\n    </>\n  );\n};\n\nexport default PieChart;\n"
  },
  {
    "path": "ui/src/components/Chart/Table/Table.jsx",
    "content": "\n\nimport style from \"../style.module.css\"\n\nconst Table = ({data = [], dataLength = 10})=>{\n\n\n    let tableHeader = [];\n\n    const getTableHeader = ()=>{\n        if(data.length > 0){\n            let tempData = data[0];\n            let keys = Object.keys(tempData).map(item=>item.replaceAll(\"_\", \" \"));\n            tableHeader = keys\n        }\n    }\n   \n    getTableHeader()\n\n    return(\n        <>\n            <div className={style.ChartTableContainer}>\n                <table cellSpacing={0} className={style.ChatTable}>\n                    <thead>\n                        <tr>\n                            {tableHeader.map((item, index)=><th key={index}>{item}</th>)}\n                        </tr>\n                    </thead>\n                    <tbody>\n                        {data?.slice(0, dataLength)?.map((item, dIndex)=>{\n                            return(\n                                <tr key={dIndex}>\n                                    { Object.values((item)).map(value=><td>{value}</td>) }\n                                </tr>\n                            )\n                        })}\n                    </tbody>\n                </table>\n            </div>\n        </>\n    )\n\n}\n\n\nexport default Table"
  },
  {
    "path": "ui/src/components/Chart/style.module.css",
    "content": ".ChartContainer{\n    padding: 24px 24px;\n    border-radius: 10px;\n    background: #F5FAFF;\n    width: fit-content;\n    \n}\n\n.ChartTitle {\n    display: block;\n    color: #1C1C1C;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 20px; \n    margin-bottom: 20px;\n}\n\n.BarChartResponsive {\n    margin-left: -25px;\n}\n\n.PieChartContainer{\n    padding: 24px;\n        width: fit-content;\n        height: auto;\n        flex-shrink: 0;\n        border-radius: 10px;\n        background: #F5FAFF;\n}\n.PieChartTitle{\n    color: #1C1C1C;\n    font-feature-settings: 'ss01' on, 'cv01' on, 'cv11' on;\n    font-family: Inter;\n    font-size: 18px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px; /* 142.857% */\n}\n\n.PieLegend{\n    display: flex;\n    color: #888787;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px; /* 166.667% */\n    margin-right: 100px;\n    margin-bottom: 10px;\n}\n\n\n/* table style */\n\n.ChartTableContainer {\n    width: 500px;\n    overflow: scroll;\n}\n\n\n.ChatTable tr th, .ChatTable tr th td{\n    padding: 5.5px 12px;\n    font-family: Inter;\n    font-size: 11px;\n    font-style: normal;\n    font-weight: 600;\n}\n\n.ChatTable tr th{\n    background: #84BCFF;\n    color: #FFFFFF;\n    text-transform: uppercase;\n}\n\n.ChatTable tr th:nth-child(1) {\n    border-radius: 10px 0px 0px 0px;\n}\n.ChatTable, tr th:last-child {\n    border-radius: 0px 10px 0px 0px;\n}\n\n.ChatTable tr td {\n    background-color: #F5FAFF;\n    color: #323232;\n    padding-left: 10px;\n    border-bottom: 1px #EFEFEF solid;\n    padding: 9px 10px;\n}\n\n\n.ChatTable tr:last-child td {\n    border-bottom: 0px;\n}\n"
  },
  {
    "path": "ui/src/components/ChatBox/ChatBox.jsx",
    "content": "import { forwardRef, useEffect, useRef } from \"react\"\nimport style from \"./ChatBox.module.css\"\nimport Message from \"./Message\"\n\nimport Loader from \"./Loader\"\n\nimport ChatHistorySideBar from \"./ChatHistorySideBar\"\n\n\nconst ChatBox = forwardRef(({messageBoxRef = null, handleNavigateChatContext=()=>{}, onCreateNewChat=()=>{}, chatHistory=[], isLoading = false, onFeedBackSubmit=()=>{}, conversations = [], onKeyDown = ()=>{}, onKeyUp = ()=>{}, onSendClick = ()=>{}, onLike = ()=>{} , onDisLike = ()=>{} }, ref)=>{\n\n    const chatListRef = useRef(null)\n   \n    const handleOnLikeClick = (e, feedbackStatus, feedbackMessage, message)=>{\n        onLike(e, feedbackStatus, feedbackMessage, message)\n    } \n\n    const handleOnDisLikeClick = (e,message)=>{\n        onDisLike(message)\n    }\n\n\n    const toggleContainer = (e, setIsHidden) => {\n        setIsHidden(prev => !prev); \n      };\n\n    useEffect(()=>{\n        document.querySelector(\"#messageBody\").scrollIntoView({ behavior: \"smooth\", block: \"end\", inline: \"nearest\" });\n    },[conversations])\n\n    return(\n        <>  \n            <div className={style.ChatBoxContainer}>\n                <div className={style.ChatMessagesContainer}>\n                    <div className={style.ChatMessageContainer}>\n                        <div id=\"messageBody\" ref={chatListRef} className={style.chatList}>\n                            {\n                                conversations.map((message, index) => {\n                                    return <Message onLike={handleOnLikeClick} onDisLike={handleOnDisLikeClick} onFeedbackSubmit={onFeedBackSubmit} key={index} message={message} />\n\n                                })\n                            }\n                            {isLoading && <Loader />}\n                        </div>\n                    </div>\n\n                    <div>\n                        <div className={style.ChatBoxTextContainer}>\n                            <div ref={messageBoxRef} className={style.ChatBoxTextBox} contentEditable=\"plaintext-only\" onKeyDown={onKeyDown} onKeyUp={onKeyUp}>\n                            </div>\n                            <div>\n                                <div className={style.ChatBoxSendIcon} onClick={onSendClick}></div>\n                            </div>\n                        </div>\n                        <div>\n                            <p className={style.ChatBottomMessage}>RAG Builder may display inaccurate info, including about people, so double-check its responses.</p>\n                        </div>\n                    </div>\n                </div>\n                <ChatHistorySideBar handleNavigateChatContext={handleNavigateChatContext} onCreateNewChat={onCreateNewChat} chatHistory={chatHistory} onClick={(e, setIsHidden) => toggleContainer(e, setIsHidden)}/>     \n          </div>\n        </>\n    )\n})\n\nexport default ChatBox"
  },
  {
    "path": "ui/src/components/ChatBox/ChatBox.module.css",
    "content": "\n\n/* Chatbox.jsx */\n\n.ChatBoxContainer {\n    display: flex;\n    height: 100%;\n    overflow: hidden;\n    /* background-color: red; */\n}\n.ChatMessagesContainer{\n    flex-grow: 1;\n    padding-left: 39px;\n    padding-right: 39px;\n    display: flex;\n    flex-direction: column;\n    height: 100%;\n}\n\n.ChatMessageContainer {\n    flex-grow: 1;\n    /* background-color: blue; */\n    overflow: scroll;\n}\n\n.ChatMessageContainer p {\n    margin: 0px;\n}\n\n\n.ChatMessageContainer::-webkit-scrollbar {\n    display: none;\n}\n    \n.ChatMessageContainer {\n    -ms-overflow-style: none;  \n    scrollbar-width: none;  \n}\n\n.ChatBoxTextContainer {\n    display: flex;\n    padding: 8px 8px;\n    align-items: center;\n    gap: 16px;\n    flex-shrink: 0;\n    border-radius: 180px;\n    border: 1px solid #E0E0E0;\n    background: #FFF;\n    outline: none;\n    margin-bottom: 22px;\n}\n\n\n.ChatBoxTextBox {\n    flex-grow: 1;\n    padding: 0px 10px;\n    max-height: 54px;\n    overflow: scroll;\n    overflow: hidden;\n    color: #888787;\n    text-overflow: ellipsis;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 24px;\n}\n\n.ChatBoxTextBox::-webkit-scrollbar {\n    display: none;\n}\n      \n.ChatBoxTextBox {\n    -ms-overflow-style: none; \n    scrollbar-width: none;\n}\n\n.ChatBoxTextBox:focus{\n    outline: none;\n}\n\n.ChatBoxTextContainer:has(.ChatBoxTextBox:hover) {\n    border-color: #3893FF;\n}\n\n.ChatBoxSendIcon {\n    background: url(/src/components/ChatBox/assets/send-icon.svg);\n    width: 42px;\n    height: 42px;\n    background-repeat: no-repeat;\n    background-color: #F9F9F9;\n    border-radius: 180px;\n    background-position: 12px 10px;\n    cursor: pointer;\n}\n\n   \n.ChatBoxTextBox:hover  + div .ChatBoxSendIcon{\n    background-color: #ECF5FF !important;\n    background: url(/src/components/ChatBox/assets/send-icon-active.svg);\n    background-repeat: no-repeat;\n    background-position: 12px 10px;\n}\n\n\n.ChatBottomMessage {\n    text-align:center;\n    margin-bottom: 29px; \n}\n\n\n/* Message.jsx */\n .MessageContainer {\n    border-radius: 10px;\n    padding: 12px 16px; \n    margin: 15px 0px;\n    color: #151414;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 150%;\n}\n\n.UserMessageContainer {\n    display: flex;\n    justify-content: end;\n    gap: 12px;\n}\n\n.BotMessageContainer {\n    display: flex;\n    justify-content: start;\n    gap: 8px;\n}\n\n.UserMessage {\n    border-radius: 10px;\n    background: #F1F1F1;;\n    color: #323232;\n}\n\n.BotMessage {\n    border-radius: 10px;\n}\n\n.BotMessage p {\n    color: #323232;\n    font-size: 14px;\n}\n\n.MessageAvatar {\n    margin-top: 20px;\n}\n\n\n/* loader */\n\n.Loader {\n    text-align: center;   \n    width: fit-content; \n    margin-left: 10px;\n    padding-bottom: 10px;\n\n}\n.Loader span {\n    display: inline-block;\n    vertical-align: middle;\n    width: 10px;\n    height: 10px;\n    background: grey;\n    border-radius: 50px;\n    -webkit-animation: loader 0.5s infinite alternate;\n    -moz-animation: loader 0.5s infinite alternate;\n    margin-right: 4px;\n}\n.Loader span:nth-of-type(2) {\n    -webkit-animation-delay: 0.2s;\n    -moz-animation-delay: 0.2s;\n}\n.Loader span:nth-of-type(3) {\n    -webkit-animation-delay: 0.3s;\n    -moz-animation-delay: 0.3s;\n}\n@-webkit-keyframes loader {\n  0% {\n  \n    height: 10px;\n    opacity: 0.9;\n    -webkit-transform: translateY(0);\n  }\n  100% {\n\n    opacity: 0.3;\n    -webkit-transform: translateY(-11px);\n  }\n}\n@-moz-keyframes loader {\n  0% {\n    width: 10px;\n    height: 10px;\n    opacity: 0.9;\n    -moz-transform: translateY(0);\n  }\n  100% {\n    width: 24px;\n    height: 24px;\n    opacity: 0.3;\n    -moz-transform: translateY(-11px);\n  }\n}\n\n/*  Time CSS  */\n\n\n.MessageExtraInfo{\n    margin-top: 3px;\n    margin-left: 0px;\n\n}\n.Timelabel{\n    font-family: Inter;\n    font-size: 12px;\n    font-weight: 400;\n    line-height: 18px;\n    text-align: left;\n    color: #C8C8C8;\n    width: 87px;\n    height: 18px;\n    gap: 0px;\n}\n\n.Timecontainer{\n    display: flex;\n    justify-items: center;\n    align-items: center;\n}\n.LikeIcon{\n    display: flex;\n    width: Fixed (18px)px;\n    height: auto;\n    padding: 3px 13px 3px 13px;\n    gap: 6px;\n    border-radius: 4px 0px 0px 0px;\n    opacity: 0px;    \n}\n\n.LikeButton {\n    outline: none;\n    display: flex;\n    width: auto;\n    justify-content: center;\n    align-items: center;\n    gap: 6px;\n    padding: 0 3px; \n    border-radius: 4px;\n    background: #F0F0F0;\n    border: none;\n    cursor: pointer;\n    position: relative; \n}\n\n.LikeButton.Activeliked {\n    background: #ECF5FF;\n}\n\n.LikeButton:hover {\n    background: #ECF5FF;\n}\n\n.LikeButton::before {\n    content: url('./assets/like-icon.svg');\n    transition: content 0.3s; \n}\n\n.LikeButton.Activeliked::before {\n    content: url('./assets/like-hover.svg'); \n}\n\n.LikeButton:hover::before {\n    content: url('./assets/like-hover.svg');\n}\n\n\n.DislikeButton {\n    outline: none;\n    display: flex;\n    width: auto;\n    justify-content: center;\n    align-items: center;\n    gap: 6px;\n    padding-left: 3px;\n    padding-right: 3px;\n    border-radius: 4px;\n    background: #F0F0F0;\n    border: none;\n    cursor: pointer;\n    position: relative; \n}\n\n.DislikeButton.ActiveDisliked{\n    background: #ECF5FF;\n}\n\n.DislikeButton:hover{\n    background: #ECF5FF;\n}\n    \n.DislikeButton::before {\n    content: url('./assets/dislke-icon.svg');\n}\n\n.DislikeButton:hover::before {\n    content: url('./assets/dislike-hover.svg');\n}\n\n.DislikeButton.ActiveDisliked::before {\n    content: url('./assets/dislike-hover.svg');\n}\n\n\n\n/*  Feedback popup  */\n\n\n.FeedbackCommet{\n    /* position: absolute; */\n    display: block;\n    width: 401px;\n    height: auto;\n    padding: 10px;\n    flex-direction: column;\n    align-items: flex-start;\n    gap: 10px;\n    flex-shrink: 0;\n    border-radius: var(--4, 4px);\n    border: 1px solid #F0F0F0;\n    background: var(--white-100, #FFF);\n    margin-top: 20px;\n}\n\n.FeedbackCommetShow {\n    display: block;\n}\n\n.FeedbackCommet h2{\n    color: #323232;\n    font-family: Lato;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: normal;    font-family: Lato;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: normal;\n    margin-top: 5px;\n}\n\n.TitleHead{\n    display: flex;\n    width: 100%;\n    justify-content: space-between;\n}\n\n.imageBgRemove{\n    backface-visibility: hidden;\n    \n}\n\n.CloseIconBtn{\n    background: none;\n    outline: none;\n    border: none;\n    outline: navajowhite;\n    cursor: pointer;\n}\n.SuggestedComment{\n    display: flex;\n    gap: 8px;\n}\n\n.SuggestedComment > span{\n    /* display: flex; */\n    width: auto;\n    height: 17px;\n    padding: var(--4, 4px) var(--8, 8px);\n    justify-content: center;\n    align-items: center;\n    gap: var(--8, 8px);\n    border-radius: var(--4, 4px);\n    border: 0px solid #64A25E;\n    background: #ECF5FF;\n    color: #74B3FF;\n    font-family: Inter;\n    font-size: 9px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 20px; /* 222.222% */\n    cursor: pointer;\n}\n\n.FeedbackTextarea{\n    margin-top: 11px;\n    margin-bottom: 6px;\n    outline: none;\n    resize: none;\n}\n\n.FeedbackButton {\n    display: inline-flex;\n    padding: 3px 13px;\n    align-items: center;\n    gap: 6px;\n    display: inline-flex;\n    padding: 3px 13px;\n    align-items: center;\n    gap: 6px;\n    border-radius: var(--4, 4px);\n    background: #3893FF;\n    color: var(--white-100, #FFF);\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 150%;\n    /* 18px */\n    border: none;\n    outline: none;\n}\n\n\n/* =======CHAT HISTORY======= */\n\n.ButtonContainer{\n    width:auto;\n    cursor: pointer;\n    display: flex;\n    padding: 20px 13px;\n    align-items: center;\n    gap: 6px;\n    flex-shrink: 0;\n    border-radius: var(--12, 12px) 0px 0px var(--12, 12px);\n    background: #3893FF;\n}\n\n.ButtonContainer:hover{\n    background: #84BCFF;\n    color: var(--white-100, #FFF);\n}\n\n.BotMessageContainer:focus{\n    background: #84BCFF;\n}\n\n.ChatHistoryText{\n    display: none;\n    color: #FFF;\n    /* Small text */\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 150%; /* 24px */\n}\n\n.ButtonContainer:hover .ChatHistoryText{\n    display: flex;\n}\n\n.ButtonContainer:hover .ChatHistoryIcon {\n    animation: rotateIcon 1s ease-in-out forwards;\n}\n\n@keyframes rotateIcon {\n    0% {\n        transform: rotate(0deg);\n    }\n    50% {\n        transform: rotate(20deg);\n    }\n    100% {\n        transform: rotate(0deg);\n    }\n}\n\n\n.ChatHistoryIcon{\n    margin-top: 5px;\n}\n\n\n/* ===========CHAT HISTORY SIDEBAR=========== */\n.chatHistoryContainer {\n    width: 356px; /* Start with the sidebar visible */\n    padding-right: 16px; /* Adjust padding as needed */\n    position: relative;\n    box-sizing: border-box;\n    background-color: #FFFFFF;\n    border-left: 1px solid #F0F0F0;\n}\n\n.toggleContainer {\n    animation: toggleDiv 0.8s forwards; \n}\n\n@keyframes toggleDiv {\n    from {\n        min-width: 356px;\n        padding-right: 16px;\n    }\n    to {\n        width: 0;\n        padding-right: 0;\n    }\n}\n\n\n\n\n.ChatNavBar {\n    padding-right: 20px;\n    padding-left: 20px;\n    padding-top: 14px;\n    padding-bottom: 14px;\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    border-bottom: 1px solid #F0F0F0;\n}\n\n.ChatNavBar h3 {\n    color: #000;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 150%;\n    /* 24px */\n}\n\n.ChatNavBar button:last-child {\n    cursor: pointer;\n    border-radius: var(--4, 4px);\n    background: #ECF5FF;\n    padding: 3px 13px;\n    display: inline-flex;\n    align-items: center;\n    gap: 6px;\n    outline: none;\n    border: none;\n    border-radius: var(--4, 4px);\n    background: #ECF5FF;\n\n    color: #3893FF;\n\n    /* Small text */\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 150%;\n    /* 24px */\n}\n\n.ChatNavBar button:last-child:hover {\n    background-color: #CDE5FF;\n    color: #3893FF;\n}\n\n.ChatNavBar button:last-child img {\n    margin-top: 7px;\n}\n\n.ChatBarStyle {\n    background-color: #FFFFFF;\n\n}\n\n.ChatHistoryContent {\n    min-width: 93%;\n    height: calc(100vh - 150px);\n    overflow-y: scroll;\n    padding: 27px 20px 20px 20px;\n}\n\n\n\n\n\n.ChatHistoryHeading {\n    color: #5B5B5B;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 150%;\n    /* 24px */\n    margin-bottom: 18px;\n}\n\n.RecentChats{\n    background: #FFF;\n    display: inline-flex;\n    width: 100%;\n    gap: 10px;\n}\n\n.RecentMessage {\n    color: #858585;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 150%;\n}\n\n.HistoryArrowButton{\n    width: 20px;\n    padding-top: 3px;\n    padding-left: 2px;\n    border-radius: 40px;\n    text-align: center;\n    height: 20px;\n    cursor: pointer;\n    border: 1px #84BCFF;\n\n    background: #84BCFF;\n    position: absolute;\n    left: -12px;\n}\n\n.HistoryArrowButton:hover{\n    border: 1px #3893FF;\n    background: #3893FF;\n}\n\n.HistoryArrowButton img{\n    width: 16px;\n}\n\n\n\n\n\n/* Chat Summary */\n\n.SummaryContainer{\n    display: flex;\n    flex-direction: column ;\n    \n    width: 401px;\n    height: 20px;\n    padding: 12px 13px;\n    margin-top: 20px;\n\n    border-radius: 8px;\n    background: #F1F1F1;\n    margin-bottom: 20px;\n    overflow: hidden;\n    \n}\n\n.SummaryContainer.SummaryContainerOpen {\n    height: auto;\n}\n\n.SummartyHeader {\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    gap: 13px;\n    cursor: pointer;\n}\n\n.SummaryToggleButton {\n    border-radius: 4px;\n    border: 0px;\n    background: #F9F9F9;\n    width: 18px;\n    height: 18px;\n    padding: 0px;\n    cursor: pointer;  \n    padding-top: 3px;  \n}\n\n\n\n.SummaryToggleIconOpen {\n    content: url('./assets/summary-up.svg');\n}\n\n.SummaryToggleIconClose {\n    content: url('./assets/summary-down.svg');\n}\n\n\n.SummaryHeaderTitle {\n    color: #888787;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    margin: 0px;\n}\n\n\n.ChatSummayContainer {\n    display: flex;\n    flex-direction: column;\n    margin: 20px 5px;\n    margin-top: 25px;\n    cursor: pointer;\n    margin-bottom: 0px;\n}\n\n.ChatSQLSummary {\n    color: #9EA1A4;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n}\n\n\n\n.QueryTitle {\n    color: #888787;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 150%;\n    margin-top: 25px;\n    margin-bottom: 12px;\n}\n\n.QueryTitle::before,\n.QueryTitle::after {\n    display: inline-block;\n    content: \"\";\n    border-top: 1px solid #F9F9F9;;\n    width: 38%;\n    transform: translateY(-6px);\n}\n\n.QueryTitle::before {\n    margin-right:  10px;\n}\n\n.QueryTitle::after {\n    margin-left:  10px;\n}\n\n.QueryInnerTitle{\n    display: inline-flex;\n    align-items: center;\n    gap: 7px;\n}\n\n.SQLQueryOpen {\n    margin-bottom: 12px;\n}\n\n.SQLQueryClose {\n    display: none;\n}\n\n\n\n/* Chat Summary */\n\n\n/* Error Message Style */\n.ErrorContainer {\n    width: 401px;\n    border-radius: 4px;\n    border: 1px solid #F0F0F0;\n    background: #FFF;\n    padding: 10px;\n}\n\n.ErrorHeaderContainer {\n    display: flex;\n}\n\n.ErrorHeadingContainer{\n    flex-grow: 1;\n}\n\n.ErrorHeading {\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: normal;\n    margin: 0px;\n    margin-bottom: 10px;\n}\n\n.ErrorCloseIcon {\n    cursor: pointer;\n}\n\n.ErrorDescription {\n    color: #858585;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: normal;\n    margin-bottom: 23px !important;\n}\n\n.ErrorButtonAnchor {\n    text-decoration: none;\n}\n\n.ErrorActionButton {\n    border-radius: 4px;\n    background: #ECF5FF;\n    border: 0px;\n    padding: 6px 13px;\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    cursor: pointer;\n}\n\n.ErrorExpandButton {\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 140%;\n    text-decoration-line: underline;\n    cursor: pointer;\n}\n\n.MessageContainer p:has(+ .ErrorExpandButton){\n    display: inline-block;\n    color: #FF7F6D;\n}\n\n.MessageContainer:has(> .ErrorExpandButton){\n    margin-top: 10px;\n}\n\n\n/* Error Message Style */"
  },
  {
    "path": "ui/src/components/ChatBox/ChatDropdownMenu/ChatDropdownMenu.jsx",
    "content": "import {useEffect, useState } from 'react';\nimport style from './ChatDropdownMenu.module.css';\nimport arrowDown from '../assets/arrow-down.svg';\nimport arrowUp from '../assets/arrow-up.svg';\n\nexport default function ChatDropdownMenu({ handleNavigateChatContext = () => {}, data = [], showDropdownArrow = true }) {\n    const [openDropdown, setOpenDropdown] = useState([]);\n    const [showUpto, setShowUpto] = useState(4); // Start with 4 items visible\n    const [isExpanded, setIsExpanded] = useState(false); // Track expansion\n\n    const toggleDropdown = (index) => {\n        if (index === 0) return; // Prevent toggling for index 0\n\n        setOpenDropdown((prevState) =>\n            prevState.includes(index) ? prevState.filter((i) => i !== index) : [...prevState, index]\n        );\n    };\n\n    useEffect(() => {\n        // Open all dropdowns except for index 0 on initial load\n        const allIndexes = data.map((_, index) => index).filter((index) => index !== 0);\n        setOpenDropdown([0, ...allIndexes]);\n    }, [data]);\n\n    if (data.length > 0) {\n        data[0].title = 'Recent Chat';\n    }\n\n    const toggleVisibility = (index, chatQuery = []) => {\n        if (index === 0) {\n            if (isExpanded) {\n                setShowUpto(4); \n            } else {\n                setShowUpto(chatQuery.length); // Show all items on \"See More\"\n            }\n            setIsExpanded(!isExpanded); // Toggle expansion state\n        }\n    };\n\n    return (\n        <div className={style.ChatDropDown}>\n            {data.map((item, index) => (\n                <div key={index}>\n                    <div\n                        className={style.ChatHistoryHeadWithArrow}\n                        onClick={() => toggleDropdown(index)}\n                    >\n                        <h3>{item.title}</h3>\n                        {index !== 0 && showDropdownArrow && (\n                            <div>\n                                <img\n                                    src={openDropdown.includes(index) ? arrowUp : arrowDown}\n                                    alt=\"arrowIcon\"\n                                />\n                            </div>\n                        )}\n                    </div>\n                    <div\n                        className={`${\n                            openDropdown.includes(index) ? style.ActiveDropDown : style.InActiveDropDown\n                        }`}\n                    >\n                        <ul>\n                            {item.chatQuery.slice(0, showUpto).map((chat, chatIndex) => (\n                                <span key={chatIndex} className={style.ListOptions}>\n                                    <li onClick={(e) => handleNavigateChatContext(e, chat.contextId, chat.configId)}>\n                                        {chat?.message}\n                                    </li>\n                                </span>\n                            ))}\n                        </ul>\n                        {Array.isArray(item.chatQuery) && item.chatQuery.length > 4 && index === 0 && (\n                            <button\n                                className={style.SeeMoreDropDown}\n                                onClick={() => toggleVisibility(index, item.chatQuery)}\n                            >\n                                <span style={{ paddingTop: '6px' }}>\n                                    <img\n                                        src={isExpanded ? arrowUp : arrowDown}\n                                        alt=\"arrowIcon\"\n                                    />\n                                </span>\n                                <span>{isExpanded ? 'Show Less' : 'See More'}</span>\n                            </button>\n                        )}\n                    </div>\n                </div>\n            ))}\n        </div>\n    );\n}\n"
  },
  {
    "path": "ui/src/components/ChatBox/ChatDropdownMenu/ChatDropdownMenu.module.css",
    "content": ".ChatDropDown {\n    display: flex;\n    flex-direction: column;\n\n}\n\n.ChatDropDown h3 {\n    flex-grow: 1;\n    margin: 0;\n    color: #5B5B5B;\n    font-family: Inter;\n    font-size: 16px;\n    margin-bottom: 18px;\n    font-style: normal;\n    font-weight: 600;\n    line-height: 150%;\n    /* 24px */\n}\n\n\n\n\n.ChatDropDown li {\n    cursor: pointer;\n    display: block;\n    color: #858585;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 150%;\n    position: relative;\n    padding-left: 36px;\n    padding-right: 6px;\n    padding-top: 9px;\n    border-radius: 4px;\n    padding-bottom: 9px;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    margin-bottom: 9px;\n}\n\n\n\n.ChatDropDown li:hover{\n    border-radius: 4px;\n    background: #F0F0F0;\n}\n\n.ChatDropDown li:focus{\n    background: #D8D8D8;\n}\n\n.ChatDropDown li div {\n    margin: 0;\n    width: 260px;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n}\n\n.ChatDropDown ul {\n    padding: 0;\n    margin-top: 0;\n    margin-left: 10px;\n    width: 300px;\n}\n\n.ListOptions{\n    width: 100%;\n}\n\n.ChatDropDown li::before {\n    content: \"\";\n    position: absolute;\n    left: 6px;\n    top: 56%;\n    width: 20px;\n    height: 20px;\n    /* Adjust based on the size of the image */\n    background-image: url(../assets/message-history.svg);\n    background-size: contain;\n    background-repeat: no-repeat;\n    background-position: center;\n    transform: translateY(-50%);\n    /* Centers the image vertically */\n}\n\n.ChatHistoryHeadWithArrow {\n    cursor: pointer;\n    display: flex;\n    gap: 8px;\n}\n\n.ChatHistoryHeadWithArrow img {\n    padding-top: 2px;\n}\n\n.ActiveDropDown {\n    height: auto;\n    display: block;\n    animation: slideUp 0.5s ease-in-out forwards;\n    overflow: hidden;\n}\n\n\n.InActiveDropDown {\n    overflow: hidden;\n    animation: slideDown 0.5s ease-in-out forwards;\n    /* Adjust duration and easing as needed */\n}\n\n.SeeMoreDropDown{\n    display: flex;\n    min-width: 295px;\n    padding: var(--12, 12px) 6px;\n    align-items: center;\n    gap: 10px;\n    border-radius: var(--4, 4px);\n    border: 1px solid var(--white-100, #FFF);\n    background: #ffffff;\n    color: #858585;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    width: 295px;\n    height: 30px;\n    line-height: 150%;\n    cursor: pointer;\n    margin-bottom: 18px; /* 18px */\n}\n\n.SeeMoreDropDown:hover{\n    background: #F0F0F0;\n}\n\n@keyframes slideDown {\n    0% {\n        min-height:fit-content;\n        opacity: 1;\n    }\n\n    100% {\n        max-height: 0;\n        opacity: 0;\n    }\n}\n\n@keyframes slideUp {\n    0% {\n        min-height: 0;\n        opacity: 0;\n    }\n    100% {\n        min-height:fit-content; \n        opacity: 1;\n    }\n}\n"
  },
  {
    "path": "ui/src/components/ChatBox/ChatHistoryButton.jsx",
    "content": "import style from './ChatBox.module.css'\n\nfunction ChatHistoryButton({icon,text, onClick = ()=>{}}) {\n  return (\n    <div style={{position:\"absolute\",right:\"0\",top:\"50%\",bottom:\"50%\"}} onClick={onClick} className={style.ButtonContainer}>\n       <div className={style.ChatHistoryIcon}><img src={icon}/></div>\n       <div className={style.ChatHistoryText}>{text}</div>\n    </div>\n  )\n}\n\nexport default ChatHistoryButton"
  },
  {
    "path": "ui/src/components/ChatBox/ChatHistorySideBar.jsx",
    "content": "import { useRef, useState } from 'react'\nimport style from \"./ChatBox.module.css\"\nimport plusIcon from \"./assets/plus-image.svg\"\nimport arrowRight from \"./assets/arrow-right.svg\"\nimport ChatHistoryButton from \"src/components/ChatBox/ChatHistoryButton\"\nimport Clock from \"./assets/time-lap.svg\"\nimport ChatDropdownMenu from './ChatDropdownMenu/ChatDropdownMenu'\n\n\nfunction ChatHistorySideBar({handleNavigateChatContext=()=>{}, onCreateNewChat=()=>{}, onClick=()=> {}, chatHistory }) {\n\n  const toggleHistoryRef = useRef(null)\n  const [isHidden, setIsHidden] = useState(false);\n\n  const showHideSideHistory = (e) => {\n    onClick(e, setIsHidden)\n  }\n\n  const formatDate = (date) => {\n      const options = { year: 'numeric', month: 'long' };\n      return new Date(date).toLocaleDateString('en-US', options);\n  };\n\n\nconst formattedData = chatHistory.reduce((acc, chat) => {\n  \n    const { chatContextId, chatQuery, date, chatConfigurationId } = chat;\n\n    // Format the date to \"MONTH YEAR\"\n    const formattedDate = formatDate(date);\n\n    // Initialize the entry if it doesn't exist\n    if (!acc[formattedDate]) {\n        acc[formattedDate] = {\n            title: formattedDate,\n            chatQuery: []\n        };\n    }\n\n    // Add the message to the appropriate date group\n    acc[formattedDate].chatQuery.push({\n        contextId: chatContextId,\n        configId: chatConfigurationId,\n        message: chatQuery\n    });\n\n    return acc;\n}, {});\n\nconst resultArray = Object.values(formattedData);\n\n\n  return (\n    <>\n    <div className={isHidden ? `${style.toggleContainer}` : `${style.chatHistoryContainer}`} ref={toggleHistoryRef}>\n      <div className={style.ChatBarStyle}>\n        <div className={style.ChatNavBar}>\n          {isHidden ? <></> : (<div className={style.HistoryArrowButton} onClick={(e) => {showHideSideHistory(e) }}>\n            <img src={arrowRight} />\n          </div>)}\n\n          <h3>Chat History</h3>\n          <button onClick={(e)=>{onCreateNewChat(e)}}>NewChat<span><img src={plusIcon} /></span></button>\n        </div>\n        <div className={style.ChatHistoryContent}>\n          <div className={style.RecentChat}>\n            <div className={style.RecentChats}>\n            <ChatDropdownMenu handleNavigateChatContext={handleNavigateChatContext} data={resultArray}/>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n      {isHidden ? (<ChatHistoryButton onClick={() => { setIsHidden(!isHidden) }} icon={Clock} text={\"History\"} />) : null}\n    </>\n\n  )\n}\n\nexport default ChatHistorySideBar"
  },
  {
    "path": "ui/src/components/ChatBox/ErrorMessage.jsx",
    "content": "\nimport { SLACK_URL } from \"src/config/const\"\nimport slackIcon from \"./assets/slack-icon.svg\"\nimport closeIcon from \"./assets/error-close.svg\"\nimport style from './ChatBox.module.css'\n\nconst ErrorMessage = ({ error = \"\", onClose = ()=>{}})=>{\n\n    return(\n        <div className={style.ErrorContainer}>\n            <div className={style.ErrorHeaderContainer}>\n                <div className={style.ErrorHeadingContainer}>\n                    <h1 className={style.ErrorHeading}>An unexpected error has occurred</h1>\n                </div>\n                <div>\n                    <img src={closeIcon} className={style.ErrorCloseIcon} onClick={onClose} />\n                </div>\n            </div>\n           \n            <p className={style.ErrorDescription}>{error}</p>\n            <a href={SLACK_URL} target=\"_blank\" className={style.ErrorButtonAnchor}>\n                <button className={style.ErrorActionButton}>Contact Us <img src={slackIcon}/></button>\n            </a>\n        </div>\n    )\n}\n\nexport default ErrorMessage"
  },
  {
    "path": "ui/src/components/ChatBox/Feedback.jsx",
    "content": "import { useState } from 'react'\nimport close from './assets/close-modal-icon.svg'\nimport style from './ChatBox.module.css'\n\nfunction Feedback({ onSubmit=()=>{}, message={}, onFeedBackClose = ()=>{}}) {\n\n  const [inputValue,setInputValue] = useState()\n  const feedBackPredefinedComment = [\"Incorrect\", \"Confusing\", \"Incomplete\", \"Unclear\"]\n  \n  const handleSuggestClick = (e, item) => {\n    setInputValue(item)\n  }\n\n\n  return (\n    <>\n        <div className={`${style.FeedbackCommet}`} >\n          <div className={style.TitleHead}>\n            <h2>Why did you choose this rating?</h2>\n            <button className={`${style.CloseIconBtn}`} onClick={onFeedBackClose}>\n              <img src={close} alt='closemodal' width={23} height={23} className={style.ImageBGRemove} />\n            </button>\n          </div>\n          <div className={style.SuggestedComment}>\n            {feedBackPredefinedComment.map((item) => <span onClick={(e) => { handleSuggestClick(e, item) }}>{item}</span>)}\n          </div>\n          <textarea value={inputValue} onChange={e => setInputValue(e.target.value)} className={style.FeedbackTextarea} cols=\"30\" rows=\"5\" wrap=\"on\" />\n          <div>\n            <button className={style.FeedbackButton} onClick={(e) => onSubmit(e, false, inputValue, message)}>Submit</button>\n          </div>\n        </div>\n    </>\n  )\n}\n\nexport default Feedback"
  },
  {
    "path": "ui/src/components/ChatBox/Loader.jsx",
    "content": "import style from \"./ChatBox.module.css\"\n\nconst Loader = ()=>{\n\n    return(\n        <div className={style.Loader}>\n            <span></span>\n            <span></span>\n            <span></span>\n        </div>\n    )\n}\n\nexport default Loader"
  },
  {
    "path": "ui/src/components/ChatBox/Message.jsx",
    "content": "\nimport style from \"./ChatBox.module.css\"\nimport botIcon from \"./assets/bot-icon.svg\"\nimport botErrorIcon from \"./assets/bot-error-icon.svg\"\nimport Time from \"./Time\"\nimport { useState } from \"react\"\nimport Feedback from \"./Feedback\"\nimport Table from \"../Chart/Table/Table\"\nimport BarChart from \"../Chart/BarChart/BarChart\"\nimport PieChart from \"../Chart/PieChart/PieChart\"\nimport LineChart from \"../Chart/LineChart/LineChart\"\nimport AreaChart from \"../Chart/AreaChart/AreaChart\"\nimport Summary from \"./Summary\"\nimport Markdown from \"react-markdown\"\nimport ErrorMessage from \"./ErrorMessage\"\nconst Message = ({\n    message = {},\n    onLike = ()=>{}, \n    onDisLike = ()=>{},\n    onFeedbackSubmit = ()=>{},\n    })=>{\n\n    const [showFeedback, setShowFeedback] = useState(false)\n    const [showChatSummary, setShowChatSummary] = useState(false)\n    const [showChatError, setShowChatError] = useState(false)\n\n\n    const handleOnLikeClick = (e)=>{\n        onLike(e, true, \"\", message)\n    }\n\n    const handleOnDislikeClick = (e)=>{\n        setShowFeedback(true)\n        onDisLike(e)\n    }\n\n    const handleOnFeedbackClose = ()=>{\n        setShowFeedback(false)\n    }\n\n    const handleOnSummaryOpen = ()=> {\n        setShowChatSummary(true)\n    }\n\n    const handleOnSummaryClose = ()=>{\n        setShowChatSummary(false)\n    }\n\n\n    return(\n        <>\n            <div className={style.Message}>\n                <div className={message.isBot == false ? style.UserMessageContainer : style.BotMessageContainer}>\n                    {message.isBot && <div> <img src={ message.error != \"\" ? botErrorIcon : botIcon} className={style.MessageAvatar} /></div>}\n                    <div>\n                        <div className={`${style.MessageContainer}  ${message.isBot == false ? style.UserMessage : style.BotMessage}`}>\n                            <Markdown>{message.message}</Markdown> { (message.isBot == true && message.error != \"\") && <span className={style.ErrorExpandButton} onClick={()=>setShowChatError(!showChatError)}>click here</span>}\n                            {message.isBot == true &&  <Time onLike={handleOnLikeClick} onDisLike={handleOnDislikeClick} onSummaryClick={handleOnSummaryOpen} summaryOpen ={showChatSummary}  time={\"Today 12:30pm\"} message={message}/>}\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div style={{marginLeft: \"52px\", marginBottom: \"40px\"}}>\n                 {/* {showFeedback && message.isBot && <Feedback onSubmit={onFeedbackSubmit} onFeedBackClose={handleOnFeedbackClose} message={message} /> } */}\n                \n                 { (message.kind == \"list\" || message.kind == \"table\" || message.kind == \"single\" || message.kind == \"none\") && <Table data={message.data?.chart?.data} />}\n                 { message.kind == \"bar_chart\" && <BarChart title={message.data.chart.title} data={message.data.chart.data} xAxis={message.data.chart.xAxis[0]} yAxis={message.data.chart.yAxis[0]}  /> }\n                 { message.kind == \"pie_chart\" && <PieChart title={message.data.chart.title} data={message.data.chart.data} labelKey={message.data.chart.xAxis[0]} dataKey={message.data.chart.yAxis[0]}  /> }\n                 { message.kind == \"line_chart\" && <LineChart title={message.data.chart.title} data={message.data.chart.data} xAxis={message.data.chart.xAxis[0]} yAxis={message.data.chart.yAxis[0]}  /> }\n                 { message.kind == \"area_chart\" && <AreaChart title={message.data.chart.title} data={message.data.chart.data} xAxis={message.data.chart.xAxis[0]} yAxis={message.data.chart.yAxis[0]}  /> }\n                 { message.isBot && message.data.query && <Summary message={message} /> }\n                 { message.isBot && showChatError && message.error != \"\" && <ErrorMessage error={message.error} onClose={()=>setShowChatError(false)} />} \n            </div>\n            \n        </>\n    )\n}\n\nexport default Message"
  },
  {
    "path": "ui/src/components/ChatBox/Summary.jsx",
    "content": "\nimport { useState } from 'react'\nimport queryOpenImg from \"./assets/query-open.svg\"\nimport queryCloseImg from \"./assets/query-close.svg\"\nimport style from './ChatBox.module.css'\n\nfunction Summary({message={}}) {\n  const [summaryOpen, setSummaryOpen] = useState(false);\n  const [queryOpen, setQueryOpen] = useState(false);\n\n  return (\n    <>\n        <div className={`${style.SummaryContainer} ${summaryOpen ? style.SummaryContainerOpen: \"\"}`} >\n          <div className={style.SummartyHeader} onClick={()=>setSummaryOpen(!summaryOpen)}>\n            <button className={` ${style.SummaryToggleButton}`} onClick={()=>setSummaryOpen(!summaryOpen)}>\n              <img src={\"\"} alt='closemodal' width={18} height={18} className={`${summaryOpen ? style.SummaryToggleIconClose: style.SummaryToggleIconOpen}`} />\n            </button>\n            <div>\n              <h2 className={style.SummaryHeaderTitle}>Summary</h2>\n            </div>\n          </div>\n          \n          <div>\n              <div className={style.ChatSummayContainer}>\n                  <div>\n                     \n                        <p className={style.ChatSQLSummary}>\n                          { message?.data?.chart?.data?.length > 0 && <>\n                            Showing {message?.data?.chart?.data?.length > 12 ? 12 : message?.data?.chart?.data?.length } out of {message.data?.chart?.data?.length} items retreived\n                          </> }\n                          { message?.data?.chart?.data?.length == 0 && <>\n                            There are no entries to show at the moment.\n                          </> }\n                        </p>\n                     \n                     \n                  </div>\n                  <div onClick={()=>setQueryOpen(!queryOpen)}>\n                      <div className={style.QueryTitle}>\n                          <div className={style.QueryInnerTitle}>\n                            <img src={queryOpen ? queryOpenImg : queryCloseImg}/>\n                            Query\n                            <img src={queryOpen ? queryOpenImg : queryCloseImg}/>\n                          </div>\n                      </div>\n                      <div className={queryOpen ? style.SQLQueryOpen : style.SQLQueryClose}>\n                          <p className={style.ChatSQLSummary}>{message.data.query}</p>\n                      </div>\n                  </div>\n              </div>\n              {/* <div>\n\n                 \n                  <p className={style.ChatDataSummary}>showing {message?.data?.chart?.data?.length > 12 ? 12 : message?.data?.chart?.data?.length } out of {message.data?.chart?.data?.length} items retreived</p>\n              </div> */}\n          </div>\n        </div>\n    </>\n  )\n}\n\n\n\nexport default Summary"
  },
  {
    "path": "ui/src/components/ChatBox/Time.jsx",
    "content": "import style from \"./ChatBox.module.css\"\n\nfunction Time({message={}, time= \"\", onLike = ()=>{}, onDisLike = ()=>{}, summaryOpen = false, onSummaryClick = ()=>{}}) {\n  return (\n      <>\n          <div className={style.MessageExtraInfo}>\n              <div className={style.Timecontainer}>\n                  {/* <div className={style.Timelabel}>\n                      {time}\n                  </div>\n                  <div className={style.LikeIcon}>\n                        <div className={`${message.feedback_status == 1 ? `${style.LikeButton} ${style.Activeliked}` : style.LikeButton}`} onClick={(e)=>onLike(e)}></div>\n                        <div className={`${message.feedback_status == 0 ? `${style.DislikeButton} ${style.ActiveDisliked}` : style.DislikeButton}`} onClick={(e)=>{onDisLike(e)}}></div>\n                  </div> */}\n              </div>\n          </div>\n      </>\n  )\n}\n\nexport default Time"
  },
  {
    "path": "ui/src/components/CodeBlock/CodeBlock.jsx",
    "content": "import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; // Prism highlighter\nimport { solarizedlight } from 'react-syntax-highlighter/dist/cjs/styles/prism';\nimport Button from '../Button/Button';\nimport { PiCopySimpleBold } from 'react-icons/pi';\nimport style from './CodeBlock.module.css'; // Import the CSS module\n\nconst CodeBlock = ({ codeString = \"\", Codestyle }) => {\n  const customTheme = {\n    ...solarizedlight, // Use the base solarizedlight theme\n    'comment': { color: '#888787' }, // Customize comment color\n    'variable': { color: '#ff0000' }, // Customize variable color\n  };\n\n  const customStyle = {\n    lineHeight: '1.5',\n    fontSize: '1rem',\n    borderRadius: '6px',\n    background: '#F9F9F9',\n    padding: '20px',\n    width: '100%', // Make code block width responsive\n    height: '260px'\n  };\n\n  const copyToClipboard = () => {\n    navigator.clipboard.writeText(codeString)\n      .catch(err => console.error(\"failed to copy\", err))\n  }\n\n  return (\n    <div className={style.CodeBlockContainer} style={Codestyle} onClick={copyToClipboard}>\n      <Button type=\"solid\" className={`${style.LightButton}`} >\n        <span>Copy Code</span>\n        <span><PiCopySimpleBold size={18} /></span>\n      </Button>\n\n      <SyntaxHighlighter language='javascript' style={customTheme} customStyle={customStyle}>\n        {codeString}\n      </SyntaxHighlighter>\n    </div>\n  );\n};\n\nexport default CodeBlock;\n"
  },
  {
    "path": "ui/src/components/CodeBlock/CodeBlock.module.css",
    "content": ".CodeBlockContainer{\n    width: 100%;\n    max-width: 426px;\n    box-sizing: border-box;\n}\n\n.LightButton{\n    border-radius: var(--4, 4px);\n    background: #ECF5FF;\n    color: #3893FF;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n}\n\n.LightButton span:nth-child(2) {\n    margin-top: 5px;\n}"
  },
  {
    "path": "ui/src/components/FileUpload/FileUpload.jsx",
    "content": "import React from 'react';\nimport TitleDescription from '../TitleDescription/TitleDescription';\nimport style from './FileUpload.module.css';\nimport FolderIcon from './assets/folderIcon.svg';\nimport FileIcon from './assets/fileIcon.svg';\nimport closeIcon from \"./assets/closeIcon.svg\"\n\nconst FileUpload = ({\n    title = \"\",\n    description = \"\",\n    accept = \"*\",\n    progressPrecentage = '',\n    progressTime = \"\",\n    files = [],\n    onAddFileOnDrag = () => { },\n    onFileChange = () => { },\n    onRemoveFile = () => { },\n    pdfUploadRef = null,\n    showProgressBar = false,\n    supportedFileMessage = \"\",\n    dragMessage = \"\",\n    multipleFileSupport = false\n}) => {\n    return (\n        <div>\n            <TitleDescription title={title} description={description} descriptionStyle={{paddingBottom:\"23px\"}} />\n            <div className={style.DragContainer} onDragOver={(e) => e.preventDefault()} onDragEnter={(e) => e.preventDefault()} onDrop={onAddFileOnDrag}>\n                <img src={FolderIcon} alt=\"Folder Icon\" />\n                <h4 className={style.DragMessage}>{dragMessage}</h4>\n\n                <input\n                    type=\"file\"\n                    name=\"documentLoader\"\n                    className={style.FileUploader}\n                    multiple={multipleFileSupport}\n                    onChange={onFileChange}\n                    accept={accept}\n                    ref={pdfUploadRef}\n                />\n\n                <div className={style.OptionDefault}> <h5>OR</h5> </div>\n\n                <button type='button' className={style.UploadButton} onClick={() => pdfUploadRef.current.click()}>\n                    Browse file\n                </button>\n            </div>\n            <p>{supportedFileMessage}</p>\n\n            <div>\n\n\n                {showProgressBar ? (\n                    <div className={style.ProgressContainer}>\n                        <div className={style.ProgressAnalzer}>\n                            <div className={style.ProgressBarContent}>\n                                <div className={style.ProgressText}>\n                                    <span>Uploading...</span>\n                                    <span>{progressPrecentage}% • {progressTime} remaining</span>\n                                </div>\n                            </div>\n                            <div className={style.ProgressBar}>\n                                <span\n                                    className={style.ProgressLine}\n                                    style={{ width: `${progressPrecentage}%` }}\n                                ></span>\n                            </div>\n                        </div>\n                    </div>\n                ) : (\n                    files.map((fileItem, index) => (\n                      <div key={index} className={style.ProgressContainer}>\n                        <div className={style.FileInfo}>\n                          <img src={FileIcon} alt=\"File Icon\" className={style.FileIcon} />\n                          <div className={style.FileName}>\n                            <span className={style.FilesName}>{fileItem.file_name}</span>\n                            <span className={style.FileSize}>{fileItem.file_size} MB</span> \n                          </div>\n                        </div>\n                        <div className={style.CloseProgress} onClick={() => onRemoveFile(fileItem.file_id)}>\n                          <img src={closeIcon} width={24}/>\n                        </div>\n                      </div>\n                    ))\n                  )\n                  }\n            </div>\n        </div>\n    );\n};\n\nexport default FileUpload;\n"
  },
  {
    "path": "ui/src/components/FileUpload/FileUpload.module.css",
    "content": ".DragContainer {\n    border-radius: var(--radi-mlg, 8px);\n    border: 2px dashed #3893FF;\n    background: #FFF;\n    display: flex;\n    padding: var(--spacing-lg, 24px);\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    gap: 12px;\n    max-width: 500px;\n    align-self: stretch;\n    padding: 24px;\n}\n\n.DragContainer:hover {\n    background: #F5FAFF;\n}\n\n.DragContainer:focus {\n    background: #F5FAFF;\n}\n\n.DragMessage {\n    color: #0B0B0B;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 600;\n    line-height: 20px;\n}\n\n.FileUploader {\n    display: none;\n}\n\n.FileUploader::-webkit-file-upload-button {\n    display: none;\n}\n\n.FileUploader::-webkit-file-upload-button {\n    display: none;\n}\n\n.UploadButton {\n    display: inline-block;\n    border: 1px solid #3893FF;\n    border-radius: 3px;\n    padding: 5px 8px;\n    outline: none;\n    color: #3893FF;\n    white-space: nowrap;\n    cursor: pointer;\n    font-weight: 700;\n    font-size: 10pt;\n    background: transparent;\n    margin-top: 8px;\n}\n\n.FileUploader:hover::before {\n    border-color: black;\n}\n\n.FileUploader:active::before {\n    background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9);\n}\n\n.OptionDefault {\n    width: 201px;\n    text-align: center;\n    border-top: 1px solid #E7E7E7;\n    position: relative;\n}\n\n.DragContainer:hover .OptionDefault h5 {\n    background: #F5FAFF;\n}\n\n.OptionDefault h5 {\n    left: 34%;\n    top: -8px;\n    padding-right: 20px;\n    position: absolute;\n    margin: 0;\n    background-color: #FFF;\n    color: #6D6D6D;\n    font-family: Inter;\n    font-size: 12px;\n    font-weight: 400;\n    padding-left: 20px;\n}\n\n.ProgressContainer {\n    display: flex;\n    padding: var(--16, 16px);\n    flex-direction: row;\n    align-items: center;\n    align-items: flex-start;\n    gap: 8px;\n    align-self: stretch;\n    border-radius: var(--radi-lg, 12px);\n    border: 1px solid #F0F0F0;\n    background: #FFF;\n    max-width: 518px;\n    height: auto;\n    margin-bottom: 16px;\n    animation: zoomEffect 0.5s ease-in-out forwards; \n    animation-iteration-count: 1; \n    align-items: center;\n  }\n\n  .ProgressContainer:hover, .ProgressContainer:focus {\n    border: 1px solid #A0CCFF;\n    background: #F5FAFF;\n  }\n  \n  @keyframes zoomEffect {\n    0% {\n      transform: scale(1); \n    }\n    50% {\n      transform: scale(1.1); \n    }\n    100% {\n      transform: scale(1); \n    }\n  }\n  \n\n\n.FileInfo {\n    display: flex;\n    gap: 10px;\n    flex-grow: 1;\n}\n\n.FileName {\n    display: flex;\n    flex-direction: column;\n    gap: 3px;\n}\n\n.FileSize {\n    color: #888787;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px;\n}\n\n.FilesName {\n    color: #323232;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 600;\n}\n.CloseProgress{\n    cursor: pointer;\n}\n\n.ProgressAnalzer{\n    width: 100%;\n    gap: 8px;\n    display: flex;\n    flex-direction: column;\n}\n\n.ProgressBarContent {\n    width: inherit;\n    display: flex;\n}\n\n.ProgressText {\n    display: flex;\n    flex-grow: 1;\n    flex-direction: column;\n    gap: 4px;\n}\n\n.ProgressText span:first-child {\n    color: #323232;\n    font-family: Inter, sans-serif;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 600;\n}\n\n.ProgressText span:nth-child(2) {\n    color: #888787;\n    font-family: Inter, sans-serif;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n}\n\n\n.ProgressControl{\n    display: flex;\n    gap: 12px;\n    align-items: center;\n}\n\n.ProgressBar {\n    width: 100%;\n    background-color: #e6e6e6;\n    height: 8px;\n    border-radius: 40px;\n}\n\n.ProgressLine {\n    display: block;\n    background-color: #3893FF;\n    height: 8px;\n    border-radius: 40px;\n    transition: width ease-in-out;\n}\n  "
  },
  {
    "path": "ui/src/components/Input/Input.jsx",
    "content": "import { forwardRef, useEffect, useState } from \"react\"\nimport style from \"./Input.module.css\"\n\n\n\nconst Input = forwardRef(({\n        label = \"\",\n        type = \"text\",\n        value = \"\",\n        placeholder = \"Enter here\",\n        className = \"\",\n        minLength = 0,\n        maxLength = Infinity,\n        hasError = false,\n        errorMessage = \"\",\n        onChange = ()=>{},\n        ...props\n    }, ref\n)=>{\n\n    const [textLength, setTextLength] = useState(0)\n\n    const inputOnChange = (e)=>{\n        setTextLength(e.target?.value?.length)\n        onChange(e)\n    }\n\n    useEffect(()=>{\n        setTextLength(value?.length)\n    },[value])\n\n\n    return(\n        <>\n            <div className={style.InputContainer}>\n                {label !== \"\" && <label className={style.InputLabel}>{label}</label> }\n                <input ref={ref} type={type} defaultValue={value} placeholder={placeholder} className={`${style.Input} ${hasError ? style.HasError : \"\"} ${className}`} onChange={inputOnChange} {...props} />\n                { type == \"text\" && <div className={style.InputHintContainer}>\n                    <div className={style.InputHint}>\n                            { minLength > 0 && maxLength == Infinity && <span className={style.InputHintMessage}>{`Min characters ${minLength}`}</span> }  \n                            { minLength == 0 && maxLength != Infinity &&  <span className={style.InputHintMessage}>{ `Max characters ${maxLength}`}</span> }  \n                            { minLength > 0 && maxLength != Infinity && <span className={style.InputHintMessage}>{ `Min characters ${minLength} and Max characters ${maxLength}`}</span> }  \n               \n                    </div>\n                    <div>\n                       {(minLength > 0 || maxLength != Infinity) && <span className={style.InputHintMessage}>{textLength}/ { maxLength != Infinity ? maxLength: minLength }</span> }\n                    </div>\n                </div>}\n                {errorMessage !== \"\" && <span className={style.ErrorMessage}>{errorMessage}</span>}\n            </div>\n\n        </>\n    )\n})\n\nexport default Input"
  },
  {
    "path": "ui/src/components/Input/Input.module.css",
    "content": "\n.InputContainer{\n    margin-bottom: 24px;\n}\n\n.InputLabel {\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px;\n    margin-bottom: 5px;\n    margin-left: 4.23px;\n    display: block;\n}\n\n.InputHintContainer{\n    display: flex;\n}\n\n.InputHint {\n    flex-grow: 1;\n}\n\n.InputHintMessage {\n    color: #C8C8C8;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px;\n    margin-left: 5px;\n    margin-right: 5px;\n}\n\n\n.Input {\n    border-radius: 6px;\n    border: 1px solid #F0F0F0;\n    background: var(--white-100, #FFF);\n    padding: 10px 16px;\n    width: 100%;\n    color: #888787;\n    box-sizing: border-box;\n     -webkit-box-sizing: border-box;\n     -moz-box-sizing:  border-box;\n}\n\n.Input:hover {\n    border: 1px solid #DBEBFF;\n}\n\n.Input:focus {\n    outline: none;\n    border: 1px solid #3893FF;\n}\n\n.Input::placeholder {\n    color: #DDD;\n    font-weight: 400;\n}\n\n\n\n.InputLabel:has(+ .Input:required)::after {\n    content: \" *\";\n    color: #FF7F6D;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400\n}\n.HasError {\n    border-color: #FF7F6D;\n}\n\n.HasError:hover {\n    border-color: #FFB9AF;\n}\n\n.HasError:focus {\n    border-color: #FF7F6D;\n}\n\n.ErrorMessage {\n    color: #FF7F6D;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px; /* 133.333% */\n    margin-left: 4px;\n}\n\n.HasError:hover ~ .ErrorMessage {\n    color: #FFB9AF;\n}\n\n.HasError:focus ~ .ErrorMessage {\n    color: #FF7F6D;\n}\n"
  },
  {
    "path": "ui/src/components/Modal/Modal.jsx",
    "content": "\n\nimport closeIcon from \"./assets/closeIcon.svg\"\nimport style from \"./Modal.module.css\"\n\nconst Modal = ({title = \"\", show = \"\", onClose=()=>{}, children})=>{\n\n\n\n\n    return(\n        <div className={`${style.Modal} ${show == false ? \"\": style.ModalShow} `}>\n            <div className={style.ModalHeader}>\n                <div className={style.ModalTitle}>{title}</div>\n                <div className={style.CloseIconContainer} onClick={()=>onClose()}><img src={closeIcon}/></div>\n            </div>\n            <div>\n                {children}\n            </div>\n        </div>\n    )\n}\n\nexport default Modal"
  },
  {
    "path": "ui/src/components/Modal/Modal.module.css",
    "content": "\n.Modal {\n    height: 85vh;\n    width: 460px;\n    position: fixed;\n    background-color: #FFF;\n    right: 0px;\n    bottom: 0px;\n    border-radius: 10px 0px 0px 0px;\n    padding: 27px 29px;\n    box-shadow: -2px 2px 20px 2px #e9e5e5;\n    display: none;\n}\n\n.ModalShow {\n    display: block;\n}\n\n\n.ModalHeader {\n    display: flex;\n    margin-bottom: 41px;\n}\n\n.ModalTitle {\n    flex-grow: 1;\n    color: #323232;\n    font-family: Inter;\n    font-size: 20px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 20px;\n}\n\n.CloseIconContainer{ \n    cursor: pointer;\n}"
  },
  {
    "path": "ui/src/components/NotificationPanel/NotificationPanel.jsx",
    "content": "\n\nimport style from \"./NotificationPanel.module.css\";\n\nconst NotificationPanel = ({type = \"error\", message = \"\", containerStyle = {}, containerClass = \"\"})=>{\n\n\n    const getNotificationType = (type)=>{\n        switch (type) {\n            case \"error\": return style.NotificationError;\n            case \"warning\": return style.NotificationWarning;\n            case \"success\": return style.NotificationSuccess;\n            default: return style.NotificationError;\n        }\n    }\n\n    return (\n        <div className={`${style.NotificationContainer} ${containerClass}`} style={containerStyle}>\n             <div className={`${style.NotificationPanel} ${getNotificationType(type)}`}>\n                <div> <img src=\"\" className={style.NotificationImg} /> </div>\n                <div className={style.NotificationMessage}>{message}</div>\n             </div>\n        </div>\n    )\n\n}\n\nexport default NotificationPanel;"
  },
  {
    "path": "ui/src/components/NotificationPanel/NotificationPanel.module.css",
    "content": ".NotificationPanel {\n    border-radius: 8px;\n    display: flex;\n    padding: 9px 13px 6px;\n    justify-content: center;\n    align-items: flex-start;\n    gap: 10px;\n}\n\n.NotificationError {\n    background: #FFF2F0;\n}\n\n.NotificationSuccess {\n    background: #EAF0EC;;\n}\n\n.NotificationWarning {\n    background: #FDF5EC;;\n}\n\n.NotificationError .NotificationImg {\n    content: url(./assets/error.svg);\n}\n\n.NotificationSuccess .NotificationImg {\n    content: url(./assets/success.svg);\n}\n\n.NotificationWarning .NotificationImg {\n    content: url(./assets/warning.svg);\n}\n\n.NotificationMessage {\n    flex-grow: 1;\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px\n}"
  },
  {
    "path": "ui/src/components/RouteTab/RouteTab.jsx",
    "content": "import { useState } from 'react';\nimport style from './RouteTab.module.css';\n\nexport default function RouteTab({className, TabName=\"\", Deployroutes, TabStyle, ContainerStyle, ...props }) {\n    // State to track the active tab\n    const [activeTab, setActiveTab] = useState(Deployroutes[0].path);\n    return (\n        <>\n            <nav>\n                <div className={`${style.TabNavBar} ${className}`} style={ContainerStyle}{...props}>\n                    {Deployroutes.map((item, index) => (\n                        <div style={TabStyle}\n                            key={index}\n                            className={`${style.TabNavBarLinkActive} ${activeTab === item.path ? style.active : ''} ${item.disabled? style.TabDisable : \"\"}`}\n                            onClick={() => item.disabled ? ()=>{} : setActiveTab(item.path)}\n                        >\n                            {item.title}\n                        </div>\n                    ))}\n                </div>\n            </nav>\n            <div className={`${style.TabContent}`}>\n                {Deployroutes.map((item, index) => (\n                    activeTab === item.path && (\n                        <div key={index}>\n                            {item.page}\n                        </div>\n                    )\n                ))}\n            </div>\n        </>\n    );\n}\n"
  },
  {
    "path": "ui/src/components/RouteTab/RouteTab.module.css",
    "content": ".TabNavBar {\n    display: flex;\n    padding: var(--4, 4px) 5px;\n    gap: 10px;\n    border-radius: 10px;\n    background: #F9F9F9;\n    flex-direction: row;\n}\n\n.TabNavBarLinkActive {\n    flex-grow: 1;\n    background-color: aquamarine;\n    padding: 15px 10px;\n    text-align: center;\n    border-radius: var(--8, 8px);\n    color: #000;\n    font-feature-settings: 'liga' off, 'clig' off;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 20px; /* 125% */\n    background: #F9F9F9;\n    cursor: pointer;\n    /* 125% */\n}\n\n.TabNavBarLinkActive.active{\n    background: #F0F0F0;\n}\n.TabNavBarLinkActive:hover{\n    background: white;\n}\n\n.TabContent {\n    background-color: #FFF;\n    padding: 47px 13px;\n    display: block;\n}\n\n\n.TabDisable {\n    cursor: not-allowed;\n    /* pointer-events: none; */\n}\n"
  },
  {
    "path": "ui/src/components/SearchInput/SearchInput.jsx",
    "content": "\nimport style from \"./SearchInput.module.css\"\n\nconst SearchInput = ({\n    label=\"\",\n    placeholder = \"Search\",\n    defaultValue = \"\",\n    className = \"\",\n    onChange = ()=>{},\n    ...props\n})=>{\n\n    return(\n        <>\n            {label !== \"\" && <lable className={style.InputLabel}>{label}</lable> }\n            <input type=\"text\" placeholder={placeholder} className={style.Input} onChange={onChange} {...props} />\n        </>\n    )\n}\n\nexport default SearchInput"
  },
  {
    "path": "ui/src/components/SearchInput/SearchInput.module.css",
    "content": "\n.InputLabel {\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px;\n    margin-bottom: 5px;\n    margin-left: 4.23px;\n    display: block;\n}\n\n.Input {\n    border-radius: 6px;\n    border: 0.5px solid #F0F0F0;\n    background: var(--white-100, #FFF);\n    padding: 10px 16px;\n    width: 100%;\n    margin-bottom: 20px;\n    box-sizing: border-box;\n     -webkit-box-sizing: border-box;\n     -moz-box-sizing:  border-box;\n\n     background-image: url(\"./assets/search.svg\");\n     background-repeat: no-repeat;\n     background-position: 10px 9px;\n     padding-left: 32px;\n}\n\n\n.Input:hover {\n    border: 1px solid #DBEBFF;\n}\n\n.Input:focus {\n    outline: none;\n    border: 1px solid #3893FF;\n}"
  },
  {
    "path": "ui/src/components/Select/Select.jsx",
    "content": "import { useEffect, useState } from 'react';\nimport { default as DropdownSelect } from 'react-select';\nimport style from './Select.module.css';\n\n\n\nconst Select = ({label, disabled = false , placeholder, options, value, hasError = false, errorMessage = \"\", onChange, noMargin, ...props}) => {\n    const [selectedOption, setSelectedOption] = useState(null);\n\n    const handleChange = (option) => {\n        setSelectedOption(option);\n        onChange(option)\n    };\n\n    useEffect(()=>{\n        setSelectedOption(value)\n    },[value])\n\n    // Custom styles for the dropdown\n    const customStyles = {\n        control: (provided, state) => ({\n            ...provided,\n            color: '#DDDDDD',\n            fontSize: \"14px\",\n            fontFamily: 'Inter',\n            backgroundColor: state.isFocused ? 'transparent' : 'transparent',\n            borderColor: state.isFocused ? hasError ?   '#3893FF' : '#3893FF' : hasError ? \"#FF7F6D\" : '#F0F0F0',\n            boxShadow: 'none',\n            '&:hover': {\n                borderColor: '#3893FF'\n            }\n        }),\n        option: (provided, state) => ({\n            ...provided,\n            fontFamily: 'Inter',\n            backgroundColor: state.isSelected ? '#FFF' : state.isFocused ? '#f0f0f0' : '#fff',\n            color: state.isSelected ? '#5B5B5B' : state.isFocused ? '#333' : '#333',\n            fontSize: \"14px\",\n            padding: '10px',\n            '&:hover': {\n                backgroundColor: '#F9F9F9'\n            }\n        }),\n        menu: (provided) => ({\n            ...provided,\n            backgroundColor: '#fff',\n            border: '1px solid #ddd',\n            borderRadius: '4px',\n            boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)'\n        }),\n        menuList: (provided) => ({\n            ...provided,\n            padding: '0'\n        }),\n        singleValue: (provided) => ({\n            ...provided,\n            color: '#333'\n        }),\n        indicatorSeparator: (provided) => ({\n            ...provided,\n            display: 'none'\n        }),\n        placeholder:(provided)=>({\n            ...provided,\n            color:\"#888787\"\n        }),\n        multiValue: (provided) => ({\n            ...provided,\n            backgroundColor: '#74B3FF',\n            borderRadius: '20px',\n            padding: '3px 4px',\n            gap: '4px',\n            border: 'none',\n            display: 'flex',\n            alignItems: 'center'\n\n        }),\n        multiValueLabel: (provided) => ({\n            ...provided,\n            color: '#FFFFFF',\n            fontSize: '14px',\n            padding: '2px',\n            fontFamily: 'Inter',\n        }),\n        multiValueRemove: (provided) => ({\n            ...provided,\n            color: '##84BCFF',\n            backgroundColor: '#fff',\n            cursor: 'pointer',\n            height: '18px',\n            width: '18px',\n            borderRadius: '100%',\n            ':hover': {\n                color: '#FF7F6D',\n            }\n        }),\n    };\n\n    return (\n        <div className={`${noMargin ? '' : style.SelectContainer}`}>\n            {noMargin ? '' : <h4 className={style.SelectLabel}>{label}</h4>}\n            <DropdownSelect\n                value={selectedOption}\n                onChange={handleChange}\n                options={options}\n                placeholder={placeholder}\n                isDisabled={disabled}\n                styles={customStyles}\n                {...props}\n\n            />\n             {errorMessage !== \"\" && <span className={style.errorMessage}>{errorMessage}</span>}\n        </div>\n    );\n};\n\nexport default Select;"
  },
  {
    "path": "ui/src/components/Select/Select.module.css",
    "content": ".SelectContainer {\n    margin-bottom: 24px;\n}\n\n\n.SelectLabel{\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px;\n    margin-bottom: 5px;\n    margin-left: 4.23px;\n    display: block;\n}"
  },
  {
    "path": "ui/src/components/Tab/Tab.jsx",
    "content": "\nconst Tab = ({\n        title=\"Tab\",\n        eventKey= \"tab\",\n        children\n    })=>{\n\n    return(\n        <>\n            <div>\n                {children}\n            </div>\n        \n        </>\n    )\n\n}\n\nexport default Tab"
  },
  {
    "path": "ui/src/components/Tab/Tab.module.css",
    "content": "\n/* Tabs style */\n\n.Tabs {\n    display: flex;\n}\n\n.TabButton {\n    padding: 15px 16px;\n    color: #C8C8C8;\n    text-align: center;\n    font-family: Inter;\n    font-size: 11px;\n    font-style: normal;\n    font-weight: 600;\n    line-height: 16px;\n    text-transform: uppercase;\n    cursor: pointer;\n}\n\n\n\n.TabButton:hover{\n    background-color: #F0F0F0;\n}\n\n.TabButtonDisabled {\n   cursor:no-drop ;\n}\n\n.TabButtonActive {\n    border-bottom: 2px solid #3893FF;\n    color: #3893FF;\n}\n\n\n.TabPanel {\n    display: none;\n}\n\n.TabBody {\n    padding: 25px 0px;\n}\n\n.TabPanelActive {\n    display: initial;\n}\n"
  },
  {
    "path": "ui/src/components/Tab/Tabs.jsx",
    "content": "\nimport { Children, useEffect, useState } from \"react\"\nimport style from \"./Tab.module.css\"\n\nconst renderTab = (title, key, isActive, onTabClick, disabled = false, hide = false) => {\n    return (\n        <>\n           {hide == false && <div key={key} className={`${style.TabButton} ${disabled == true ? style.TabButtonDisabled : \"\"} ${isActive == true ? style.TabButtonActive : ''}`} onClick={() => disabled == false ? onTabClick(key): ()=>{}} >{title}</div> }\n        </>\n    )\n}\n\nconst Tabs = ({ activeTab, children }) => {\n    const [activetab, setActivetab] = useState(activeTab)\n    let content = \"\"\n\n    const onTabClick = (key) => setActivetab(key)\n\n    useEffect(() => {\n        setActivetab(activeTab)\n    }, [activeTab]);\n\n    return (\n        <>\n            <div className={style.Tabs}>\n                {Children.map(children, (child) => {\n                   \n                    if(child){\n                        if (activetab == child.props.tabKey){content = child.props.children}\n                        return renderTab(child.props.title, child.props.tabKey, activetab == child.props.tabKey, onTabClick, child.props.disabled ?? false, child.props.hide ?? false)\n                    }\n                })}\n            </div>\n            <div className={style.TabBody}>\n                {\n                   Children.map(children, (child, index)=>{\n                        return (<>\n                              {child && <div key={index} className={`${style.TabPanel} ${child.props.tabKey == activetab ? style.TabPanelActive : \"\"}`}>\n                                {child}\n                                </div>}\n                            </>\n                        )\n                   }) \n                }\n            </div>\n        </>\n    )\n\n}\n\nexport default Tabs"
  },
  {
    "path": "ui/src/components/Table/DatatableCustomTheme.css",
    "content": ".rdt_Table{\n    font-family:  Inter;\n}\n\n.rdt_TableHeadRow {\n    height: 58px;\n    background-color: red;\n    border-bottom-color: #EFEFEF !important;\n}\n\n\n\n.rdt_TableHeadRow  {\n    background-color: #F9F9F9 !important;\n    text-transform: uppercase;\n    color: #888787;\n    font-size: 11px;\n    font-style: normal;\n    font-weight: 600;\n    line-height: 16px\n}\n\n.rdt_TableRow {\n    height: 58px;\n    background-color: #F9F9F9 !important;\n    border-bottom-color: #EFEFEF !important;\n    cursor: pointer;\n}\n\n.rdt_TableRow:hover {\n    background-color: #FFF !important;\n}\n\n\n\n.rdt_TableRow:has(+ .rdt_ExpanderRow)  {\n    background-color: #FFF !important;\n    border: 0px !important;\n}\n\n.rdt_TableRow button[data-testid]:hover, .rdt_TableRow button[data-testid]:focus {\n    background-color: transparent !important;\n}\n"
  },
  {
    "path": "ui/src/components/Table/Pagination.jsx",
    "content": "import style from \"./Table.module.css\"\n\nconst Pagination = (props)=>{\n\n    let totalButtons = Math.floor(props.rowCount/props.rowsPerPage) + 1 ?? 0\n  \n    let starting = (props.currentPage - 1) * props.rowsPerPage\n    let ending = props.rowCount\n\n    let buttonStartFrom = totalButtons > 10 ? parseInt(props.currentPage) : 1;\n\n    if (buttonStartFrom > (totalButtons - 10) && totalButtons > 10){\n        buttonStartFrom = totalButtons - 9\n    }\n\n    const onPageInputChange = (e)=>{\n        if(isNaN(e.key) && e.keyCode != 8){\n            e.preventDefault()\n        }\n    }\n\n\n    return(\n        <>\n            <div className={style.Pagination}>\n                { totalButtons > 10  && (<>\n                                    <button className={`${style.opPaginationButton} `} disabled={props.currentPage == 1}  style={{width: \"auto\"}} onClick={()=>props.onChangePage(1)}>First</button>\n                                    <button className={`${style.opPaginationButton} `} disabled={props.currentPage == 1} style={{width: \"auto\"}} onClick={()=>props.onChangePage( props.currentPage - 1)}>Previous</button>\n                            </>)} \n                            {/* <div> */}\n                            {\n                                 new Array(totalButtons > 10 ? 10 : totalButtons).fill(0).map((item,index)=>{\n                                    return(\n                                        <button key={index} \n                                        className={`${style.PaginationButton}  ${(buttonStartFrom + index) == props.currentPage ? style.PaginationButtonSelected:\"\"}`} \n                                        onClick={()=>props.onChangePage(buttonStartFrom + index)}>{buttonStartFrom  + index}</button>)\n                                    \n                                })\n                            } \n                            {/* </div> */}\n\n                           { totalButtons > 10 && (<>\n                                <button className={`${style.opPaginationButton} `} disabled={props.currentPage == totalButtons} style={{width: \"auto\"}} onClick={()=>props.onChangePage( props.currentPage + 1)}>Next</button>\n                                <button className={`${style.opPaginationButton} `} disabled={props.currentPage == totalButtons} style={{width: \"auto\"}} onClick={()=>props.onChangePage(totalButtons)}>Last</button>\n                           </>) }\n            </div>\n        </>\n    )\n}\n\nexport default Pagination"
  },
  {
    "path": "ui/src/components/Table/Table.jsx",
    "content": "\nimport DataTable from \"react-data-table-component\"\nimport Pagination from \"./Pagination\"\nimport expandIcon from \"./assets/tableExpandIcon.svg\"\nimport collapseIcon from \"./assets/tableCollapseIcon.svg\"\nimport style from \"./Table.module.css\"\nimport \"./DatatableCustomTheme.css\"\n\nconst Table = ({\n    columns = [],\n    data= [],\n    ...props\n})=>{\n\n    return(\n        <>\n            <div className={style.Table}>\n                <DataTable \n                    columns={columns} \n                    data={data} \n                    pagination={true} \n                    paginationPerPage={10}\n                    paginationComponent={Pagination} \n                    expandableIcon={{collapsed:  <img src={collapseIcon} className={style.TableExpandCollapseIcon} />, expanded: <img src={expandIcon} className={style.TableExpandCollapseIcon} />}}\n                    {...props}/>\n            </div>\n            \n        \n        </>\n    )\n}\n\nexport default Table"
  },
  {
    "path": "ui/src/components/Table/Table.module.css",
    "content": "\n\n.Table {\n    border-radius: 8px;\n    background: #F9F9F9;\n    padding: 12px 0px;\n}\n\n.TableExpandCollapseIcon {\n    margin-left: 20px;\n    height: 21px;\n}\n\n/* Pagination */\n.Pagination {\n    margin: auto;\n    text-align: center;\n    margin-top: 27px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 2px;\n}\n\n.PaginationButton {\n    color: #151414;\n    text-align: center;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px;\n    padding: 8px;\n    background-color: transparent;\n    border: 0px;\n    width: 30px;\n    height: 30px;\n    cursor: pointer;\n}\n\n.PaginationButtonSelected {\n    border-radius: 4px;\n    background: #FFF;\n    box-shadow: 0px 1px 4px 0px rgba(26, 26, 67, 0.10);\n}"
  },
  {
    "path": "ui/src/components/Tag/Tag.jsx",
    "content": "\nimport style from \"./Tag.module.css\"\n\nconst Tag = ({type = \"primary\", children, ...props})=>{\n\n\n    return(\n        <span className={`${style.Tag} ${style[`Tag-${type}`]}`} {...props}>{children}</span>\n    )\n}\n\nexport default Tag\n\n"
  },
  {
    "path": "ui/src/components/Tag/Tag.module.css",
    "content": ".Tag{\n    padding: 3px 8px;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 18px;\n    border-radius: 4px;\n    display: block;\n}\n\n\n.Tag-success{\n    border: 0px solid #64A25E;\n    background: #E4F5E1;\n    color: #2F6846;\n}\n\n.Tag-warning{\n    border: 0px solid #FFC57D;\n    background: #F9EEE2;\n    color: #EE9D3E;;\n}"
  },
  {
    "path": "ui/src/components/Textarea/Textarea.jsx",
    "content": "import { forwardRef, useEffect, useState } from \"react\"\nimport style from \"./Textarea.module.css\"\n\nconst Textarea = forwardRef(({\n    label = \"\",\n    value = \"\",\n    placeholder = \"Enter here\",\n    className = \"\",\n    minLength = 0,\n    maxLength = Infinity,\n    hasError = false,\n    errorMessage = \"\",\n    onChange = ()=>{},\n    ...props\n},ref)=>{\n\n\n    const [textLength, setTextLength] = useState(0)\n\n    const inputOnChange = (e)=>{\n        setTextLength(e.target?.value?.length)\n        onChange(e)\n    }\n\n    useEffect(()=>{\n        setTextLength(value?.length)\n    },[value])\n\n\n    return(\n        <>\n            <div className={style.InputContainer}>\n                {label !== \"\" && <label className={style.InputLabel}>{label}</label> }\n                <textarea ref={ref} defaultValue={value} placeholder={placeholder} className={`${style.Input} ${hasError ? style.HasError : \"\"} ${className}`} onChange={inputOnChange} {...props} />\n                <div className={style.InputHintContainer}>\n                    <div className={style.InputHint}>\n                        <span className={style.InputHintMessage}>\n                            { minLength > 0 && maxLength == Infinity && `Min characters ${minLength}` }  \n                            { minLength == 0 && maxLength != Infinity && `Max characters ${maxLength}` }  \n                            { minLength > 0 && maxLength != Infinity && `Min characters ${minLength} and Max characters ${maxLength}` }  \n                        </span>\n                    </div>\n                    <div>\n                       {(minLength > 0 || maxLength != Infinity) &&  <span className={style.InputHintMessage}>{textLength}/ { maxLength != Infinity ? maxLength: minLength }</span> }\n                    </div>\n                </div>\n                {errorMessage !== \"\" && <span className={style.ErrorMessage}>{errorMessage}</span>}\n            </div>\n        </>\n    )\n})\n\nexport default Textarea"
  },
  {
    "path": "ui/src/components/Textarea/Textarea.module.css",
    "content": ".InputContainer{\n    margin-bottom: 24px;\n}\n\n.InputLabel {\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px;\n    margin-bottom: 5px;\n    margin-left: 4.23px;\n    display: block;\n}\n\n\n.InputHintContainer{\n    display: flex;\n}\n\n.InputHint {\n    flex-grow: 1;\n}\n\n.InputHintMessage {\n    color: #C8C8C8;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px;\n    margin-left: 5px;\n    margin-right: 5px;\n}\n\n\n.Input {\n    color: #888787;\n    border-radius: 6px;\n    border: 0.5px solid #F0F0F0;\n    background: var(--white-100, #FFF);\n    padding: 10px 16px;\n    width: 100%;\n    box-sizing: border-box;\n     -webkit-box-sizing: border-box;\n     -moz-box-sizing:  border-box;\n     font-family: \"Inter\";\n}\n\n.Input:hover {\n    border: 1px solid #DBEBFF;\n}\n\n.Input:focus {\n    outline: none;\n    border: 1px solid #3893FF;\n}\n\n.Input::placeholder {\n    color: #DDD;\n}\n\n.InputLabel:has(+ .Input:required)::after {\n    content: \" *\";\n    color: #FF7F6D;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400\n}\n\n.HasError {\n    border-color: #FF7F6D;\n}\n\n.HasError:hover {\n    border-color: #FFB9AF;\n}\n\n.HasError:focus {\n    border-color: #FF7F6D;\n}\n\n.ErrorMessage {\n    color: #FF7F6D;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px; /* 133.333% */\n    margin-left: 4px;\n}\n\n.HasError:hover ~ .ErrorMessage {\n    color: #FFB9AF;\n}\n\n.HasError:focus ~ .ErrorMessage {\n    color: #FF7F6D;\n}\n"
  },
  {
    "path": "ui/src/components/TitleDescription/TitleDescription.jsx",
    "content": "import style from './TitleDescription.module.css';\n\nconst TitleDescription = ({\n  title = \"\",\n  description = \"\",\n  className = \"\",\n  headingClass = \"\",\n  showOrder = false ,\n  descriptionClass = \"\",\n  orderNumber = 0,\n  ...props\n})=>{\n    return (\n    <div className={`${style.TitleContainer} ${className}`} {...props}>\n      {showOrder ? ( <div className={style.CountNumber}>{orderNumber}</div>):(null)}\n      <div>\n        <h3 className={`${style.Title} ${headingClass}`}>{title}</h3>\n        <p className={`${style.Description} ${descriptionClass}`}>{description}</p>\n      </div>\n    </div>\n    )\n}\n\nexport default TitleDescription;\n"
  },
  {
    "path": "ui/src/components/TitleDescription/TitleDescription.module.css",
    "content": ".TitleContainer{\n    display: flex;\n    gap:10px\n}\n.CountNumber{\n    width: 26px;\n    height: 26px;\n    border-radius: 15px;\n    background: #F0F0F0;\n    text-align: center;\n    display: flex;\n    justify-items: center;\n    align-items: center;\n    justify-content: center;\n    color: #323232;\n    font-family: Inter;\n    font-size: 16px;\n    font-weight: 500;\n}\n\n.NoCount{\n    display: none;\n}\n\n\n.Title{\n    margin: 0;\n    padding: 0;\n    color: #323232;\n    /* Small text */\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 150%; /* 24px */\n}\n\n.Description{\n    margin: 0;\n    margin-top: 10px;\n    color: #888787;\n    font-feature-settings: 'liga' off, 'clig' off;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px; \n    padding-bottom: 30px;/* 142.857% */\n}"
  },
  {
    "path": "ui/src/components/TitleDescription/TitleDescriptionContainer.jsx",
    "content": "import  React  from 'react';\nconst TitleDescriptionContainer = ({ children }) => {\n    return (\n       <>\n       {React.Children.map(children, (child, index) => {\n            if(React.isValidElement(child)){\n                return React.cloneElement(child, { showOrder: true, })\n            }\n        })}\n       </>\n    );\n};\n\nexport default TitleDescriptionContainer"
  },
  {
    "path": "ui/src/config/const.js",
    "content": "const defaultBackednURL = \"\"\nexport const  API_URL = (import.meta.env.VITE_BACKEND_URL ?? defaultBackednURL) + \"/api/v1\"\nexport const  BACKEND_SERVER_URL = import.meta.env.VITE_BACKEND_URL ?? defaultBackednURL\nexport const  SLACK_URL = \"https://theailounge.slack.com\"\n\n\n"
  },
  {
    "path": "ui/src/config/routes.jsx",
    "content": "import Sources from \"src/pages/Sources/Sources\";\nimport Configuration from \"src/pages/Configuration/Configuration\"\nimport Deploy from \"src/pages/Deploy/Deploy\";\nimport Preview from \"src/pages/Preview/Preview\";\nimport Samples from \"src/pages/Samples/Samples\";\nimport ChatConfiguration from \"src/pages/ChatConfiguration/ChatConfigurationForm\";\nimport ProviderForm from \"src/pages/Configuration/ProviderForm/ProviderForm\";\nimport BotConfiguration from \"src/pages/ChatConfiguration/ChatConfigurationForm\";\nimport Chat from \"src/pages/Chat/Chat\";\nimport NotFound from \"src/layouts/errorPage/404\";\nimport ServerError from 'src/layouts/errorPage/500';\nimport ChatConfigurationMain from \"src/pages/ChatConfiguration/ChatConfiguration\";\n\nconst  routes = [\n\n    {\n        title: \"chatContext\",\n        path: \"/preview/:contextId/chat\",\n        icon: \"\",\n        page: <Preview/>,\n        isPrivate: true\n    },\n    {\n        title: \"Plugins\",\n        path: \"/plugins\",\n        icon: \"\",\n        page: <Configuration/>,\n        isPrivate: true\n    },\n    {\n        title: \"Samples\",\n        path: \"/samples\",\n        icon: \"\",\n        page: <Samples/>,\n        isPrivate: true\n    },\n   \n    // {\n    //     title: \"Deploy\",\n    //     path: \"/deploy\",\n    //     icon: \"\",\n    //     page: <Deploy/>,\n    //     isPrivate: true\n    // },\n    {\n        title: \"Sources\",\n        path: \"/plugins/sources\",\n        icon: \"\",\n        page: <Sources/>,\n        isPrivate: true\n    },\n    \n\n    {\n        title: \"Provide Form\",\n        path: \"/plugins/:providerId/:providerName\",\n        icon: \"\",\n        page: <ProviderForm/>,\n        isPrivate: true\n    },\n\n    {\n        title: \"Provide Form\",\n        path: \"/plugins/:providerId/:providerName/:connectorId/details\",\n        icon: \"\",\n        page: <ProviderForm/>,\n        isPrivate: true\n    },\n\n    {\n        title: \"Chat Configuration\",\n        path: \"/chat-configuration\",\n        icon: \"\",\n        page: <ChatConfiguration/>,\n        isPrivate: true\n    },\n    {\n        title: \"Bot Configuration\",\n        path: \"/bot-configuration\",\n        icon: \"\",\n        page: <ChatConfigurationMain/>,\n        isPrivate: true\n    },\n    {\n        title: \"Bot Configuration\",\n        path: \"/bot-configuration/sources\",\n        icon: \"\",\n        page: <BotConfiguration/>,\n        isPrivate: true\n    },\n    {\n        title: \"Bot Configuration\",\n        path: \"/bot-configuration/:configId\",\n        icon: \"\",\n        page: <BotConfiguration/>,\n        isPrivate: true\n    },\n    {\n        title: \"Not Found\",\n        path: \"*\",  \n        icon: \"\",\n        page: <NotFound />, \n        isPrivate: false\n    },\n    {\n        title: \"Server Error\",\n        path: \"/error\",  \n        icon: \"\",\n        page: <ServerError />, \n        isPrivate: false\n    },\n  ]\n\n  export default routes"
  },
  {
    "path": "ui/src/embedbot/ChatBot.css",
    "content": "@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap');\nbody {\n  font-family: Arial, sans-serif;\n  margin: 0;\n  padding: 0;\n}\n\n/* floating button */\n.float-button {\n  width: 60px;\n  height: 60px;\n  padding: 19.41px;\n  gap: 0px;\n  border-radius: 100px;\n  position: fixed;\n  bottom: 20px;\n  right: 20px;\n  background-color: #3893FF;\n  color: white;\n  border: none;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.button-icon {\n  transform: rotate(90deg);\n\n}\n\n.chat-box {\n  position: fixed;\n  width: 338px;\n  height: 625px;\n  bottom: 90px;\n  right: 20px;\n  border: 1px solid #ccc;\n  border-radius: 18px;\n  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n  background-color: white;\n  z-index: 1001;\n  display: flex;\n  flex-direction: column;\n}\n\n.chat-header {\n  background-color: #3893FF;\n  height: 58px;\n  padding: 20px;\n  border-radius: 18px 18px 0px 0px;\n  box-sizing: border-box;\n  display: flex;\n  align-items: center;\n}\n.chat-header img {\n  cursor: pointer;\n}\n.min-btn {\n  background: none;\n  border: none;\n  color: #F8F8F8;\n  cursor: pointer;\n  margin-right: 15px;\n  padding: none;\n}\n\n\n.header-text {\n  color: #FFF;\n  font-feature-settings: 'ss01' on, 'cv01' on, 'cv11' on;\n  font-family: Inter;\n  font-size: 18px;\n  font-style: normal;\n  font-weight: 600;\n  margin-left: 3px;\n}\n\n\n\n.chat-body {\n  flex: 1;\n  display: flex;\n  flex-direction: column;\n  overflow-y: auto; \n  padding: 10px;\n  box-sizing: border-box;\n  height: calc(100% - 112px); \n  background-color: white;\n  font-family: Inter;\n  font-size: 16px;\n  font-style: normal;\n  font-weight: 500;\n  line-height: 180%;\n}\n.message-wrapper {\n  margin-top: auto;\n  display: flex;\n  flex-direction: column;\n  gap: 10px;\n  min-height: min-content;\n}\n\n.message-wrapper table {\n  font-size: smaller;\n}\n\n.user-message,\n.bot-message,\n.botresponse-body {\n  word-wrap: break-word;\n  padding: 12px;\n  border-radius: 10px;\n  box-sizing: border-box;\n}\n\n.user-message {\n  margin-top: 10px;\n  max-width: 273.3px;\n  padding: 12px 16px;\n  background: #F1F1F1;\n  align-self: flex-end; \n}\n\n.bot-message {\n  padding: 12px 12px 0 0 ;\n  max-width: 305px;\n  align-self: flex-start;\n  display: grid;\n  grid-template-columns: auto 1fr;\n}\n.bot-message > img {\n  width: 30px; /* Fixed width for the image */\n  grid-row: span 2; /* Make the image span two rows */\n}\n\n.bot-message > div:nth-child(2) {\n  margin-left: 0; /* Reset margin as it's handled by the grid */\n  padding-top: 0;\n  max-width: 290px; /* Limit the width of the second column content */\n}\n\n.bot-message > div:nth-child(3) {\n  grid-column: span 2; /* Make the third div span across both columns */\n  width: 100%; /* Ensure it takes full width */\n}\n.bot-message div div div p {\n  font-family: Inter;\n  font-size: 16px;\n  font-style: normal;\n  font-weight: 500;\n  line-height: 180%;\n  /* max-width: 260px; */\n  margin: 0;\n}\n.bot-message div div div {\n  margin-top: 0;\n  padding-top: 0;\n}\n.bot-message div div div ul {\n  margin-left: -10px;\n}\n.botresponse-body {\n  align-self: flex-end;\n  border-radius: 4px;\n  background: #F3FAFF;\n  width: 273.3px;\n  padding: 6px 15px;\n  margin-bottom: 10px;\n}\n\n.action-div {\n  padding: 10px;\n  display: flex;\n  flex-wrap: wrap-reverse;\n  gap: 10px;\n}\n\n.action-div button {\n  display: flex;\n  gap: 6px;\n  align-items: center;\n  flex-direction: row-reverse;\n  height: 30px;\n  padding: 3px 13px;\n  border: none;\n  border-radius: 100px;\n  background: #F1F1F1;\n  color: #323232;\n  font-family: Inter;\n  font-size: 14px;\n  font-style: normal;\n  font-weight: 500;\n  line-height: 150%; /* 21px */\n  cursor: pointer;\n}\n\n.input-div {\n  box-sizing: border-box;\n  width: 100%;\n  height: auto;\n  min-height: 54px;\n  padding: 15px 20px 15px 20px;\n  gap: 30px;\n  color: black;\n  width: 100%;\n  display: flex;\n  justify-content: space-between;\n  border-top: 1px solid rgb(219, 219, 219);\n}\n\n.chat-input {\n  flex: 1;\n  border: none;\n  outline: none;\n  width: 330px;\n  max-height: 133px;\n  overflow-y: auto; \n  overflow-x: hidden;\n  font-size: 16px;\n  word-wrap: break-word;\n  white-space: pre-wrap;\n  display: flex;\n  align-items: center;\n  scrollbar-width: none; /* Firefox */\n}\n\n/* hide srollbar */\n.chat-input::-webkit-scrollbar {\n  width: 0px;\n  height: 0px;\n  display: none;\n}\n\n.chat-input:empty::before {\n  content: attr(placeholder);\n  color: gray;\n  pointer-events: none;\n  display: block;\n}\n\n\n\n.chat-button {\n  background: none;\n  border: none;\n  cursor: pointer;\n  padding: 0;\n\n}\n.chat-button img {\n  filter: grayscale(100%) brightness(50%);\n}\n\n/* big UI */\n.float-button.large {\n  /* display: none; */\n}\n.chat-box.large {\n  bottom: 0;\n  top: 0;\n  right: 0;\n  width: 597px;\n  height: 100vh;\n}\n.chat-box.large .chat-header{\n  background-color: #FFF;\n  border-bottom: 1px solid #F0F0F0;\n  height: 67px;\n}\n.chat-box.large .min-btn{\n  filter: invert(100);\n}\n.chat-box.large .header-text{\n  color: #323232;\n}\n.chat-body.large {\n  padding: 10px 23px;\n}\n.chat-body.large .user-message {\n  max-width: 430px;\n}\n.chat-body.large .bot-message{\n  max-width: 480px;\n}\n.chat-body.large .bot-message > div:nth-child(2) {\n  max-width: 480px;\n}\n\n.input-div.large {\n  width: 550px;\n  border: 1px solid #E0E0E0;\n  border-radius: 25px;\n  padding: 5px 20px;\n  min-height: 44px;\n  margin: 0 auto 18px;\n  align-items: center;\n}\n.input-div.large .chat-button {\n  background-color: #F9F9F9;\n  width: 42px;\n  min-height: 42px;\n  border-radius: 100%;\n  align-self: center;\n  margin-right: -14px;\n  /* position: relative;\n  bottom: 10px;\n  right: -15px; */\n}\n.input-div.large img {\n  position: relative;\n  left: 2px;\n  top: 2px;\n}"
  },
  {
    "path": "ui/src/embedbot/ChatBot.jsx",
    "content": "import { useState, useEffect } from 'react'\nimport { v4 as uuidv4 } from 'uuid';\nimport arrowImage from './assets/arrow.svg'\nimport logoImage from './assets/logo.svg'\nimport largeLogo from './assets/largelogo.svg'\nimport sendImage from './assets/send.png'\nimport botdpImage from './assets/bot-dp.svg'\nimport { chatBotAPI, getChatByContext } from './ChatBotAPI'\nimport { isEmptyJSON } from \"src/utils/utils\"\nimport Message from 'src/components/ChatBox/Message'\nimport Loader from '../components/ChatBox/Loader'\nimport './ChatBot.css'\n\n\nfunction ChatBot({ apiURL, configID, uiSize }) {\n  if (!apiURL) return console.error(\"apiURL is undefined\")\n  const [isOpen, setIsOpen] = useState(false);\n  const [messages, setMessages] = useState([]);\n  const [loading, setLoading] = useState(false);\n\n  const toggleChatbox = () => {\n    setIsOpen(!isOpen);\n  }\n\n  let contextId = localStorage.getItem('contextId');\n  useEffect(() => {\n    if (!contextId) {\n      contextId = uuidv4();\n      localStorage.setItem('contextId', contextId);\n    } else {\n      getChatByContext(contextId, apiURL)\n        .then(response => {\n          const chats = response.data.data.chats;\n\n          const newMessages = chats.flatMap(chat => {\n            const chatData = {\n              chart: {\n                data: chat.chat_answer.data,\n                title: chat.chat_answer.title,\n                xAxis: chat.chat_answer.x,\n                yAxis: chat.chat_answer.y,\n              },\n              query: chat.chat_answer.query,\n            };\n\n            return [\n              { sender: 'user', message: chat.chat_query },\n              { sender: 'bot', message: chat.chat_answer.content, entity: chat.chat_answer.main_entity, format: chat.chat_answer.main_format, kind: chat.chat_answer.kind, data: chatData },\n            ];\n          });\n\n          setMessages(newMessages);\n          scrollToLastMessage(2000);\n        }).catch(error => {\n          console.log(error, \"error\")\n        })\n    }\n  }, []);  /* runs only on mount  */\n\n  const fetchAndRender = async (message) => {\n    try {\n      setMessages((prevMessages) => [...prevMessages, { sender: 'user', message }]);\n      setLoading(true);\n      scrollToLastMessage(0);\n      \n      const response = await chatBotAPI(contextId, configID, apiURL, message);\n      const res = response.data;\n      \n      setMessages((prevMessages) => [\n        ...prevMessages,\n        { sender: 'bot', message: res.response.content, entity: res.response.main_entity, format: res.response.main_format, kind: res.response.kind, data: res.response },\n      ]);\n      \n      scrollToLastMessage(0); \n      \n    } catch (error) {\n      console.error(\"Chat API error:\", error);\n      setMessages((prevMessages) => [\n        ...prevMessages,\n        { sender: 'bot', message: \"Sorry, I encountered an error. Please try again.\" },\n      ]);\n    } finally {\n      setLoading(false);\n    }\n  };\n  \n\n  return (\n    <div>\n      {/* Chatbox Icon */}\n      <button className={`float-button large ${isOpen ? 'open' : ''}`} onClick={toggleChatbox}>\n        <img src={arrowImage} className='button-icon'></img>\n      </button>\n\n      {/* Chatbox Window */}\n      {isOpen && (\n        <div className={`chat-box ${uiSize === 'large' ? 'large' : ''}`}>\n          <div className=\"chat-header\">\n            <img src={arrowImage} onClick={toggleChatbox} className='min-btn'></img>\n            <img src={uiSize === 'large' ? largeLogo : logoImage}></img>\n            <span className='header-text'>Assistant</span>\n          </div>\n\n          <div className={`chat-body ${uiSize === 'large' ? 'large' : ''}`}>\n            <div className='message-wrapper'>\n              {messages.map((message, index) => {\n                if (message.sender === 'user') {\n                  return (\n                    <>\n                      <div className='user-message'>{message.message}</div>\n                      <div className='bot-message'>{loading && index === messages.length - 1 && <Loader />}</div>\n                    </>\n                  )\n                } else if (message.sender === 'bot') {\n                  return (\n                    <>\n                      <div className='bot-message'>\n                        <img src={botdpImage} alt='bot avatar'></img>\n                        {/* {message.message} */}\n                        <Message message={message} />\n                      </div>\n                    </>)\n                }\n              })}\n            </div>\n\n\n          </div>\n\n          <div className={`input-div ${uiSize === 'large' ? 'large' : ''}`}>\n            <div\n              className=\"chat-input\"\n              contentEditable=\"true\"\n              placeholder=\"Type a reply...\"\n              suppressContentEditableWarning={true}\n              onKeyDown={(e) => {\n                if (e.key === 'Enter' && !e.shiftKey) {\n                  e.preventDefault();\n                  // console.log(e.target.textContent)\n                  const chatInput = e.target.textContent.trim();\n                  if (chatInput) fetchAndRender(chatInput)\n                  e.target.textContent = ''; // Clear input\n                }\n              }}\n              onInput={(e) => {\n                if (e.target.textContent.trim() === '') {\n                  e.target.innerHTML = '';\n                }\n              }}\n            >\n            </div>\n            <button\n              className='chat-button'\n              onClick={() => {\n                const chatInput = document.querySelector('.chat-input').textContent.trim();\n                if (chatInput) fetchAndRender(chatInput);\n                document.querySelector('.chat-input').textContent = '';\n              }}\n            >\n              <img src={sendImage}></img>\n            </button>\n          </div>\n        </div>\n      )}\n    </div>\n  )\n}\n\nfunction scrollToLastMessage(delay) {\n  setTimeout(() => {\n    const chatBody = document.querySelector('.message-wrapper');\n    const lastMessage = chatBody.lastElementChild;\n    lastMessage.scrollIntoView({ behavior: 'smooth' })\n  }, delay);\n}\n\n\nexport default ChatBot\n"
  },
  {
    "path": "ui/src/embedbot/ChatBotAPI.js",
    "content": "// src/ChatBotAPI.js\n// import { API_URL } from \"src/config/const\"\nimport PostService from \"src/utils/http/PostService\";\nimport GetService from \"src/utils/http/GetService\"\nexport const chatBotAPI = (contextId, configID, apiURL, message) => {\n\n  // console.log(contextId)\n  let axiosConfig = {\n    headers: {}\n  }\n\n  return PostService(\n    apiURL + `/query/query?contextId=${contextId}&configId=${configID}&envId=${0}`,\n    { \"content\": message, \"role\":\"user\" }, {showLoader: false,allowAuthHeaders:true}, axiosConfig)\n};\n\nexport const getChatByContext = (contextId, apiURL) => {\n  return GetService(apiURL + `/chat/get/${contextId}`,{},{allowAuthHeaders:false})\n}\n\n\n"
  },
  {
    "path": "ui/src/embedbot/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport ChatBot from './ChatBot';\nimport './ChatBot.css';\n\n// Function to mount the chatbox to a specific element\nconst mountChatbox = (elementId, props = {}) => {\n  const container = document.getElementById(elementId);\n  if (container) {\n    const root = createRoot(container);\n    root.render(<ChatBot {...props}/>);\n  }\n};\n\n// Export mountChatbox so it can be used externally\nexport { mountChatbox };\n"
  },
  {
    "path": "ui/src/global.css",
    "content": "@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');\n\n\nbody{\n    padding: 0px;\n    margin: 0px;\n}\n\n\n\n:root {\n    --primary-1: #3893FF;\n    --primary-2: #74B3FF;\n    --primary-3: #84BCFF;\n    --primary-4: #CDE5FF;\n    --primary-5: #ECF5FF;\n    --primary-6: #F5FAFF;\n\n    --neural-1: #323232;\n    --neural-2: #5B5B5B;\n    --neural-3: #888787;\n    --neural-4: #C8C8C8;\n    --neural-5: #F0F0F0;\n    --neural-6: #F4F4F4;\n    --neural-7: #F9F9F9;\n    --neural-8: #FFFFFF;\n\n    --danger-1: #FF7F6D;\n    --danger-2: #FFA599;\n    --danger-3: #FFB9AF;\n    --danger-4: #FFD9D3;\n    --danger-5: #FFF2F0;\n\n    --alert-1: #EE9D3E;\n    --alert-2: #F3C188;\n    --alert-3: #FAE2C5;\n    --alert-4: #F9EEE2;\n    --alert-5: #FDF5EC;\n\n    --success-1: #2F6846;\n    --success-2: #6D957E;\n    --success-3: #96B99F;\n    --success-4: #D8E5DB;\n    --success-5: #EAF0EC;\n\n\n}\n\nh4 {\n    color: var(--neural-1);\n    font-feature-settings: 'clig' off, 'liga' off;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 20px;\n    margin: 0px;\n}\n\np{\n    color: var(--neural-3);\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px;\n    margin: 10px 0px;\n}\n\n\ntextarea {\n    color: var( --neural-3);\n    border-radius: 6px;\n    border: 0.5px solid #F0F0F0;\n    background: var(--white-100, #FFF);\n    padding: 10px 16px;\n    width: 100%;\n    /* margin-bottom: 20px; */\n    box-sizing: border-box;\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    font-family: \"Inter\";\n}\n\ntextarea::placeholder {\n    color: #DDD;\n}\n\n\n\n\n\n/* util class */\n\n.flex {\n    display: flex;\n}\n\n.flex-align-center {\n    align-items: center;\n}\n\n.flex-grow-1 {\n    flex-grow: 1;\n}\n.flex-grow-0 {\n    flex-grow: 0;\n}\n\n\n.inline-flex-align-center {\n    display: inline-flex;\n    align-items: center;\n    gap: 6px;\n}\n\n.icon-button {\n    display: inline-flex;\n    align-items: center;\n    gap: 6px;\n}\n\n.text-align-right {\n    text-align: right;\n}\n\n.text-align-center {\n    text-align: center;\n}\n\n.text-align-left {\n    text-align: left;\n}\n\n/* Chrome, Edge and Safari */\n*::-webkit-scrollbar {\n    width: 6px;\n    display: flex;\n    justify-self: start;\n    /* height: 126.786px; */\n  }\n  *::-webkit-scrollbar-track {\n    border-radius: 5px;\n  }\n  \n\n  \n  *::-webkit-scrollbar-track:active {\n    background: #F0F0F0;\n  }\n  \n  *::-webkit-scrollbar-thumb {\n    border-radius: 5px;\n    background: #F0F0F0;\n  }\n  \n  *::-webkit-scrollbar-thumb:hover {\n    background: #F0F0F0;\n  }\n  \n\n\n\n.float-right {\n    float: right;\n}\n\n.float-left {\n    float: left;\n}\n\n\n\n.margin-bottom-10 {\n    margin-bottom: 10px;\n}\n\n.margin-bottom-30 {\n    margin-bottom: 30px;\n}\n\n.flex-gap-10 {\n    gap: 10px;\n}\n\n\n\n.justify-content-end {\n    justify-content: end;\n}\n\n\n/* important span */\n.span-important::after {\n    content: \" *\";\n    color: #FF7F6D\n}"
  },
  {
    "path": "ui/src/layouts/auth/AuthLogin.jsx",
    "content": "// import { defer } from \"react-router-dom\"\nimport UserLogin from \"./UserLogin\"\nimport UserSignUp from \"./UserSignUp\"\n\n\nconst AuthLogin = () => {\n    return (\n        <UserLogin></UserLogin>\n        // <UserSignUp></UserSignUp>\n    )\n}\n\nexport default AuthLogin"
  },
  {
    "path": "ui/src/layouts/auth/UserAuth.module.css",
    "content": ".AuthBackground {\n    width: 100vw;\n    height: 100vh;\n    background: #FFF;\n\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    align-content: center;\n    flex-direction: column-reverse;\n    flex-wrap: wrap;\n}\n\n.FieldContainer {\n    display: flex;\n    padding: var(--spacing-xxxl, 40px) 60px;\n    align-items: center;\n    gap: 10px;\n    align-self: stretch;\n    width: 440px;\n    max-height: fit-content;\n    border-radius: 8px;\n    border: 0.5px solid #F0F0F0;\n    background: #FFF;\n    box-shadow: 0px 0px 30px 0px rgba(33, 33, 52, 0.08);\n    padding-bottom: 50px;\n    justify-content: center;\n    flex-direction: column;\n}\n\n.Welcome {\n    color: #323232;\n    text-align: center;\n    margin: 0;\n    color: #323232;\n    text-align: center;\n    font-family: Inter;\n    font-size: 22px;\n    font-style: normal;\n    font-weight: 600;\n    line-height: 150%;\n    /* 36px */\n}\n\n.FIeldContainer p {\n    margin: 0;\n    color: #858585;\n    text-align: center;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 150%;\n    /* 24px */\n}\n\n.SubmitButton {\n    width: 100%;\n    text-align: center;\n    justify-content: center;\n    margin: 38px 0;\n}\n\n.loader {\n    width: 28px;\n    height: 28px;\n    border-radius: 50%;\n    display: inline-block;\n    border-top: 3px solid #FFF;\n    border-right: 3px solid transparent;\n    box-sizing: border-box;\n    animation: rotation 1s linear infinite;\n  }\n  \n  @keyframes rotation {\n    0% {\n      transform: rotate(0deg);\n    }\n    100% {\n      transform: rotate(360deg);\n    }\n  } \n\n.ErrorDiv {\n    display: flex;\n    align-content: center;\n    align-items: center;\n    justify-content: center;\n    width: fit-content;\n    height: 21px;\n    flex-direction: row;\n    justify-content: center;\n    align-items: center;\n    gap: 7px;\n    border-radius: 10px;\n    background: #FDF5EC;\n    margin-top: 20px;\n    margin-bottom: 20px;\n    color: #323232;\n    text-align: center;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 150%;\n    padding: 9px 18px;\n\n}\n\n.WarningMessage{\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap:7px ;\n}\n\n.SimileIcon{\n    padding-top: 5px;\n}\n\n.CheckBox {\n    display: flex;\n    align-items: center;\n    gap: 4px;  \n}\n\n.CheckBox span {\n    color: #323232;\n    font-feature-settings: 'liga' off, 'clig' off;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 300;\n    line-height: 16px; /* 133.333% */\n}\n\ninput[type=\"checkbox\"] {\n    appearance: none;\n    width: 15px;\n    height: 15px;\n    background: #FFF;\n    border: 1.5px solid #F0F0F0;\n    border-radius: 2px;\n    cursor: pointer;\n    position: relative;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n  }\n  \n  input[type=\"checkbox\"]:checked {\n    background: #FFF;\n    border-color: #3893FF;\n  }\n  \n  input[type=\"checkbox\"]:checked::after {\n    content: \"\";\n    position: absolute;\n    top: 0px;\n    width: 4px;\n    height: 9px;\n    border: 1px solid #3893FF;\n    border-width: 0 1.5px 1.5px 0;\n    transform: rotate(45deg);\n  }\n\n  .OAuthLogin {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    gap: 20px;\n  }\n\n  .OrLogin {\n    color: #323232;\n    font-feature-settings: 'liga' off, 'clig' off;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 300;\n    line-height: 16px; /* 133.333% */\n  }\n\n.LoginGoogle {\n    display: flex;\n    align-items: center;\n    padding: 16px 52px;\n    gap: 16px;\n    border-radius: 50px;\n    border: 1px solid #F0F0F0;\n    background: #FFF;\n    cursor: pointer;\n\n}\n\n.LoginGoogle img {\n    width: 23px;\n    height: 23px;\n}\n\n.LoginGoogle span {\n    color: #323232;\n    font-feature-settings: 'liga' off, 'clig' off;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 20px; /* 125% */\n}\n\n"
  },
  {
    "path": "ui/src/layouts/auth/UserLogin.jsx",
    "content": "import style from \"./UserAuth.module.css\"\nimport logo from './assets/gennie-logo.svg';\nimport googleLogo from \"./assets/googleLogo.svg\";\nimport githubLogo from \"./assets/githubLogo.svg\"\nimport Input from 'src/components/Input/Input';\nimport Button from 'src/components/Button/Button';\nimport React, { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { AuthLoginService, IdpLoginService, GetIdpList } from 'src/services/Auth';\nimport { useNavigate } from \"react-router-dom\";\nimport { v4 as uuid4 } from \"uuid\"\nimport { toast } from \"react-toastify\";\n\n\n\nconst UserLogin = () => {\n    const { register: authRegister, setValue: authSetValue, handleSubmit: authHandleSubmit, formState: authFormState, setError: authSetError, clearErrors: authClearErrors, watch: authWatch } = useForm({ mode: 'all' });\n    const { errors: authFormError } = authFormState;\n    const [showError, setShowError] = useState(false);\n    const [errorMessage, setErrorMessage] = useState('');\n    const [idpList, setIdpList] = useState([]);\n    const [loading, setLoading] = useState(false);\n    const navigate = useNavigate()\n\n    useEffect(() => {\n        GetIdpList().then(response => {\n            setIdpList(response.data.idp_list);\n        }).catch(error => {\n            console.error(\"failed to fetch idp list\", error);\n        })\n    }, []);\n\n    function capitalizeFirstLetter(str) {\n        return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();\n    }\n    \n    /* fucntion to render idp buttons dynamically */\n\n    const renderIdpButtons = () => {\n        return idpList?.slice(0,1).map((idp) => {\n            let logo = idp.type === \"PROVIDER_TYPE_GOOGLE\" ? googleLogo : \n                       idp.type === \"PROVIDER_TYPE_GITHUB\" ? githubLogo : null;\n            return (\n                <div key={idp.id} className={style.LoginGoogle} onClick={() => IdpLoginService(idp.id)}>\n                    {logo && <img src={logo} alt={idp.type} />}\n                    <span>Login with {capitalizeFirstLetter(idp.type.replace(\"PROVIDER_TYPE_\", \"\"))}</span>\n                </div>\n            );\n        });\n    };\n\n    const onSubmit = (data) => {\n            setLoading(true);\n            const authCredentials = {\n                \"username\": data.username,\n                \"password\": data.password\n            };\n            AuthLoginService(authCredentials).then((response) => {\n                const authResponse = response.data\n                console.log(\"authResponse\", authResponse)\n                toast.success(\"Login successful\");\n                navigate(`/preview/${uuid4()}/chat`)\n                setLoading(false);\n                // const token = authResponse.data.token\n                // storeToken(token)\n                // setIsAuthenticated(true)\n            }).catch(() => {\n                setErrorMessage(\"Incorrect username or password. Please try again.\");\n                setShowError(true);\n                setLoading(false);\n            });\n        };\n\n    return (\n        <>\n        {/* add div to display error */}\n        <div className={style.AuthBackground}>\n            {/* <span style={{marginTop: \"15px\",color: \"#3893FF\",fontFamily: \"Inter\",fontSize: \"14px\"}}>Forgot password?</span> */}\n            <div className={style.FieldContainer}>\n                <img src={logo} alt=\"Genie Logo\" />\n                <h2 className={style.Welcome}>Welcome Back</h2>\n                <p>Login to your Ragggenie account</p>\n                <div style={{ width: \"100%\", backgroundColor: \"#FFF\"}}>\n                        <form onSubmit={authHandleSubmit(onSubmit)}>\n                            <Input\n                                label=\"Email\"\n                                placeholder=\"Enter your email address\"\n                                hasError={authFormError.username?.message ? true : false}\n                                errorMessage={authFormError.username?.message}\n                                {...authRegister('username', { required: 'Username is required' })}\n                            />\n\n                            <Input\n                                label=\"Password\"\n                                placeholder=\"Enter your password\"\n                                type=\"password\"\n                                hasError={authFormError.password?.message ? true : false}\n                                errorMessage={authFormError.password?.message}\n                                {...authRegister('password', { required: 'Password is required' })}\n                            />\n                            <div className={style.CheckBox}>\n                                <input type=\"checkbox\"></input>\n                                <span>Remeber me</span>\n\n                            </div>\n\n                            <Button buttonType=\"submit\" className={style.SubmitButton}>\n                                {loading ? <span className={style.loader}></span> : \"Login\"}\n                            </Button>\n                        </form>\n                        <div className={style.OAuthLogin}>\n                            <span className={style.OrLogin}>Or Login with</span>\n                            {renderIdpButtons()}\n\n                        </div>\n                    </div>\n            </div>\n        </div>\n\n        </>\n    );\n};\n\nexport default UserLogin;\n"
  },
  {
    "path": "ui/src/layouts/auth/UserSignUp.jsx",
    "content": "import style from \"./UserAuth.module.css\"\nimport logo from './assets/gennie-logo.svg';\nimport googleLogo from \"./assets/googleLogo.svg\"\nimport Input from 'src/components/Input/Input';\nimport Button from 'src/components/Button/Button';\n\n\nconst UserSignUp = () => {\n\n\n    return (\n        <>\n        <div className={style.AuthBackground}>\n            <div className={style.FieldContainer}>\n                <img src={logo} alt=\"Genie Logo\" />\n                <h2 className={style.Welcome}>Welcome Back</h2>\n                <p>Login to your Ragggenie account</p>\n                <div style={{ width: \"100%\", backgroundColor: \"#FFF\"}}>\n                        <form>\n                            <Input\n                                label=\"Name\"\n                                placeholder=\"Enter your name\"\n                            />\n                            <Input\n                                label=\"Last Name\"\n                                placeholder=\"Enter your last name\"\n                            />\n                            <Input\n                                label=\"Email\"\n                                placeholder=\"Enter you email address\"\n                            />\n                            <Input\n                                label=\"Password\"\n                                placeholder=\"Enter your password\"\n                                type=\"password\"\n                            />\n                            <Input\n                                label=\"Confirm Password\"\n                                placeholder=\"Confirum your password\"\n                                type=\"password\"\n                            />\n                            <div className={style.CheckBox}>\n                                <input type=\"checkbox\"></input>\n                                <span>I accept the term and the privacy policy</span>\n\n                            </div>\n\n                            <Button buttonType=\"submit\" className={style.SubmitButton}>\n                                Sign Up\n                            </Button>\n                        </form>\n                        <div className={style.OAuthLogin}>\n                            <span className={style.OrLogin}>Or Sign up with</span>\n                            <div className={style.LoginGoogle}>\n                                <img src={googleLogo} />\n                                <span>Sign up with Google</span>\n                            </div>\n\n                        </div>\n                    </div>\n            </div>\n        </div>\n\n        </>\n    );\n};\n\nexport default UserSignUp;\n"
  },
  {
    "path": "ui/src/layouts/dashboard/DashboadBody.jsx",
    "content": "import help from \"src/assets/icons/help.svg\"\nimport style from \"./Dashboard.module.css\"\nimport { v4 as uuidv4 } from 'uuid';\nimport { restartBot } from \"src/services/BotConfifuration\";\nimport { toast } from \"react-toastify\";\nimport Select from \"src/components/Select/Select\";\nimport { useNavigate } from \"react-router-dom\";\n\nconst DashboardBody = ({urlPrex = \"/preview\", title = \"Dashboard\",options=[], select, children, selectedOption, setSelectedOption, containerStyle = {}, containerClassName = \"\"}) => {\n    \n    const navigate = useNavigate()\n    \n\n    const onCreateNewChat=()=>{\n        navigate(`${urlPrex}/${generateContextUUID()}/chat`)\n    }\n\n    function generateContextUUID() {\n            return uuidv4();\n    }\n\n    return (\n        <>\n            <div className={`${style.DashboardBody} ${containerClassName}`} >\n                \n                <div className={style.DashboardHeader}>\n                    <div className={style.DashboardTitleContainer}>\n                        {select ? (\n                            <div style={{width: '183px'}}>\n                                <Select\n                                    options={options}\n                                    value={selectedOption}\n                                    onChange={(value) => { setSelectedOption(value); onCreateNewChat()}}\n                                    noMargin={true}\n                                    placeholder={'Configuration'}\n                                    isSearchable={false}\n                                />\n                            </div>\n                        ) : ( \n                        <span className={style.DashboardTitle}>{title}</span> )}\n                    </div>\n                    <div>\n                    </div>\n                    <div>\n                        <a href=\"https://www.raggenie.com/\" target=\"_blank\"> <img className={style.DashboardHeaderIcon} src={help} /></a>\n                    </div>\n                </div>\n                <div className={`dashboard-loader-container ${style.LoaderContainer}`}>\n                    <span className={style.Loader}></span>\n                    <p className={`dashboard-loader-message ${style.LoaderMessage}`}>Getting Data</p>\n                </div>\n                <div className={style.DashboardChildrenBody} style={containerStyle}>\n                   \n                    {children}\n                </div>\n            </div>\n\n        </>\n    )\n}\n\nexport default DashboardBody"
  },
  {
    "path": "ui/src/layouts/dashboard/Dashboard.jsx",
    "content": "import {  Outlet, useNavigate} from \"react-router-dom\";\nimport { useEffect } from \"react\";\nimport useAppSettings from \"src/store/authStore\";\nimport style from \"./Dashboard.module.css\";\nimport SideMenu from \"./SideMenu\";\nimport { GetUserDetails } from \"src/services/Auth\";\nimport axios from \"axios\";\n\nconst DashboardLayout = () => {\n\n  const { username, setUsername, authEnabled, isAuthenticated, setIsAuthenticated, setAuthEnabled, setEnvID } = useAppSettings();\n\n  const navigate = useNavigate()\n\n  const fetchUserInfo = () => {\n    GetUserDetails().then((response) => {\n      const userData = response.data;\n      setUsername(userData.data.username);\n      setEnvID(userData.data.env_id)\n      setIsAuthenticated(true)\n      setAuthEnabled(userData.data.auth_enabled)\n    })\n      .catch((error) => {\n        if (error.response.status == 401) {\n          navigate(\"/login\")\n        }\n      });\n  };\n\n\n  useEffect(() => {\n    fetchUserInfo()\n  }, []);\n\n  return (\n    isAuthenticated && <div className={style.DashboardLayout}>\n      <div className={style.SideMenuContainer}>\n        <SideMenu username={username} authEnabled={authEnabled} />\n      </div>\n      <div className={style.DashboardBodyContainer}>\n        <Outlet />\n      </div>\n    </div>\n  );\n};\n\nexport default DashboardLayout;\n"
  },
  {
    "path": "ui/src/layouts/dashboard/Dashboard.module.css",
    "content": ".DashboardLayout {\n    display: flex;\n    width: 100vw;\n    height: 100vh;\n}\n\n.SideMenuContainer {\n    background-color: var(--neural-7);\n    min-width: 296px;\n    height: 100vh;\n}\n\n.SideMenu {\n    \n}\n\n.LogoContainer {\n    padding: 21px 20px;\n}\n\n.AppLogo {\n    width: 80px;\n    height: 18.127px;\n}\n\n.ProfileContainer {\n    cursor: pointer;\n    padding: 0px 17px 0px 17px;\n    margin: 7px 0px 17px 0px;\n}\n\n\n\n.ProfilePanel {\n    display: flex;\n    gap:6px;\n    display: flex;\n    gap: 6px;\n    padding: 10px 10px 6px 10px;\n\n}\n\n.ProfilePanel:hover {\n    background-color: var(--neural-5);\n    border-radius: 4px;\n}\n\n\n.UsernameDiv{\n    flex-grow: 1;\n    color: var(--neural-2);\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 300;\n    line-height: 150%;\n    margin-top: -2px;\n}\n\n\n.MenuContainer {\n    padding: 0px 17px;\n}\n\n.MenuList {\n    list-style: none;\n    color: var(--neural-2);\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 600;\n    line-height: 150%; \n    padding: 0px;\n}\n\n.MenuList a {\n   text-decoration: none;\n   \n}\n\n.MenuList a[aria-current=\"page\"] li {\n    background-color: var(--neural-5);\n}\n\n.MenuList li {\n    color: var(--neural-2);\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 300;\n    line-height: 150%;\n\n    cursor: pointer;\n    padding: 6px;\n    border-radius: 4px;\n    display: flex;\n    align-items: center;\n    gap: 6px;\n    margin-bottom: 4px\n}\n\n.MenuList li:hover {\n    background-color: var(--neural-5);\n}\n\n\n/* DashboardBody style */\n\n.DashboardBodyContainer {\n    flex-grow: 1;\n    width: calc(100vw - 245px);\n}\n\n.DashboardChildrenBody {\n    padding: 26px;\n    overflow: scroll;\n    height: calc(100vh - 120px);\n    /* width: calc(100vw - 348px); */\n}\n\n\n\n.DashboardChildrenBody::-webkit-scrollbar {\n    display: none;\n}\n\n.DashboardChildrenBody {\n  -ms-overflow-style: none; \n  scrollbar-width: none; \n}\n\n.DashboardHeader {\n    display: flex;\n    padding: 19px 26px 18px 26px;\n    border-bottom: 1px solid var(--neural-5);\n    align-items: center;\n    gap: 10px;\n}\n\n.DashboardTitleContainer {\n    flex-grow: 1;\n}\n\n.DashboardTitle {\n    color: var(--neural-1);\n    font-family: Inter;\n    font-size: 20px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 150%;\n}\n\n.DashboardHeaderIcon {\n    width: 22px;\n    height: 22px;\n    cursor: pointer;\n}\n\n.LoaderContainer {\n    background-color: #aea9a9;\n    width: calc(100% - 296px);\n    height: calc(100% - 69px);\n    opacity: 0.5;\n    position: absolute;\n    z-index: 1000;\n    display: none;\n}\n\n.Loader {\n    width: 48px;\n    height: 48px;\n    border: 3px dotted #3c3c3c;\n    border-style: solid solid dotted dotted;\n    border-radius: 50%;\n    display: inline-block;\n    position: relative;\n    box-sizing: border-box;\n    animation: rotation 2s linear infinite;\n    margin: auto;\n    display: block;\n    margin-top: 45vh;\n\n}\n  .Loader::after {\n    content: '';  \n    box-sizing: border-box;\n    position: absolute;\n    left: 0;\n    right: 0;\n    top: 0;\n    bottom: 0;\n    margin: auto;\n    border: 3px dotted #3992f7;\n    border-style: solid solid dotted;\n    width: 24px;\n    height: 24px;\n    border-radius: 50%;\n    animation: rotationBack 1s linear infinite;\n    transform-origin: center center;\n  }\n      \n  @keyframes rotation {\n    0% {\n      transform: rotate(0deg);\n    }\n    100% {\n      transform: rotate(360deg);\n    }\n  } \n  @keyframes rotationBack {\n    0% {\n      transform: rotate(0deg);\n    }\n    100% {\n      transform: rotate(-360deg);\n    }\n  } \n\n\n  .LoaderMessage {\n    text-align: center;\n    color: black;\n  }\n/* End of DashboardBody style */\n\n"
  },
  {
    "path": "ui/src/layouts/dashboard/SideMenu.jsx",
    "content": "import { useState } from \"react\";\nimport SideMenuRoutes from \"./SideMenuRoutes\";\nimport style from \"./Dashboard.module.css\";\nimport raggenieLogo from \"../../assets/logo/logo.svg\";\nimport userIcon from \"../../assets/icons/header-user-avatar.svg\";\nimport downArrowIcon from \"../../assets/icons/chevron-right.svg\";\nimport { NavLink, useNavigate } from \"react-router-dom\";\nimport userLogout from \"../../assets/icons/menu-icons/log-out.svg\";\nimport { AuthLogoutService } from \"src/services/Auth\";\nimport { toast } from \"react-toastify\";\nimport { storeToken } from \"src/store/authStore\";\n\nconst SideMenu = ({ username, authEnabled }) => {\n\n    const [isDropdownOpen, setIsDropdownOpen] = useState(false);\n    const navigate = useNavigate(); \n\n\n    const UserNameDetails = [\n        // {\n        //     action:\"profile\",\n        //     icon: userProfile,\n        //     title: \"Profile\"\n        // },\n        {\n            action:\"logout\",\n            icon: userLogout,\n            title: \"Logout\"\n        }\n    ];\n\n    const toggleDropdown = () => {\n        setIsDropdownOpen(!isDropdownOpen);\n    };\n\n    const onHandleClick = (action) => {\n        switch (action) {\n            case \"logout\":\n                AuthLogoutService().then((response) => {\n                    navigate(\"/login\");\n                    toast.success(response.data.message);\n                    storeToken(null) \n                }).catch((error) => {\n                    console.error(\"Logout failed:\", error); \n                });\n                break;\n            default:\n                break;\n        }\n    };\n    \n\n    return (\n        <div className={style.SideMenu}>\n            <div className={style.LogoContainer}>\n                <img src={raggenieLogo} className={style.AppLogo} />\n            </div>\n            <div className={style.ProfileContainer}>\n                <div className={style.ProfilePanel} onClick={toggleDropdown}>\n                    <div>\n                        <img src={userIcon} alt=\"User Icon\" />\n                    </div>\n                    <div className={style.UsernameDiv}>{username}</div>\n                    <div>\n                        <img src={downArrowIcon} alt=\"Arrow Icon\" />\n                    </div>\n                </div>\n\n                { authEnabled && isDropdownOpen && (\n                    <div className={style.DropdownMenu}>\n                        {UserNameDetails.map((item, index) => (\n                            <ul key={index} className={style.MenuList} onClick={() => onHandleClick(item.action)}>\n                                        <li className={style.menu}>\n                                            <img src={item.icon} alt={item.title} /> <span>{item.title}</span>\n                                        </li>\n                            </ul>\n                        ))}\n                    </div>\n                )}\n            </div>\n\n            <div className={style.MenuContainer}>\n                <ul className={style.MenuList}>\n                    {SideMenuRoutes.map((menu, index) => (\n                        <NavLink key={index} to={menu.path}>\n                            <li className={style.menu}>\n                                <img src={menu.icon} alt={menu.title} /> <span>{menu.title}</span>\n                            </li>\n                        </NavLink>\n                    ))}\n                </ul>\n            </div>\n        </div>\n    );\n};\n\nexport default SideMenu;\n"
  },
  {
    "path": "ui/src/layouts/dashboard/SideMenuRoutes.js",
    "content": "\nimport previewIcon from \"../../assets/icons/menu-icons/preview.svg\"\nimport configIcon from \"../../assets/icons/menu-icons/confiruration.svg\"\nimport samplesIcon from \"../../assets/icons/menu-icons/sample.svg\"\nimport deployIcon from \"../../assets/icons/menu-icons/deploy.svg\"\nimport pluginIcon from \"../../assets/icons/menu-icons/plugin.svg\"\nimport { v4 } from \"uuid\"\n\n const SideMenuRoutes = [\n\n    {\n        title: \"Preview\",\n        path: `/preview/${v4()}/chat`,\n        icon: previewIcon,\n    },\n    {\n        title: \"Configuration \",\n        path: \"/bot-configuration\",\n        icon: configIcon,\n    },\n    {\n        title: \"Plugins\",\n        path: \"/plugins\",\n        icon: pluginIcon,\n    },\n    {\n        title: \"Samples\",\n        path: \"/samples\",\n        icon: samplesIcon,\n    },\n    // {\n    //     title: \"Deploy\",\n    //     path: \"/deploy\",\n    //     icon: deployIcon,\n    // }\n  ]\n\n  export  default SideMenuRoutes\n"
  },
  {
    "path": "ui/src/layouts/errorPage/404.jsx",
    "content": "import React from 'react'\nimport { FaRegArrowAltCircleLeft } from 'react-icons/fa'\nimport Button from \"src/components/Button/Button\"\nimport style from './error.module.css'\nimport DashboardBody from 'src/layouts/dashboard/DashboadBody'\nimport { useNavigate } from 'react-router-dom'\nimport { v4 } from \"uuid\"\nimport errorImage from '../../assets/images/404.svg'\n\nconst NotFound = () => {\n    const navigate = useNavigate()\n    return (\n        <DashboardBody title=\"\">\n            <div className={style.error}>\n                <img src={errorImage}></img>\n                <div className={style.errorText}>\n                    <h3>So Sorry,</h3>\n                    <p>We couldn’t find what were you looking for...</p>\n                    <Button className={style.iconButton} onClick={() => navigate(`/preview/${v4()}/chat`)} ><FaRegArrowAltCircleLeft />Go Back</Button>\n                </div>\n            </div>\n        </DashboardBody>\n            );\n  };\n\n            export default NotFound;"
  },
  {
    "path": "ui/src/layouts/errorPage/500.jsx",
    "content": "import React from 'react'\nimport { FaRegArrowAltCircleLeft } from 'react-icons/fa'\nimport Button from \"src/components/Button/Button\"\nimport style from './error.module.css'\nimport DashboardBody from 'src/layouts/dashboard/DashboadBody';\nimport { useNavigate } from 'react-router-dom';\nimport { v4 } from \"uuid\"\nimport errorImage from '../../assets/images/500.svg'\n\nconst NotFound = () => {\n    const navigate = useNavigate()\n    return (\n        <DashboardBody title=\"\">\n            <div className={style.error}>\n                <img src={errorImage}></img>\n                <div className={style.errorText}>\n                    <h3>So Sorry, it's not you. it's us</h3>\n                    <p>We are expreincing internal server problem. Please try again later.</p>\n                    <Button className={style.iconButton} onClick={() => navigate(`/preview/${v4()}/chat`)} ><FaRegArrowAltCircleLeft />Go Back</Button>\n                </div>\n            </div>\n        </DashboardBody>\n    );\n};\n\nexport default NotFound;"
  },
  {
    "path": "ui/src/layouts/errorPage/error.module.css",
    "content": ".error {\n    border-radius: 8px;\n    background: #F5FAFF;\n    position: relative;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    height: 88vh; /* Or any desired height */\n    text-align: center;\n}\n\n.errorText{\n    \n    position: absolute;\n    top: 47%;\n    z-index: 1; /* Ensures text is above the SVG */\n\n}\n\n.errorText h3 {\n    color: var(--Light-mode-Neutral800, #32324D);\n    font-family: Inter;\n    font-size: 20px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 22px;\n    margin: 0;\n}\n\n.errorText p {\n    color: var(--Light-mode-Neutral800, #32324D);\n    font-feature-settings: 'liga' off, 'clig' off;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 22px;\n}\n\n.iconButton {\n    margin-top: 90px; /* Adjust space between text and button */\n    z-index: 1; /* Same z-index to stay above SVG */\n}"
  },
  {
    "path": "ui/src/layouts/general/GeneralLayout.jsx",
    "content": "\nimport style from \"src/layouts/dashboard/Dashboard.module.css\"\n\nconst GeneralLayout = ({children})=>{\n    return(\n        <>\n            <div className={`dashboard-loader-container ${style.LoaderContainer}`}>\n                <span className={style.Loader}></span>\n                <p className={`dashboard-loader-message ${style.LoaderMessage}`}>Getting Data</p>\n            </div>\n        <div>\n            {children}\n        </div>\n        </>\n    )\n}\n\nexport default GeneralLayout"
  },
  {
    "path": "ui/src/layouts/general/GeneralLayout.module.css",
    "content": ""
  },
  {
    "path": "ui/src/main.jsx",
    "content": "import ReactDOM from 'react-dom/client'\nimport App from './App.jsx'\nimport 'react-toastify/dist/ReactToastify.css';\nimport { BrowserRouter } from 'react-router-dom'\nimport { ToastContainer } from 'react-toastify';\nimport \"./global.css\"\n\nReactDOM.createRoot(document.getElementById('root')).render(\n  // <React.StrictMode>\n    <BrowserRouter basename=\"/ui\">\n        <App />\n        <ToastContainer/>\n    </BrowserRouter>\n  // </React.StrictMode>,\n)\n"
  },
  {
    "path": "ui/src/pages/Chat/Chat.jsx",
    "content": "import GeneralLayout from \"src/layouts/general/GeneralLayout\"\nimport PreviewChatBox from \"../Preview/ChatBox\"\nimport style from \"./Chat.module.css\"\nconst Chat = ()=>{ \n\n    return(\n        <>\n            <GeneralLayout>\n                <div className={style.ChatBody}>\n                    <div>\n                        <div className={style.ChatHeader}>\n                            <span className={style.ChatHeaderTitle}>Rag Assistant</span>\n                        </div>\n                    </div>\n                    <PreviewChatBox urlPrex=\"\"/>\n                </div>\n            </GeneralLayout>\n        </>\n    )\n}\n\nexport default Chat"
  },
  {
    "path": "ui/src/pages/Chat/Chat.module.css",
    "content": ".ChatBody {\n    height: calc(100vh - 67px);\n}\n\n.ChatHeader {\n    background: #FFF;\n    border-bottom: 1px solid #F0F0F0;\n    padding: 18px 26px;\n}\n\n.ChatHeaderTitle {\n    color: var(--neural-1);\n    font-family: Inter;\n    font-size: 20px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 150%; \n}"
  },
  {
    "path": "ui/src/pages/ChatConfiguration/Capability/Capability.jsx",
    "content": "\n\nimport { IoIosArrowDown, IoIosArrowUp } from \"react-icons/io\";\nimport { GoPencil } from \"react-icons/go\";\nimport { LuTrash2 } from \"react-icons/lu\";\nimport { FiCheckCircle} from \"react-icons/fi\"\nimport style from \"./Capability.module.css\"\nimport Button from \"src/components/Button/Button\";\nimport Input from \"src/components/Input/Input\";\nimport Textarea from \"src/components/Textarea/Textarea\";\nimport { GoPlus } from \"react-icons/go\"\nimport { useEffect, useState } from \"react\";\n\n\nconst Capability = ({capabilityId = \"\", capabilityIndex = 0, title = \"\", name = \"\", description = \"\", parameters = [], isCollapse= true, onCapabilitySave = ()=>{}, onCapabilityDelete = ()=>{}, onParamEdit=()=>{}, onParamDelete = ()=>{}, onCreateNewParam = ()=>{}})=>{\n\n    const [expand, setExpand] = useState(true)\n    const [capabilityLitle, setCapabilityLitle] = useState(title)\n\n    const onDeleteCapability = ()=> {\n        let capabilityContainer = document.querySelector(`[data-capability-index='${capabilityIndex}']`)\n        capabilityContainer.remove()\n        onCapabilityDelete(capabilityIndex, capabilityId)\n    }\n\n    const onCreateNewParamClick = ()=>{\n        onCreateNewParam(capabilityId, capabilityIndex)\n    }\n\n    const onFormSubmit = (e)=>{\n        e.preventDefault()\n        var data = new FormData(e.target);\n        onCapabilitySave(data)\n    }\n\n    useEffect(()=>{\n        setExpand(isCollapse)\n    },[isCollapse])\n\n\n    return(\n        <>\n            <form onSubmit={onFormSubmit}>\n                <div data-capability-index={`${capabilityIndex}`} data-capability-id={`${capabilityId}`} className={`${style.CapabilityContainer} ${expand == false ? \"\" : style.CapabilityContainerCollapse}`}>\n                    <div className={style.CapabilityHeader}>\n                        <div onClick={()=>setExpand(!expand)} style={{cursor: \"pointer\"}}> {expand == false ? <IoIosArrowUp/> : <IoIosArrowDown/>} </div>\n                        <div className={`flex-grow-1 ${style.CapabilityTitle}`}>\n                            {capabilityLitle}\n                        </div>\n                        <div> \n                            <Button variant=\"secondary-danger\" className=\"icon-button\" onClick={onDeleteCapability}  style={{marginRight: \"10px\"}}>Delete <LuTrash2/></Button> \n                            { !expand && <Button buttonType=\"submit\" className=\"icon-button\" >Save  <FiCheckCircle/></Button>}\n                        </div>\n                    </div>\n                    <div>\n                        <div className={style.CapabilityDetailsContainer}>\n                            <Input type=\"hidden\" name=\"capability-id\" value={capabilityId}  />\n                            <Input label=\"Capability Name\" name=\"capability-name\" value={name}  onChange={(e)=>setCapabilityLitle(e.target.value)} />\n                            <Textarea label=\"Description\" name=\"capability-description\" value={description} rows={8}/>\n                        </div>\n                    </div>\n\n                    <div className={style.CapabilityParamsBody}>\n                        <div className={style.CapabilityParamsHeader}>\n                            <div className={`flex-grow-1 ${style.CapabilityTitle}`}>\n                                Create Parameters for Capability\n                            </div>\n                            <div> \n                                <Button variant=\"secondary\" className=\"icon-button\" onClick={onCreateNewParamClick}>Create New Parameter <GoPlus/></Button> \n                            </div>\n                        </div>\n                        <div>\n                            <table className={style.CapabilityParamsTable}>\n                                <thead>\n                                    <tr>\n                                        <th className={style.CapabilityParamsTableHeader} style={{width: \"250px\"}}>Name</th>\n                                        <th className={style.CapabilityParamsTableHeader}>Description</th>\n                                    </tr>\n                                </thead>\n                                <tbody key={\"tbody\"}>\n                                {parameters?.map((item, index)=>{\n                                    return(\n                                        <>\n                                            <tr key={index}>\n                                                <td className={style.CapabilityParamsTableColumn}>\n                                                    <Input type=\"hidden\" name=\"params-id[]\" value={item.parameter_id} />\n                                                    <Input type=\"hidden\" name=\"params-name[]\" value={item.parameter_name} />\n                                                    {item.parameter_name}\n                                                </td>\n                                                <td className={style.CapabilityParamsTableColumn}>\n                                                    <Input type=\"hidden\" name=\"params-description[]\" value={item.parameter_description} />\n                                                    {item.parameter_description}\n                                                    <span style={{float: \"right\"}}>\n                                                        <GoPencil size={20} color=\"#3893FF\" onClick={()=>onParamEdit(capabilityIndex, item)} style={{marginRight: \"23px\"}}/>\n                                                        <LuTrash2 size={20} color=\"#FF7F6D\" onClick={()=>onParamDelete(capabilityIndex, index, item)}/>\n                                                    </span>\n                                                </td>\n                                            </tr>\n                                        </>\n                                    )\n                                })}\n                                </tbody>\n                            </table>\n                        </div>\n                    </div>\n                </div>\n            </form>\n        </>\n    )\n}\n\n\nexport default Capability"
  },
  {
    "path": "ui/src/pages/ChatConfiguration/Capability/Capability.module.css",
    "content": "\n.CapabilityContainer {\n    background-color: var(--neural-7);\n    padding: 17px 15px;\n    overflow: hidden;\n    margin-bottom: 11px;\n}\n\n.CapabilityContainerCollapse {\n    height: 29px;\n}\n\n.CapabilityHeader {\n    display: flex;\n    gap: 15px;\n    align-items: center;\n}\n\n.CapabilityTitle {\n    color: #323232;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 20px\n}\n\n.CapabilityDetailsContainer {\n    padding: 21px 20px;\n}\n\n.CapabilityParamsBody {\n    padding: 21px 20px;\n}\n\n\n\n.CapabilityParamsHeader {\n    display: flex;\n    gap: 15px;\n    align-items: center;\n}\n\n.CapabilityParamsTable {\n    display: table;\n}\n\n\n.CapabilityParamsTableHeader{\n    text-align: left;\n    font-family: \"Inter\";\n    text-transform: uppercase;\n    color: var(--neural-3);\n    font-size: 11px;\n    font-weight: 600;\n    border-bottom: 1px solid #EFEFEF;\n    padding: 20px;\n    \n}\n\n.CapabilityParamsTable{\n    width: 100%;\n    cursor: pointer;\n}\n\n.CapabilityParamsTableColumn {\n    color: var(--neural-1);\n    font-family: \"Inter\";\n    font-size: 14px;\n    font-weight: 400;\n    border-bottom: 1px solid #EFEFEF;\n    padding: 20px;\n}\n\n\n.capabilityParamsRow {\n    display: table-row;\n}\n\n.capabilityParamsColumn{\n    display: table-column;\n}\n"
  },
  {
    "path": "ui/src/pages/ChatConfiguration/ChatConfiguration.jsx",
    "content": "\nimport DashboardBody from \"src/layouts/dashboard/DashboadBody\"\nimport EmptyConfiguration from \"./EmptyConfiguration\"\nimport ConfigurationList from \"./ConfigurationList\"\nimport { useEffect, useState } from \"react\"\nimport { useNavigate } from 'react-router-dom';\nimport { toast } from \"react-toastify\"\nimport { deleteBotConfiguration, getBotConfiguration } from \"src/services/BotConfifuration\";\n\nconst ChatConfigurationMain = ()=>{\n\n    const navigate = useNavigate()\n    const [configurationList, setConfigurationList] = useState([])\n\n    const loadConfigurations = ()=>{\n       getBotConfiguration().then(response=>{\n            setConfigurationList(response.data.data.configurations ?? [])\n       }).catch(() => {\n        navigate('/error')\n    })\n    }\n\n\n    const onConfigurationDelete = (configId)=>{\n        deleteBotConfiguration(configId).then(response=>{\n            if(response.data.status == true){\n                toast.success(\"Configuration Deleted\")\n                loadConnectors()\n            }else{\n                toast.error(\"Opps something went wrong\")\n            }\n        })\n    }\n\n\n    useEffect(()=>{\n        loadConfigurations()\n    }, [])\n\n    \n    return(\n        <DashboardBody title=\"Bot Configuration\">\n                {configurationList?.length === 0  && <EmptyConfiguration/>}\n                {configurationList?.length > 0  && <ConfigurationList configurations={configurationList} onConfigDelete={onConfigurationDelete}/>}\n                \n        </DashboardBody>\n    )\n}\n\nexport default ChatConfigurationMain\n"
  },
  {
    "path": "ui/src/pages/ChatConfiguration/ChatConfiguration.module.css",
    "content": ".ActionDiv {\n    border-radius: 8px;\n    background: var(--neural-7);\n    padding: 17px 16px;\n    display: flex;\n}\n\n\n.ConfigHeading{\n    color: #323232;\n    font-feature-settings: 'liga' off, 'clig' off;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    line-height: 20px; /* 125% */\n    margin: 0;\n    margin-bottom: 10px;\n}\n\n.ConfigDescription{\n    color: #888787;\n    font-feature-settings: 'liga' off, 'clig' off;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px; /* 142.857% */\n    margin-bottom: 30px;\n}\n\n.SaveConfigContainer {\n    bottom: 20px;\n    border-radius: var(--8, 8px);\n    background: #F9F9F9;\n    height: auto;\n    bottom: 20px;\n    padding: 17px 19px 18px 16px;\n    align-content: space-around;\n    justify-content: space-between;\n}\n\n.ConfigSaveContainer{\n    text-align: right;  \n}\n\n.InferenceSaveContainer {\n    display: flex;\n}\n\n.BackButton{\n    font-size: 14px;\n}\n\n.DropdownHead{\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px;\n    margin: 0px;\n    display: block;\n}\n\n.AlignDropdownOptions{\n    display: flex;\n    align-items: center;\n    justify-items: center;\n    gap: 8px;\n}\n\n.LLMDropdownOptionImg{\n    width: 25px;\n    height: 25px;\n}\n\n\n\n.ToastContainerClass {\n    min-width: 640px;;\n    position: absolute;\n    right: 330px;\n    border-radius: 4px;\n    border: 1px solid var(--Light-mode-Primary200, #D9D8FF);\n    background: var(--Light-mode-Primary100, #F0F0FF);\n}\n\n.BotRestartToast {\n    display: flex;\n    align-items: center;\n    justify-items: center;\n}\n\n.BotRestartMessage {\n   flex-grow: 1;\n    color: #32324D;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 500;\n    display: flex;\n    align-items: center;\n    justify-items: center;\n    gap: 10px;\n}\n.CustomBotCloseButton{\n    background: transparent;\n    outline: none;border: none;\n}\n\n.VectorContainer{\n    display: flex;\n    justify-content: center;\n    align-content: center;\n    align-items: center;\n    padding-top: 85px;\n    flex-direction: column;\n}\n.VectorContent{\n    max-width: 572px;\n    text-align: center;\n}\n.VectorControls{\n    max-width: 572px; \n    gap: 10px;\n    display:flex;\n    justify-content: center;\n    align-items: center;\n    margin-top: 20px;\n}\n\n.SaveVectorContainer {\n    bottom: 20px;\n    border-radius: var(--8, 8px);\n    background: #F9F9F9;\n    height: auto;\n    bottom: 20px;\n    padding: 17px 19px 18px 16px;\n    align-content: space-around;\n    justify-content: space-between;\n}\n\n.VectorSaveContainer {\n    display: flex;\n}\n.VectorFields{\n    display: flex;\n    flex-grow: 1;\n    flex-direction: column;\n}\n.VectorFormContainer{\n    display: flex;\n    flex-direction: column;\n}"
  },
  {
    "path": "ui/src/pages/ChatConfiguration/ChatConfigurationForm.jsx",
    "content": "import { useEffect, useRef, useState } from 'react';\nimport { useNavigate, useParams } from \"react-router-dom\"\nimport Input from 'src/components/Input/Input';\nimport Tab from 'src/components/Tab/Tab';\nimport Tabs from 'src/components/Tab/Tabs';\nimport Textarea from 'src/components/Textarea/Textarea';\nimport DashboardBody from 'src/layouts/dashboard/DashboadBody';\nimport style from './ChatConfiguration.module.css';\nimport { useForm, Controller } from \"react-hook-form\"\nimport Button from \"src/components/Button/Button\"\nimport { FaArrowLeft } from 'react-icons/fa6';\nimport { LiaToolsSolid } from \"react-icons/lia\";\nimport { FiCheckCircle, FiXCircle } from \"react-icons/fi\"\nimport { GoPlus } from \"react-icons/go\"\nimport { FaRegArrowAltCircleRight } from 'react-icons/fa';\nimport { API_URL, BACKEND_SERVER_URL } from 'src/config/const';;\nimport Select from 'src/components/Select/Select';\nimport { toast } from 'react-toastify';\nimport { v4 as uuid4 } from \"uuid\"\nimport Capability from './Capability/Capability';\nimport Modal from 'src/components/Modal/Modal';\nimport { deleteBotCapability, saveBotCapability, updateBotCapability } from 'src/services/Capability';\nimport { getBotConfiguration, getBotConfigurationById, getLLMProviders, getVectorDBList, saveBotConfiguration, saveBotInferene, saveVectorDB, testInference, testVectorDB} from 'src/services/BotConfifuration';\nimport NotificationPanel from 'src/components/NotificationPanel/NotificationPanel';\nimport PostService from 'src/utils/http/PostService';\nimport ToastIcon from \"./assets/ToastIcon.svg\"\nimport { RiRestartLine } from 'react-icons/ri';\nimport { IoMdClose } from 'react-icons/io';\nimport VectorEmpty from \"./assets/vectorEmpty.svg\"\nimport cromaDbIcon from \"./assets/cromdbpng.png\"\nimport pencilIcon from \"./assets/pencil02.svg\"\nimport TitleDescription from 'src/components/TitleDescription/TitleDescription';\nimport GenerateConfigs from 'src/utils/form/GenerateConfigs';\nimport { getConnectors } from \"src/services/Connectors\"\nimport Deploy from '../Deploy/Deploy';\n\n\nconst BotConfiguration = () => {\n\n    const [connectors, setConnectors] = useState([]);\n    const [selectedOptions, setSelectedOptions] = useState([]);\n    const [currentConfigID, setCurrentConfigID] = useState(undefined)\n    const [currentInferenceID, setCurrentInferenceID] = useState(undefined)\n    const [disabledInferenceSave, setDisabledInferenceSave] = useState(true)\n    const [showNotificationPanel, setShowNotificationPanel] = useState(false)\n    const [notificationMessage, setNotificationMessage] = useState(\"\")\n\n    const [activeInferencepiontTab, setActiveInferencepiontTab] = useState(true)\n    const [activeTab, setActiveTab] = useState(\"configuration\")\n    const [selectedProvider, setSelectedProvider] = useState()\n    const [capabalities, setCapabalities] = useState([])\n\n    const [llmModels, setllmModels] = useState([])\n    const [vectordbId,setVectorDbID] = useState()\n\n    const [editCapabilityIndexRef, setEditCapabilityIndexRef] = useState(\"\")\n    const [editParamsIdRef, setEditParamsIdRef] = useState(\"\")\n\n    const editParamsNameRef = useRef(\"\");\n    const editParamsDesc = useRef(\"\")\n\n    const [showParamsModal, setShowParamsModal] = useState(false)\n    let [currentEditParamsNameError, setCurrentEditParamsNameError] = useState({ hasError: false, errorMessage: \"\" })\n    let [currentEditParamsDescError, setCurrentEditParamsDescError] = useState({ hasError: false, errorMessage: \"\" })\n\n    //-----------------VECTORDB---------------------------------\n    const [disabledVectorDbSave, setDisabledVectorDbSave] = useState(true);\n    const [showVectorDbForm, setshowVectorDbForm] = useState(false)\n    const [vectorDB, setVectorDB] = useState([]);\n    const [selectedVectordb, setSelectedVectordb] = useState()\n\n\n    const { register: configRegister, setValue: configSetValue, handleSubmit: configHandleSubmit, formState: configFormState, setError: configSetError, clearErrors: configClearErrors, watch: configWatch } = useForm({ mode: \"all\" })\n    const { errors: configFormError, } = configFormState\n\n    const { register: inferenceRegister, getValues: inferenceGetValues, setValue: inferenceSetValue, handleSubmit: inferenceHandleSubmit, formState: inferenceFormState, control: inferenceController, trigger: inferenceTrigger, watch: inferenceWatch } = useForm({ mode: \"all\" })\n    const { errors: inferenceFormError } = inferenceFormState\n\n    const { register: vectorDbRegister, getValues: vectorDbGetValues, setValue: vectorDbSetValue, reset: vectorDbReset, handleSubmit: vectorDbHandleSubmit, formState: vectorDbFormState, trigger: vectorDbTrigger, control: vectorDbController } = useForm({ mode: \"all\" })\n    const { errors: vectorDbFormError } = vectorDbFormState\n\n    const navigate = useNavigate()\n    const { configId } = useParams();\n    \n    const toastRestartBot=()=>{\n        toast(\n            <ToastMessage message={<>Please restart the bot to get changes to take effect.</>} />,\n            {\n              toastId: \"RAG001\", \n              autoClose: 60000, // 5 minutes in milliseconds\n              hideProgressBar: true,\n              className: style.ToastContainerClass,\n              closeButton: <ToastCloseButton />,\n            }\n          );\n    } \n\n    const ToastCloseButton = ({ closeToast }) => {\n        return (\n          <button className={style.CustomBotCloseButton} onClick={closeToast}>\n            <IoMdClose size={18} />\n          </button>\n        );\n      };\n\n\n    const ToastMessage = ({ message}) => {\n        return (\n                <div className={style.BotRestartToast}>\n                <span className={style.BotRestartMessage}><img src={ToastIcon} alt=\"toasticon\"/>{message}</span>\n                <Button onClick={restartChatBot}>\n                    Restart Chatbot  <RiRestartLine size={24}/>\n                </Button>\n            </div>\n        );\n      };\n      \n\n      const restartChatBot = () => {\n        toast.dismiss(\"RAG001\"); \n        PostService(API_URL + `/connector/createyaml/${currentConfigID}`, {}, { loaderText: \"Restarting Chatbot\" })\n          .then(() => {\n            toast.success(\"Bot Restarted Successfully\");\n          })\n          .catch(() => {\n            toast.error(\"Failed to restart bot\");\n          });\n      };\n      \n      const onBotConfigSave = (data) => {\n        const transformedData = {\n            ...data,\n            connectors: data.connectors.map(connector => parseInt(connector.value))\n          };\n        saveBotConfiguration(currentConfigID, transformedData)\n          .then((response) => {\n            toast.success(\"Configuration Saved Successfully\")\n            setCurrentConfigID(response.data.data.configuration.id);\n            if(currentInferenceID != undefined){\n                toastRestartBot()\n            }\n            setActiveTab(\"inferenceendpoint\")\n          })\n          .catch(() => {\n            toast.error(\"Configuration failed to save\");\n          });\n      };\n      \n\n    const getCurrentConfig = (llmsList, vectorDbTempList) => {\n        if(configId){\n            getBotConfigurationById(configId).then(response => {\n                let configs = response.data?.data?.configuration\n                setActiveInferencepiontTab(false)\n                setCurrentConfigID(configs.id)\n                setCurrentInferenceID(configs.inference[0]?.id ?? undefined)\n                setVectorDbID(configs.vectordb[0]?.id ?? undefined)\n\n                configSetValue(\"botName\", configs.name, { shouldValidate: true, shouldTouch: true })\n                configSetValue(\"botShortDescription\", configs.short_description)\n                configSetValue(\"botLongDescription\", configs.long_description)\n\n                if (configs.connector?.length > 0) {\n                    const selectedConnectors = configs.connector.map(connector => ({\n                        label: connector.connector_name, // Get name from nested object\n                        value: connector.connector_id // Get ID from nested object\n                    }));\n                    configSetValue(\"connectors\", selectedConnectors);\n                }\n\n                let tempSelectedCapabilities = [];\n                configs.capabilities.map(cap => {\n                    tempSelectedCapabilities.push({ value: cap.id, label: cap.name })\n                })\n                setSelectedOptions(tempSelectedCapabilities)\n\n\n                if (configs.capabilities?.length > 0) {\n                    setCapabalities(configs.capabilities)\n                }\n\n                if (configs.inference[0]?.id) {\n                    let inference = configs.inference[0];\n                    inferenceSetValue(\"inferenceName\", inference.name)\n                    inferenceSetValue(\"inferenceModelName\", inference.model)\n                    inferenceSetValue(\"inferenceEndpoint\", inference.endpoint)\n                    inferenceSetValue(\"inferenceAPIKey\", inference.apikey)\n\n\n                    let tempSelectedProvider = llmsList.find(item => item.value == inference.llm_provider)\n\n                    setSelectedProvider(tempSelectedProvider)\n\n                }\n                \n                if (configs.vectordb[0]?.id) {\n                    let vectordb = configs.vectordb[0];\n                    setshowVectorDbForm(true)\n                    for (const configKey in vectordb.vectordb_config) {\n                        vectorDbSetValue(configKey, vectordb.vectordb_config[configKey]);\n                    }\n                    let tempVectorDb = vectorDbTempList.find(item => item.value == vectordb.vectordb)\n                    setSelectedVectordb(tempVectorDb)                                      \n                }\n        \n                \n            })\n        }\n        else {\n            getBotConfiguration().then(response => {\n                let configs = response.data?.data?.configurations\n                if (configs[0].inference[0]?.id) {\n                    let inference = configs[0].inference[0];\n                    inferenceSetValue(\"inferenceName\", inference.name)\n                    inferenceSetValue(\"inferenceModelName\", inference.model)\n                    inferenceSetValue(\"inferenceEndpoint\", inference.endpoint)\n                    inferenceSetValue(\"inferenceAPIKey\", inference.apikey)\n    \n    \n                    let tempSelectedProvider = llmsList.find(item => item.value == inference.llm_provider)\n    \n                    setSelectedProvider(tempSelectedProvider)\n    \n                }\n    \n                    })\n        }\n    }\n\n\n    const getLLMModels = async () => {\n        getLLMProviders().then(response => {\n            var llmProviders = response.data.data?.providers\n            let llmList = []\n            let vectorDbTempList = [];\n            llmProviders.map(item => {\n                llmList.push({ value: item.unique_name, label: <div className={style.AlignDropdownOptions}><img className={style.LLMDropdownOptionImg} src={`${BACKEND_SERVER_URL}${item.icon}`} alt={item.display_name} />{item.display_name}</div> },)\n            })\n            setllmModels(llmList)\n            setSelectedProvider(llmList[0])\n\n//call vectordb list api\n            getVectorDBList().then(response => {\n                const vectorDbs = response.data.data.vectordbs;\n                vectorDbs.map((item) => {\n                    vectorDbTempList.push({\n                        label: (\n                            <div style={{ display: \"flex\", alignItems: \"center\" }}>\n                            <img src={`${BACKEND_SERVER_URL}` + item.icon} alt={item.name} style={{ marginRight: '8px' }} />\n                            {item.name}\n                        </div>\n                        ),\n                        value: item.key,\n                        config: item.config,\n                    });\n                });\n                setVectorDB(vectorDbTempList);  \n                getCurrentConfig(llmList, vectorDbTempList)\n          \n            });\n\n        }).catch(() => {\n            navigate('/error')\n        })\n    }\n\n\n\n\n\n//function for testing the vector db\n    const onTestVectorDb = () => {\n        vectorDbTrigger().then((result) => {\n            if (result) {\n                const vectordbConfig = {\n                    key: selectedVectordb?.value.toLowerCase()\n                };\n\n                for (const configItem of selectedVectordb.config) {                   \n                    vectordbConfig[configItem.slug] = vectorDbGetValues(configItem.slug); \n                }\n                testVectorDB({\n                    \"vectordb_config\": vectordbConfig,\n                    // \"embedding_config\": embeddingConfig\n                }).then(() => {   \n                    toast.success(\"Vectordb Tested Successfully\");\n                    setShowNotificationPanel(false);\n                    setDisabledVectorDbSave(false);\n                }).catch(err => {\n                    toast.error(\"Inference endpoint verification failed\")\n                    setShowNotificationPanel(true);\n                    setNotificationMessage(err.data?.error ?? \"Vector database endpoint verification failed\")\n                });\n            }\n        });\n    };\n\n\n//function for testing the inference\nconst onTestInference = () => {\n        inferenceTrigger().then((result) => {\n            if (result) {\n                testInference(currentConfigID, {\n                    \"inferenceName\": inferenceGetValues(\"inferenceName\"),\n                    \"inferenceAPIKey\": inferenceGetValues(\"inferenceAPIKey\"),\n                    \"inferenceLLMProvider\": selectedProvider.value,\n                    \"inferenceModelName\": inferenceGetValues(\"inferenceModelName\"),\n                    \"inferenceEndpoint\": inferenceGetValues(\"inferenceEndpoint\"),\n                }).then(() => {\n                    toast.success(\"Inference Tested Successfully\")\n                    setShowNotificationPanel(false);\n                    setDisabledInferenceSave(false)\n                }).catch(err => {\n                    toast.error(\"Inference endpoint verification failed\")\n                    setShowNotificationPanel(true);\n                    setNotificationMessage(err.data?.error ?? \"Inference endpoint verification failed\")\n                });\n            }\n\n        })\n    }\n\n   \n\nconst onInferanceSave = (data) => {\n        configClearErrors(\"inferenceProvider\")\n        if (selectedProvider == undefined) {\n            configSetError(\"inferenceProvider\", { type: \"required\", message: \"This field is required\" });\n            return\n        }\n        data[\"inferenceLLMProvider\"] = selectedProvider.value\n        saveBotInferene(currentConfigID, currentInferenceID, data).then(() => {\n            toast.success(\"Inference Saved Successfully\")\n            toastRestartBot()\n            setShowNotificationPanel(false);\n            setActiveTab('vectordbtab')\n        })\n            .catch((err) => {\n                setShowNotificationPanel(true);\n                setNotificationMessage(err.data?.error)\n                toast.error(\"Failed to save inference\")\n            });\n    }\n\n\n    const addNewCapability = () => {\n        let tempCapabalities = JSON.parse(JSON.stringify(capabalities))\n        tempCapabalities.push({\n            id: undefined, title: `Capability ${tempCapabalities.length + 1}`, name: \"\", description: \"\", requirements: []\n        })\n        setCapabalities(tempCapabalities)\n    }\n\n\n    const onSaveCapability = (formData) => {\n\n        let capabilityId = formData.get(\"capability-id\")\n        let paramsIds = formData.getAll(\"params-id[]\")\n        let paramsNames = formData.getAll(\"params-name[]\")\n        let paramsDescs = formData.getAll(\"params-description[]\")\n        let requirements = [];\n\n        paramsIds?.map((item, index) => {\n            requirements.push({\n                parameter_id: item,\n                parameter_name: paramsNames[index],\n                parameter_description: paramsDescs[index]\n            })\n        })\n\n\n        if (requirements.length == 0) {\n            toast.error(\"Parameter is missing\");\n            return\n        }\n\n\n        if (capabilityId == \"\") {\n            saveBotCapability(currentConfigID, formData.get(\"capability-name\"), formData.get(\"capability-description\"), requirements).then(response => {\n                toast.success(\"Capability Saved Successfully\")\n            }).catch(() => {\n                toast.error(\"Capability save failed\")\n            })\n\n        } else {\n            updateBotCapability(capabilityId, currentConfigID, formData.get(\"capability-name\"), formData.get(\"capability-description\"), requirements).then(response => {\n                toast.success(\"Capability Updated Successfully\")\n            }).catch(() => {\n                toast.error(\"Capability update failed\")\n            })\n        }\n\n    }\n\n    const deleteCapability = (capabilityIndex, capabilityId) => {\n        deleteBotCapability(capabilityId).then(() => toast.success(\"Capability Deleted Successfully\")).catch(() => toast.error(\"Capability Deletion Failed\"))\n    }\n\n    const onClickNewParams = (capabilityId, capabilityIndex) => {\n        // editCapabilityIndexRef.current.value = capabilityIndex\n        setEditCapabilityIndexRef(capabilityIndex)\n        setShowParamsModal(true)\n    }\n\n    const addNewParameter = () => {\n\n        setCurrentEditParamsNameError({ hasError: false, errorMessage: \"\" })\n        setCurrentEditParamsDescError({ hasError: false, errorMessage: \"\" })\n        if (editParamsNameRef.current.value == \"\" || editParamsDesc.current.value == \"\") {\n            if (editParamsNameRef.current.value == \"\") {\n                setCurrentEditParamsNameError({ hasError: true, errorMessage: \"This field is required\" })\n            }\n\n            if (editParamsDesc.current.value == \"\") {\n                setCurrentEditParamsDescError({ hasError: true, errorMessage: \"This field is required\" })\n            }\n\n            return\n        }\n\n        capabalities?.map((item, index) => {\n\n            if (index == editCapabilityIndexRef) {\n                let hasParam = item.requirements?.some(params => params.parameter_id == editParamsIdRef)\n                if (hasParam) {\n                    item.requirements?.map(params => {\n                        if (params.parameter_id == editParamsIdRef) {\n                            params.parameter_name = editParamsNameRef.current.value;\n                            params.parameter_description = editParamsDesc.current.value;\n                        }\n                    })\n                } else {\n                    item.requirements?.push({\n                        parameter_id: editParamsIdRef == \"\" ? uuid4() : editParamsIdRef,\n                        parameter_name: editParamsNameRef.current.value,\n                        parameter_description: editParamsDesc.current.value\n\n                    })\n                }\n\n            }\n        })\n        editParamsNameRef.current.value = \"\"\n        editParamsDesc.current.value = \"\"\n        toast.success(\"New parameter added\")\n    }\n\n    const editParameter = (capabalityIndex, parameters) => {\n\n        setEditCapabilityIndexRef(capabalityIndex)\n        setEditParamsIdRef(parameters.parameter_id)\n        editParamsNameRef.current.value = parameters.parameter_name\n        editParamsDesc.current.value = parameters.parameter_description\n\n        setShowParamsModal(true)\n\n\n    }\n\n    const deleteParameter = (capabilityIndex, paramsIndex, item) => {\n        let tempCapabalities = JSON.parse(JSON.stringify(capabalities))\n        tempCapabalities[capabilityIndex].requirements.splice(paramsIndex, 1)\n        setCapabalities(tempCapabalities)\n    }\n\n    const resetTestInference = () => {\n        setDisabledInferenceSave(true)\n    }\n\n    const loadDbBasedForm = (configVectorDb) => {        \n        return (\n            <>\n                <GenerateConfigs\n                    register={vectorDbRegister}\n                    errors={vectorDbFormError}\n                    configs={configVectorDb}\n                    restForm={()=>{ setDisabledVectorDbSave(true);}}\n                />\n            </>\n        )\n\n    };\n\n    const onClickChangeVectorDB = () => {\n        setshowVectorDbForm(!showVectorDbForm)\n\n    }\n    //on changing vector db select the\n    const handleDatabaseChange = (selectedDb) => {  \n        vectorDbReset()      \n        setDisabledVectorDbSave(true);\n        setSelectedVectordb(selectedDb);\n        \n    };\n\n\n    const vectorDbSave = () => {\n        let saveData = {};\n\n        if (selectedVectordb) {\n            const vectordbConfig = {};\n            for (const configItem of selectedVectordb.config) {\n                const slug = configItem.slug;\n                vectordbConfig[slug] = vectorDbGetValues ? vectorDbGetValues(slug) : selectedVectordb[slug];\n            }\n            saveData = {\n                vectordb: selectedVectordb.value,\n                vectordb_config: vectordbConfig,\n                config_id: currentConfigID,\n                embedding_config: null\n            };\n        }\n        saveVectorDB(vectordbId, saveData).then(() => {\n            toast.success(\"VectorDB Saved Successfully\")\n            toastRestartBot()\n            setShowNotificationPanel(false);            \n            setActiveTab('capabalities')\n            \n        })\n            .catch((err) => {\n                setShowNotificationPanel(true);\n                setNotificationMessage(err.data?.error)\n                toast.error(\"Failed to save vectordb\")\n            });\n    };\n\n\n\n    useEffect(() => {\n        getLLMModels();\n        getConnectorsList();\n    }, [])\n\n    const getConnectorsList = async () => {\n        getConnectors().then(response => {\n            const connectorResponse = response.data.data?.connectors || [];\n            let connectorList = []\n            connectorResponse.map(item => {\n                connectorList.push({ value: item.connector_id, label:  <div className={style.AlignDropdownOptions}>{item.connector_name}</div>})\n            })\n\n            setConnectors(connectorList);\n        }).catch(() => {\n            navigate('/error');\n        });\n    }\n\n    const addConfiguration = () => {\n        navigate('/plugins')\n    }\n    \n\n\n    return (\n        <DashboardBody title=\"Bot Configuration\">\n            <Tabs activeTab={activeTab}>\n\n                {/* ==============Configuration tab==================*/}\n                <Tab title=\"Configuration\" tabKey=\"configuration\">\n                    <h3 className={style.ConfigHeading}>Bot Configuration details</h3>\n                    <p className={style.ConfigDescription}>Provide your database connection details and database data description can make your application more efficient.</p>\n                    <form onSubmit={configHandleSubmit(onBotConfigSave)}>\n                        <div>\n                            <Input\n                                label=\"Bot Configuration Name\"\n                                maxLength={50}\n                                value={configWatch(\"botName\")}\n                                hasError={configFormError[\"botName\"]?.message ? true : false}\n                                errorMessage={configFormError[\"botName\"]?.message}\n                                {...configRegister(\"botName\", {\n                                    required: \"This field is required\",\n                                    maxLength: {\n                                        value: 50,\n                                        message: \"The maximum length is 50 characters\"\n                                    },\n                                    minLength: {\n                                        value: 10,\n                                        message: \"The minimum length is 20 characters\"\n                                    }\n                                })}\n                            />\n                            <Input label=\"Bot Short Description\" placeholder=\"brief detail about the use case of the bot\" minLength={20} maxLength={200} value={configWatch(\"botShortDescription\")} hasError={configFormError[\"botShortDescription\"]?.message ? true : false} errorMessage={configFormError[\"botShortDescription\"]?.message}  {...configRegister(\"botShortDescription\", { required: \"This field is required\", minLength: { value: 20, message: \"minimun length is 20\" }, maxLength: { value: 200, message: \"maximum length is 200\" } })} />\n                            <Textarea label=\"Bot Long Description\" placeholder=\"detailed information about the bot, including its full use case and functionalities\" rows={10} minLength={50} maxLength={400} value={configWatch(\"botLongDescription\")} hasError={configFormError[\"botLongDescription\"]?.message ? true : false} errorMessage={configFormError[\"botLongDescription\"]?.message}  {...configRegister(\"botLongDescription\", { required: \"This field is required\", minLength: { value: 50, message: \"minimun length is 50\" }, maxLength: { value: 400, message: \"maximum length is 400\" } })} />\n                            <Select\n                                label=\"Select Source\"\n                                isMulti\n                                options={connectors}\n                                value={configWatch(\"connectors\") || []}\n                                onChange={(selectedOptions) => {\n                                    const selected = selectedOptions || [];\n                                    configSetValue(\"connectors\", selected);\n                                }}\n                            />\n                            <div className={`${style.ConfigSaveContainer} ${style.SaveConfigContainer}`}>\n                                <div>\n                                    <Button buttonType=\"submit\" className=\"icon-button\">  Save & Continue <FaRegArrowAltCircleRight /></Button>\n                                </div>\n                            </div>\n                        </div>\n                    </form>\n                </Tab>\n\n                {/*==============Inference tab==================*/}\n                <Tab title=\"Inference Endpoint\" disabled={activeInferencepiontTab} tabKey=\"inferenceendpoint\">\n                    <form onSubmit={inferenceHandleSubmit(onInferanceSave)}>\n                        <div>\n                            <Input label=\"Name\" hasError={inferenceFormError[\"inferenceName\"]?.message ? true : false} errorMessage={inferenceFormError[\"inferenceName\"]?.message}  {...inferenceRegister(\"inferenceName\", { required: \"This field is required\", maxLength: 50 })} />\n                            <div style={{ marginBottom: \"30px\" }}>\n                                <Controller\n                                    control={inferenceController}\n                                    name='inferenceProvider'\n                                    render={() => (\n                                        <Select label={\"LLM Provider\"} placeholder={llmModels[0]?.label} options={llmModels} value={selectedProvider} onChange={(value) => { setSelectedProvider(value); resetTestInference() }} />\n                                    )}\n                                />\n\n                                {configFormError[\"inferenceProvider\"]?.message && <span style={{ color: \"#FF7F6D\" }}>{configFormError[\"inferenceProvider\"]?.message}</span>}\n                            </div>\n                            <Input label=\"Model Name\" hasError={inferenceFormError[\"inferenceModelName\"]?.message ? true : false} errorMessage={inferenceFormError[\"inferenceModelName\"]?.message}  {...inferenceRegister(\"inferenceModelName\", { required: \"This field is required\" })} onChange={resetTestInference} />\n                            <Input label=\"Endpoint\" hasError={inferenceFormError[\"inferenceEndpoint\"]?.message ? true : false} errorMessage={inferenceFormError[\"inferenceEndpoint\"]?.message}  {...inferenceRegister(\"inferenceEndpoint\", { required: \"This field is required\" })} onChange={resetTestInference} />\n                            <Input label=\"API Key\" type=\"password\" hasError={inferenceFormError[\"inferenceAPIKey\"]?.message ? true : false} errorMessage={inferenceFormError[\"inferenceAPIKey\"]?.message}  {...inferenceRegister(\"inferenceAPIKey\", { required: \"This field is required\" })} onChange={resetTestInference} />\n                        </div>\n                        {showNotificationPanel && <NotificationPanel message={notificationMessage} containerStyle={{ marginBottom: \"30px\" }} />}\n                        <div className={`${style.SaveConfigContainer} ${style.InferenceSaveContainer}`}>\n                            <div style={{ flexGrow: 1 }}>\n                                <Button type=\"transparent\" className=\"icon-button\" onClick={() => { setActiveTab(\"configuration\") }} > <FaArrowLeft /> Back</Button>\n                            </div>\n                            <div>\n                                {disabledInferenceSave && <Button onClick={onTestInference} style={{ marginRight: \"10px\" }}> Test <LiaToolsSolid />  </Button>}\n                                <Button buttonType=\"submit\" className=\"icon-button\" disabled={disabledInferenceSave}>  Save <FiCheckCircle /></Button>\n                            </div>\n                        </div>\n                    </form>\n                </Tab>\n\n                {/*==============VectorDB tab==================*/}\n                <Tab title=\"VectorDB\" disabled={activeInferencepiontTab} tabKey=\"vectordbtab\" key={\"vectordbtab\"}>\n                    {showVectorDbForm ? (\n                        <form onSubmit={vectorDbHandleSubmit(vectorDbSave)}>\n                            <div className={style.VectorFormContainer}>\n                                <div className={style.VectorFields}>\n                                    <TitleDescription title=\"Vector Database details\" description=\"Provide your vector database connection details to enable efficient similarity searches and optimize your application's performance.\" />\n\n                                    <Controller\n                                        control={vectorDbController}\n                                        name=\"vectorDbProvider\"\n                                        render={({ field: { onChange, value}}) => (                                            \n                                            <Select\n                                                placeholder={\"Please select\"}\n                                                required\n                                                options={vectorDB}\n                                                value={selectedVectordb}   \n                                                onChange={(selectedOption) => {\n                                                    handleDatabaseChange(selectedOption); \n                                                    onChange(selectedOption); \n                                                }}\n                                            />\n                                        )}\n                                    />\n                                    \n                                    {selectedVectordb?.config && loadDbBasedForm(selectedVectordb.config)}\n\n                                </div>\n                                <div>\n                             {showNotificationPanel && <NotificationPanel message={notificationMessage} containerStyle={{marginBottom:\"30px\"}}/>}   \n                                </div>\n                                <div className={`${style.SaveVectorContainer} ${style.VectorSaveContainer}`}>\n                                    <div style={{ flexGrow: 1 }}>\n                                        <Button type=\"transparent\" className=\"icon-button\" onClick={() => setActiveTab(\"inferenceendpoint\")} > <FaArrowLeft /> Back</Button>\n                                    </div>\n                                    <div>\n                                        {disabledVectorDbSave && <Button onClick={onTestVectorDb} style={{ marginRight: \"10px\" }}> Test <LiaToolsSolid />  </Button>}\n                                        <Button buttonType=\"submit\" className=\"icon-button\" disabled={disabledVectorDbSave}>  Save & Continue <FiCheckCircle /></Button>\n                                    </div>\n                                </div>\n                            </div>\n                        </form>\n                    ) : (\n                        <>\n                            <div className={style.VectorContainer}>\n                                <div className={style.VectorContent}>\n                                    <img src={VectorEmpty} alt='vectorempty' />\n                                    <span>\n                                    <p style={{display:\"flex\"}}><span><img src={cromaDbIcon}/></span>Chroma DB is the currently selected vector database. Do you want to proceed with this choice, or would you like to change the vector database?</p>\n                                    </span>\n                                    <div className={style.VectorControls}>\n                                        <Button variant='secondary' className=\"icon-button\" onClick={() => { onClickChangeVectorDB() }}>Change <img src={pencilIcon}/> </Button>\n                                        <Button buttonType=\"submit\" className=\"icon-button\" onClick={() => setActiveTab(\"capabalities\")} > Continue with Default <FaRegArrowAltCircleRight /></Button>\n                                    </div>\n                                </div>\n                            </div>\n                        </>\n                    )}\n\n                </Tab>\n                <Tab title=\"Capabilities\" disabled={activeInferencepiontTab} tabKey=\"capabalities\" key={\"capabalities\"}>\n                    <div style={{ marginBottom: \"30px\" }}>\n                        <h4>Capabilities details</h4>\n                        <p>Explore and define the functionalities offered by the plugin. By incorporating additional capabilities, you can maximize its benefits and fully leverage the plugin's potential.</p>\n                    </div>\n                    <div className=\"text-align-right margin-bottom-10\">\n                        <Button variant=\"secondary\" className=\"icon-button\" onClick={addNewCapability}>New Capability <GoPlus /> </Button>\n                    </div>\n                    <div>\n\n                        {capabalities?.map((item, index) => {\n                            return <Capability\n                                key={index}\n                                capabilityId={item.id}\n                                capabilityIndex={index}\n                                title={item.name == \"\" ? item.title : item.name}\n                                name={item.name}\n                                description={item.description}\n                                parameters={item.requirements}\n                                isCollapse={item.isCollapse}\n                                onCapabilitySave={onSaveCapability}\n                                onParamEdit={editParameter}\n                                onParamDelete={deleteParameter}\n                                onCapabilityDelete={deleteCapability}\n                                onCreateNewParam={onClickNewParams}\n                            />\n                        })}\n\n                    </div>\n                    <div className={style.ActionDiv}>\n                        <div style={{ flexGrow: 1 }}>\n                            <Button type=\"transparent\" className=\"icon-button\" onClick={() => setActiveTab(\"inferenceendpoint\")}> <FaArrowLeft /> Back</Button>\n                        </div>\n                        <div>\n                            <Button className=\"icon-button\" onClick={() => setActiveTab('Deploy')}>  Save & Continue <FaRegArrowAltCircleRight /></Button>\n                        </div>\n\n                    </div>\n                </Tab>\n                <Tab title=\"Deploy\" tabKey='Deploy'>\n                    <Deploy currentConfigID={currentConfigID}></Deploy>\n\n                </Tab>\n            </Tabs>\n\n            <Modal title=\"Create New Parameter\" show={showParamsModal} onClose={() => setShowParamsModal(false)}>\n                <div>\n                    <Input type=\"hidden\" value={editCapabilityIndexRef} />\n                    <Input type=\"hidden\" value={editParamsIdRef} />\n                    <Input ref={editParamsNameRef} label={<>Name <span style={{ color: \"red\" }}>*</span></>} hasError={currentEditParamsNameError.hasError} errorMessage={currentEditParamsNameError.errorMessage} />\n                    <Textarea ref={editParamsDesc} label={<>Description <span style={{ color: \"red\" }}>*</span></>} rows={10} hasError={currentEditParamsDescError.hasError} errorMessage={currentEditParamsDescError.errorMessage} />\n                </div>\n                <div className=\"text-align-right\">\n                    <Button variant=\"secondary-danger\" className=\"icon-button\" onClick={() => setShowParamsModal(false)} style={{ marginRight: \"10px\" }}>Cancel <FiXCircle /></Button>\n                    <Button className=\"icon-button\" onClick={addNewParameter}>Save <FiCheckCircle /></Button>\n                </div>\n            </Modal>\n\n        </DashboardBody>\n    );\n};\n\nexport default BotConfiguration;\n"
  },
  {
    "path": "ui/src/pages/ChatConfiguration/Configuration.module.css",
    "content": "/* Empty Configuration Page */\n\n.EmptyDataContainer {\n    text-align: center;\n    margin-top: 20vh;\n}\n\n.EmptyDataTitleSpan {\n    color: var(--neural-3);\n    text-align: center;\n    font-feature-settings: 'clig' off, 'liga' off;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px;\n}\n\n/* end Empty Configuration Page ****/\n\n\n/* Config List Page */\n\n.SearchContainer {\n    margin-bottom: 44px;\n    display: flex;\n}\n\n.ConnectorAction {\n    display: flex;\n    align-items: center;\n    gap: 23px;\n}\n\n.ConnectorIcon {\n    width: 24px;\n    height: 24px;\n    margin-right: 8px;\n}\n"
  },
  {
    "path": "ui/src/pages/ChatConfiguration/ConfigurationList.jsx",
    "content": "// ConfigurationList.jsx\n\nimport React from \"react\";\nimport SearchInput from \"src/components/SearchInput/SearchInput\";\nimport Table from \"src/components/Table/Table\";\nimport Tag from \"src/components/Tag/Tag\";\nimport { GoPencil } from \"react-icons/go\";\nimport { HiOutlinePlusCircle } from \"react-icons/hi\";\nimport { LuTrash2 } from \"react-icons/lu\";\nimport Button from \"src/components/Button/Button\";\nimport style from \"./Configuration.module.css\";\nimport { Link } from \"react-router-dom\";\nimport { BACKEND_SERVER_URL } from \"src/config/const\";\nimport confirmDialog from \"src/utils/ConfirmDialog\";\n\nconst ConfigurationList = ({ configurations = [], onConfigDelete }) => {\n\n  const handleDelete = (config_id) => {\n    confirmDialog(\n      \"Confirmation\",\n      \"Are you sure you want to delete this?\",\n      undefined,\n      undefined,\n      \"Delete\",\n      () => {\n        onConfigDelete(config_id);\n      }\n    );\n  };\n\n\n  let tableColumns = [\n\n    {\n        name: 'Name',\n        selector: row =><div className=\"inline-flex-align-center\">{row.name}</div>,\n        // width: \"400px\"\n    },\n    {\n        name: 'Description',\n        // selector: row => row.connector_description?.slice(0,60) + \"...\",\n        selector: row => <div style={{overflow: \"hidden\", width: \"calc(50vh)\"}}>{row.short_description}</div>\n    },\n    {\n        name: '',\n        selector: row => <>\n                <div className={style.ConnectorAction}>\n                    <span>\n                        <Link to={`/bot-configuration/${row.id}`} ><GoPencil size={20} color=\"#3893FF\" /> </Link>\n                    </span>\n                    {/* <span>\n                        <TbMessagePlus size={20} color=\"#3893FF\"/>\n                    </span> */}\n                    <span>\n                    <LuTrash2 size={20} onClick={() => handleDelete(row.id)} color=\"#FF7F6D\" />\n\n                    </span>\n                </div>\n\n        </>,\n        width: \"100px\"\n    }\n\n]\n  return(\n    <>\n        <div>\n            <div className={` ${style.SearchContainer}`}>\n                <div className=\"flex-grow-1\">\n                    <SearchInput style={{width: \"349px\"}}/>\n                </div>\n                <div>\n                    <Link to={\"/bot-configuration/sources\"}>\n                        <Button className=\"icon-button\">Add New <HiOutlinePlusCircle/> </Button>\n                    </Link>\n                </div>\n            </div>\n            <Table columns={tableColumns} data={configurations} />\n        </div>\n\n    </>\n)\n}\n\nexport default ConfigurationList\n"
  },
  {
    "path": "ui/src/pages/ChatConfiguration/EmptyConfiguration.jsx",
    "content": "import emptyPluginImg from \"src/assets/images/empty-plugin.svg\"\nimport style from \"./Configuration.module.css\"\nimport Button from \"src/components/Button/Button\"\nimport { HiOutlinePlusCircle } from \"react-icons/hi\";\nimport { Link } from \"react-router-dom\";\nconst EmptyConfiguration = ()=>{\n\n    return(\n        <>\n            <div className={style.EmptyDataContainer}>\n                <div>\n                    <img src={emptyPluginImg}/>\n                </div>\n                <div style={{marginTop: \"19px\"}}>\n                    <span className={style.EmptyDataTitleSpan}>You don't have any configuration added, to get started go and add a configuration</span>\n                </div>\n                <div  style={{marginTop: \"39px\"}}>\n                    <Link to={\"/bot-configuration/sources\"}>\n                        <Button className=\"icon-button\">Create Configuration <HiOutlinePlusCircle size={22} /></Button>\n                    </Link>\n                </div>\n                \n            </div>\n        </>\n    )\n}\n\nexport default EmptyConfiguration"
  },
  {
    "path": "ui/src/pages/Configuration/Configuration.jsx",
    "content": "\nimport DashboardBody from \"src/layouts/dashboard/DashboadBody\"\nimport EmptyConfiguration from \"./EmptyConfiguration\"\nimport ConfigurationList from \"./ConfigurationList\"\nimport { useEffect, useState } from \"react\"\nimport { useNavigate } from 'react-router-dom';\nimport { toast } from \"react-toastify\"\nimport { deleteConnector, getConnectors } from \"src/services/Connectors\"\n\n\nconst Configuration = ()=>{\n\n    const navigate = useNavigate()\n    const [configurationList, setConfigurationList] = useState([])\n\n    const loadConnectors = ()=>{\n       getConnectors().then(response=>{\n            setConfigurationList(response.data.data.connectors ?? [])\n       }).catch(() => {\n        navigate('/error')\n    })\n    }\n\n\n    const onConnectorDelete = (connectorId)=>{\n        deleteConnector(connectorId).then(response=>{\n            if(response.data.status == true){\n                toast.success(\"Plugin Deleted\")\n                loadConnectors()\n            }else{\n                toast.error(\"Opps something went wrong\")\n            }\n        })\n    }\n\n\n    useEffect(()=>{\n        loadConnectors()\n    }, [])\n\n    \n    return(\n        <DashboardBody title=\"Plugin List\">\n                {configurationList?.length === 0  && <EmptyConfiguration/>}\n                {configurationList?.length > 0  && <ConfigurationList configurations={configurationList} onPluginDelete={onConnectorDelete} />}\n                \n        </DashboardBody>\n    )\n}\n\nexport default Configuration\n"
  },
  {
    "path": "ui/src/pages/Configuration/Configuration.module.css",
    "content": "/* Empty Configuration Page */\n\n.EmptyDataContainer {\n    text-align: center;\n    margin-top: 20vh;\n}\n\n.EmptyDataTitleSpan {\n    color: var(--neural-3);\n    text-align: center;\n    font-feature-settings: 'clig' off, 'liga' off;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px;\n}\n\n/* end Empty Configuration Page ****/\n\n\n/* Config List Page */\n\n.SearchContainer {\n    margin-bottom: 44px;\n    display: flex;\n}\n\n.ConnectorAction {\n    display: flex;\n    align-items: center;\n    gap: 23px;\n}\n\n.ConnectorIcon {\n    width: 24px;\n    height: 24px;\n    margin-right: 8px;\n}\n"
  },
  {
    "path": "ui/src/pages/Configuration/ConfigurationList.jsx",
    "content": "// ConfigurationList.jsx\n\nimport React from \"react\";\nimport SearchInput from \"src/components/SearchInput/SearchInput\";\nimport Table from \"src/components/Table/Table\";\nimport Tag from \"src/components/Tag/Tag\";\nimport { GoPencil } from \"react-icons/go\";\nimport { HiOutlinePlusCircle } from \"react-icons/hi\";\nimport { LuTrash2 } from \"react-icons/lu\";\nimport Button from \"src/components/Button/Button\";\nimport style from \"./Configuration.module.css\";\nimport { Link } from \"react-router-dom\";\nimport { BACKEND_SERVER_URL } from \"src/config/const\";\nimport confirmDialog from \"src/utils/ConfirmDialog\";\n\nconst ConfigurationList = ({ configurations = [], onPluginDelete }) => {\n\n  const handleDelete = (pluginId) => {\n    confirmDialog(\n      \"Confirmation\",\n      \"Are you sure you want to delete this?\",\n      undefined,\n      undefined,\n      \"Delete\",\n      () => {\n        onPluginDelete(pluginId);\n      }\n    );\n  };\n\n\n  let tableColumns = [\n\n    {\n        name: 'Name',\n        selector: row =><div className=\"inline-flex-align-center\"><img  className={style.ConnectorIcon} src={`${BACKEND_SERVER_URL}${row.icon}`}/>  { row.connector_name} </div>,\n        // width: \"400px\"\n    },\n    {\n        name: 'Description',\n        // selector: row => row.connector_description?.slice(0,60) + \"...\",\n        selector: row => <div style={{overflow: \"hidden\", width: \"calc(50vh)\"}}>{row.connector_description}</div>\n    },\n    {\n        name: 'Status',\n        selector: row => <Tag type=\"success\">{row.enable ==  true ? \"Completed\" : \"Documention Pending\"}</Tag>,\n        width: \"200px\"\n    },\n    {\n        name: '',\n        selector: row => <>\n                <div className={style.ConnectorAction}>\n                    <span>\n                        <Link to={`/plugins/${row.connector_type}/${row.connector_key}/${row.connector_id}/details`} ><GoPencil size={20} color=\"#3893FF\" /> </Link>\n                    </span>\n                    {/* <span>\n                        <TbMessagePlus size={20} color=\"#3893FF\"/>\n                    </span> */}\n                    <span>\n                    <LuTrash2 size={20} onClick={() => handleDelete(row.connector_id)} color=\"#FF7F6D\" />\n\n                    </span>\n                </div>\n\n        </>,\n        width: \"200px\"\n    }\n\n]\n  return(\n    <>\n        <div>\n            <div className={` ${style.SearchContainer}`}>\n                <div className=\"flex-grow-1\">\n                    <SearchInput style={{width: \"349px\"}}/>\n                </div>\n                <div>\n                    <Link to={\"/plugins/sources\"}>\n                        <Button className=\"icon-button\">Add Plugins <HiOutlinePlusCircle/> </Button>\n                    </Link>\n                </div>\n            </div>\n            <Table columns={tableColumns} data={configurations} />\n        </div>\n\n    </>\n)\n}\n\nexport default ConfigurationList\n"
  },
  {
    "path": "ui/src/pages/Configuration/EmptyConfiguration.jsx",
    "content": "import emptyPluginImg from \"src/assets/images/empty-plugin.svg\"\nimport style from \"./Configuration.module.css\"\nimport Button from \"src/components/Button/Button\"\nimport { HiOutlinePlusCircle } from \"react-icons/hi\";\nimport { Link } from \"react-router-dom\";\nconst EmptyConfiguration = ()=>{\n\n    return(\n        <>\n            <div className={style.EmptyDataContainer}>\n                <div>\n                    <img src={emptyPluginImg}/>\n                </div>\n                <div style={{marginTop: \"19px\"}}>\n                    <span className={style.EmptyDataTitleSpan}>You don't have any plugins added, to get started go and add a plugin</span>\n                </div>\n                <div  style={{marginTop: \"39px\"}}>\n                    <Link to={\"/plugins/sources\"}>\n                        <Button className=\"icon-button\">Add Plugin <HiOutlinePlusCircle size={22} /></Button>\n                    </Link>\n                </div>\n                \n            </div>\n        </>\n    )\n}\n\nexport default EmptyConfiguration"
  },
  {
    "path": "ui/src/pages/Configuration/ProviderForm/DatabaseTable.css",
    "content": ".rdt_TableBody div[data-column-id=\"2\"]{\n    /* background-color: red */\n}\n\n\n.rdt_TableBody div[data-column-id=\"2\"] div{\n    /* background-color: blue; */\n    width: 138%;\n}\n"
  },
  {
    "path": "ui/src/pages/Configuration/ProviderForm/ProviderForm.jsx",
    "content": "import Tab from \"src/components/Tab/Tab\"\nimport Tabs from \"src/components/Tab/Tabs\"\nimport DashboardBody from \"src/layouts/dashboard/DashboadBody\"\nimport style from \"./ProviderForm.module.css\"\nimport Input from \"src/components/Input/Input\"\nimport Textarea from \"src/components/Textarea/Textarea\"\nimport Button from \"src/components/Button/Button\"\nimport Table from \"../SchemaTable/SchemaTable\"\nimport { useForm } from \"react-hook-form\"\nimport { FaArrowLeft, FaPen } from \"react-icons/fa6\";\nimport { RiPlugLine } from \"react-icons/ri\";\nimport { FaRegArrowAltCircleRight } from \"react-icons/fa\";\n\nimport { FiTable} from \"react-icons/fi\"\n\nimport { useEffect, useState, useRef} from \"react\"\nimport { useParams, useNavigate, useSearchParams } from \"react-router-dom\"\n\nimport { getConnector, healthCheck, saveConnector, updateSchema, updateDocument} from \"src/services/Connectors\"\nimport { toast } from \"react-toastify\"\n\nimport \"./DatabaseTable.css\"\nimport TitleDescription from \"src/components/TitleDescription/TitleDescription\"\nimport { getProviderInfo } from \"src/services/Plugins\"\nimport FileUpload from \"src/components/FileUpload/FileUpload\"\nimport { API_URL } from \"src/config/const\"\nimport UploadFile from \"src/utils/http/UploadFile\"\nimport GenerateConfigs from \"src/utils/form/GenerateConfigs\"\n\n\nconst ProviderForm = ()=>{\n\n    const [providerDetails, setProviderDetails] = useState({})\n    const [providerConfig, setProviderConfig] = useState([])\n    const [providerSchema, setProviderSchema] = useState([])\n    const [currentActiveTab, setCurrentActiveTab] = useState(\"configuration\")\n\n    const [filePaths, setFilePaths] = useState([]);\n    const [files, setFiles] = useState([]);\n    const [showProgressBar, setShowProgressBar] = useState(false);\n    const [progressPrecentage, setProgressPrecentage] = useState(0);\n    const [progressTime, setProgressTime] = useState('');\n    const pdfUploadRef = useRef(null);\n    \n    \n\n    const [disableConnectorSave, setDisableConnectorSave] = useState(true);\n    \n    let [documentationError, setDocumentationError] = useState({hasError: false, errorMessage: \"\"})\n\n    let configDocRef = useRef(null)\n\n\n    let [searchParams] = useSearchParams();\n\n    \n    const { register, getValues, handleSubmit, trigger, setValue , formState  } = useForm({mode : \"all\"})\n    const { errors } = formState\n\n\n    const {providerId, connectorId} = useParams()\n    const navigate = useNavigate()\n\n    const maxFiles = 5; \n\n\n    const getProviderDetails = ()=>{\n\n        getProviderInfo(providerId).then(response=>{\n            let data = response.data.data;\n            setProviderDetails({\n                name: data.provider.name,\n                description:  data.provider.description,\n                icon: data.provider.icon,\n                category_id: data.provider.category_id,\n                enable: data.provider.enable\n            })\n\n            setProviderConfig(data.provider.configs)\n            if(connectorId){\n                getConnectDetails();\n            }\n           \n        })\n    }\n    \n    const getConnectDetails = ()=>{\n        getConnector(connectorId).then(response=>{\n            let connectorData = response.data.data.connector;\n            let connectorConfig = response.data.data.connector.connector_config\n\n           \n            setValue(\"pluginName\", connectorData.connector_name )\n            setValue(\"pluginDescription\", connectorData.connector_description )\n\n            for( let key in connectorConfig){\n                setValue(key, connectorConfig[key])\n            }\n\n            configDocRef.current.value = connectorData.connector_docs\n            setProviderSchema(connectorData.schema_config ?? [])\n\n            const fetchedFiles = connectorConfig.document_files?.map(file => ({\n                file_path: file.file_path,\n                file_name: file.file_name,\n                file_size: parseFloat(file.file_size) * 1024, \n                file_id: file.file_id\n            })) || [];\n\n            setFiles(prevFiles => [...prevFiles, ...fetchedFiles]);\n            setDisableConnectorSave(false); \n\n\n            let tempSaveTableDetails = {}\n            connectorData.schema_config?.map(item=>{\n                if(!tempSaveTableDetails[item.table_id]){\n                    tempSaveTableDetails[item.table_id] = { table_id: item.table_id, table_name: item.table_name, description: item.description, columns: {}}\n                }\n                \n                item?.columns?.map(col=>{\n                    if(!tempSaveTableDetails[item.table_id].columns[col.column_id]){\n                        tempSaveTableDetails[item.table_id].columns[col.column_id] = { column_id: col.column_id, column_name: col.column_name, description :col.description }\n                    }\n                    \n                })\n                \n            })\n            window.localStorage.setItem(\"dbschema\", JSON.stringify(tempSaveTableDetails))\n            \n        })\n    }\n\n\n    \n    const onSaveFiles = (file) => {\n        const uploadUrl = API_URL + `/connector/upload/datasource`;\n        const formData = new FormData();\n        formData.append('file', file);\n        setShowProgressBar(true);\n    \n        return UploadFile(uploadUrl, formData, (percentage, estimatedTime) => {\n            setProgressPrecentage(percentage);\n            setProgressTime(estimatedTime);\n        })\n        .then(response => {\n            const fileData = response.data.data.file;\n            const fileDetails = {\n                file_path: fileData.file_path,\n                file_name: fileData.file_name,\n                file_size: fileData.file_size,\n                file_id: fileData.file_id\n            };\n    \n            setFilePaths(prevPaths => [...prevPaths, fileDetails]);\n    \n            setFiles(prevFiles => [\n                ...prevFiles,\n                {\n                    file_name: file.name,\n                    file_size: (file.size / (1024 * 1024)).toFixed(2), // Convert size to MB\n                    file_path: fileDetails.file_path, \n                    file_id: fileDetails.file_id,\n                }\n            ]);\n    \n            setDisableConnectorSave(true);\n            setShowProgressBar(false);\n        })\n        .catch(error => {\n            toast.error('File upload failed', error);\n            setShowProgressBar(false);\n        })\n        .finally(() => {\n            setProgressPrecentage(0);\n            setProgressTime(\"\");\n        });\n    };\n    \n\n    const getMaxFileSize = (extension) => {\n        if (extension === \"text/csv\") {\n            return 100\n        } else {\n            return 100\n        }\n    }\n \n\n    const onFileChange = (event) => {\n        const selectedFile = event.target.files[0];\n        if (!selectedFile) return;\n        const maxFileSizeMB = getMaxFileSize(selectedFile.type)\n        \n        const fileSizeMB = selectedFile.size / (1024 * 1024); \n    \n        if (files.length >= maxFiles) {\n            toast.error(`You can only upload up to ${maxFiles} files.`)\n            return;\n        }\n    \n        if (fileSizeMB > maxFileSizeMB) {\n            toast.error(`File size should not exceed ${maxFileSizeMB} MB. The selected file is ${fileSizeMB.toFixed(2)} MB.`)\n            return;\n        }\n    \n        if (providerDetails.category_id === 5 && selectedFile.type === \"text/csv\"){\n            onSaveFiles(selectedFile)\n        } else if (providerDetails.category_id === 4 && selectedFile.type != \"text/csv\") {\n            onSaveFiles(selectedFile)\n        }\n        else {\n            toast.error(\"Invalid file type\")\n        }\n    };\n    \n    const onAddFileOnDrag = (event) => {\n        event.preventDefault();\n        const draggedFile = event.dataTransfer.files[0];\n        const maxFileSizeMB = getMaxFileSize(draggedFile.type)\n\n        if (!draggedFile) return;\n    \n        const fileSizeMB = draggedFile.size / (1024 * 1024); \n    \n        if (files.length >= maxFiles) {\n            toast.error(`You can only upload up to ${maxFiles} files.`)\n            return;\n        }\n    \n        if (fileSizeMB > maxFileSizeMB) {\n            toast.error(`File size should not exceed ${maxFileSizeMB} MB. The selected file is ${fileSizeMB.toFixed(2)} MB.`)\n            return;\n        }\n        if (providerDetails.category_id === 5 && draggedFile.type === \"text/csv\"){\n            onSaveFiles(draggedFile)\n        } else if (providerDetails.category_id === 4 && draggedFile.type != \"text/csv\") {\n            onSaveFiles(draggedFile)\n        }\n        else {\n            toast.error(\"Invalid file type\")\n        }\n    };\n\n\nconst onRemoveFile = (fileId) => {\n    const updatedFiles = files.filter(file => file.file_id !== fileId);\n    setFiles(updatedFiles);\n\n    const updatedFilePaths = filePaths.filter(filePath => filePath.file_id !== fileId);\n    setFilePaths(updatedFilePaths);\n\n    if (updatedFiles.length === 0) {\n        setDisableConnectorSave(true);\n    }\n};\n\n\n    const getConfigFormData = async ()=>{\n        let slugs = await providerConfig.map(item=>item.slug)\n        let formValues = {};\n        let formFilled = true\n        slugs.forEach((input)=>{\n            formValues[input] = getValues(input)\n            if(formValues[input] == \"\"){\n                trigger(input)\n                formFilled = false\n            }\n        });\n        return {formValues, formFilled}\n    }\n    \n    \n    const generateConfig = () => {\n\n        providerConfig.sort((firstItem, secondItem) => {\n            return firstItem.order > secondItem.order ? -1 : 1\n        })\n        \n        const fileConfig = {\n            onRemoveFile:onRemoveFile,\n            onAddFileOnDrag:onAddFileOnDrag,\n            pdfUploadRef:pdfUploadRef,\n            title:\"Upload your files\",\n            description:`You can upload up to 5 files, with each file having a maximum size of ${providerDetails.category_id === 5 ? 100 : 10} MB.`,\n            accept:providerDetails.category_id === 5 ? \".csv\" : \".pdf,.yaml,.txt,.docx\",\n            dragMessage:\"Drag your files to start uploading\",\n            progressPrecentage:progressPrecentage,\n            showProgressBar:showProgressBar,\n            progressTime:progressTime,\n            onAddFileOnDrag:onAddFileOnDrag,\n            onFileChange:onFileChange,\n            onRemoveFile:onRemoveFile,\n            files:files,\n            supportedFileMessage:`${providerConfig[0]?.description}`,\n            multipleFileSupport:false\n        }\n\n\n        return (\n            <>\n                <GenerateConfigs\n                    configs={providerConfig}\n                    errors={errors}\n                    register={register}\n                    fileConfig={fileConfig}\n                    restForm={onChangesOption}\n\n                />\n\n            </>\n        )\n    }\n\n    const onChangesOption=()=>{\n        if (files.length === 0) {\n            setDisableConnectorSave(true);\n        }\n    }\n\n\n    const generateGeneralDetails = ()=>{\n        return(\n            <>\n                <div style={{marginBottom: \"30px\"}}>\n                    <h4>Configuration details</h4>\n                    <p>{providerDetails.description}</p>\n                </div>\n                <div>\n                    <Input label=\"Plugin Name\" placeholder=\"Plugin Name\" maxLength={20} required hasError={errors[\"pluginName\"]?.message ? true : false} errorMessage={errors[\"pluginName\"]?.message}  {...register(\"pluginName\", {required: \"This is required\" ,minLength: {value: 10, message: \"minimum length is 10\"}})} onChange={onChangesOption}/>\n                    <Textarea label=\"Plugin Description\" placeholder=\"Describe the plugin's purpose and content in a detailed and informative manner, emphasizing its key features and functionality.\" required rows={8} maxLength={200} hasError={errors[\"pluginDescription\"]?.message ? true : false} errorMessage={errors[\"pluginDescription\"]?.message}  {...register(\"pluginDescription\", {required: \"This is required\", minLength: {value: 20, message: \"minimum length is 20\"}})} onChange={onChangesOption}/>\n                    {generateConfig()}\n        \n                </div>\n            </>\n        )\n    }\n\n\n    const onSaveConnector = async (data) => {\n\n        let { formValues } = await getConfigFormData();\n        if(providerDetails.category_id == 4 || providerDetails.category_id == 5){\n            formValues.document_files = files; \n        }\n        saveConnector(connectorId, providerId, data.pluginName, data.pluginDescription, formValues).then(response => {\n            toast.success(\"Successfuly plugin added\")\n            if (connectorId == undefined) {\n                let url = window.location.href.split('/');\n                if(providerDetails.category_id == 2 || providerDetails.category_id == 5){\n                    window.location.href = url.join(\"/\") + `/${response.data.data.connector.connector_id}/details?activeTab=database-table`\n                }else{\n                    window.location.href = url.join(\"/\") + `/${response.data.data.connector.connector_id}/details?activeTab=documentation`\n                }\n            } else {\n                if(providerDetails.category_id == 2 || providerDetails.category_id == 5){\n                    setCurrentActiveTab(\"database-table\")\n                }else{\n                    setCurrentActiveTab(\"documentation\")\n                }\n            }\n        }).catch(e => {\n            toast.error(\"Plugin saving failed\")\n        }\n        )\n    }\n\n     \n     const onTestConnection = async ()=>{\n        let {formValues, formFilled} = await getConfigFormData()\n        if(formFilled){\n            if(providerDetails.category_id == 4 || providerDetails.category_id == 5){\n                formValues.document_files = files; \n            }\n            healthCheck(providerId, { provider_config: formValues, connector_name: getValues(\"pluginName\") }).then(response=>{\n                if(response.data.status == false){\n                    toast.error(\"Connection check failed\")\n                }else {\n                    toast.success(\"Connection check Success\")\n                    setDisableConnectorSave(false)\n                }\n                \n            }).catch(()=>{\n                toast.error(\"Health check failed\")\n            })\n        }\n       \n     }\n\n\n     const onSaveDBSchema = (e)=>{\n       \n        let tempTableDetails = []\n        let localTableDetails =  JSON.parse(window.localStorage.getItem(\"dbschema\")) \n        let fullFill = false\n        Object.keys(localTableDetails).map(table_id=>{\n            let tempCols = [];\n            Object.keys(localTableDetails[table_id].columns).map(col_id=>{\n                tempCols.push({\n                    column_id: col_id,\n                    column_name: localTableDetails[table_id].columns[col_id].column_name,\n                    description: localTableDetails[table_id].columns[col_id].description\n                })\n            })\n\n\n            if(localTableDetails[table_id].description.trim() !== \"\"){\n                fullFill = true\n            }\n\n            tempTableDetails.push({\n                table_id: table_id,\n                table_name: localTableDetails[table_id].table_name,\n                description: localTableDetails[table_id].description,\n                columns: tempCols\n            })\n        })\n\n       \n\n        if(fullFill == false){\n            toast.error(\"Table description is a required field. Please provide a valid description.\")\n            return\n        }\n\n        updateSchema(connectorId, tempTableDetails).then(response=>{\n            toast.success(\"Data saved successfully.\")\n            setCurrentActiveTab(\"documentation\") \n        })\n    }\n\n\n    const onDocumentUpdate = (e)=>{\n        e.preventDefault();\n        setDocumentationError({hasError: false, errorMessage: \"\"})\n        if(configDocRef.current.value == \"\"){\n            setDocumentationError({hasError: true, errorMessage: \"This field is required\"})\n            return\n        }\n        updateDocument(connectorId, configDocRef.current.value).then(()=>{\n            navigate(\"/plugins\")\n        })\n    }\n\n\n    const onBacktoDatabaseTable = ()=>{\n        if([2].includes(providerDetails.category_id)){\n            setCurrentActiveTab(\"database-table\")\n        }else{\n            setCurrentActiveTab(\"configuration\")\n        }\n    }\n\n    useEffect(()=>{\n        getProviderDetails()\n        if(searchParams.get(\"activeTab\")){\n            setCurrentActiveTab(searchParams.get(\"activeTab\"))\n        }\n    },[])\n\n\n    return (\n        <>\n            <DashboardBody title={providerDetails.name}>\n                {/* activeTab={searchParams.get(\"activeTab\") ?? \"configuration\"} */}\n                <Tabs activeTab={currentActiveTab}>\n                    <Tab  title=\"Configuration\" tabKey=\"configuration\" key={\"configuration\"}>\n                        <form onSubmit={handleSubmit(onSaveConnector)}>\n                             \n                             {generateGeneralDetails()}\n                             \n                            <div className={style.ActionDiv}>\n                                <div style={{flexGrow: 1}}>\n                                    <Button type=\"transparent\" className=\"icon-button\" onClick={()=>navigate(\"/plugins\")}> <FaArrowLeft/> Cancel</Button>\n                                </div>\n                                <div>\n                                {disableConnectorSave && <Button style={{marginRight: \"10px\",display: (providerDetails.category_id === 4 || providerDetails.category_id === 5) ? \"none\" : \"\"}} className=\"icon-button\" disabled={Object.keys(errors).length > 0 ? true : false} onClick={onTestConnection}>  Connection Test <RiPlugLine/></Button>}\n                                    <Button buttonType=\"submit\" className=\"icon-button\" disabled={(providerDetails.category_id === 4 || providerDetails.category_id === 5) ? false : disableConnectorSave} >  Save & Continue <FaRegArrowAltCircleRight/></Button>\n                                </div>\n                            </div>\n                        </form>\n                    </Tab>\n                   \n                     <Tab title=\"Database Schema\" tabKey=\"database-table\" key={\"database-table\"} disabled={connectorId ? false : true} hide={![2,5].includes(providerDetails.category_id)}>\n                        <TitleDescription title=\"Schema Details\" description=\"Here are the tables and their columns for the plugin. Please describe the tables and it's column details to improve understanding of the plugin schema structure.\" />\n                        <div style={{marginBottom: \"30px\"}}>\n                            <Table data={providerSchema} ></Table>\n                        </div>\n                        <div className={style.ActionDiv}>\n                            <div style={{flexGrow: 1}}>\n                                <Button type=\"transparent\" className=\"icon-button\" onClick={()=>setCurrentActiveTab(\"configuration\")} > <FaArrowLeft/> Back</Button>\n                            </div>\n                            <div>\n                                <Button className=\"icon-button\" onClick={onSaveDBSchema} >  Save & Continue  <FaRegArrowAltCircleRight/></Button>\n                            </div>\n                        </div>\n                    </Tab>    \n                    <Tab title=\"Documentation\" tabKey=\"documentation\" key={\"documentation\"} disabled={connectorId ? false : true}>\n                        <form onSubmit={onDocumentUpdate}>\n                            <div style={{marginBottom: \"30px\"}}>\n                                <h4>Documentation details</h4>\n                                <p>To fully understand how a plugin functions and how to use it effectively, it’s crucial to consult the provider’s documentation. This documentation often includes important conditions and criteria, offering detailed insights and explanations.</p>\n                            </div>\n                            <div>\n                                <Textarea ref={configDocRef} label=\"Add your document data here\" placeholder=\"eg: This data doesn't contains gender baised information\" rows={18} hasError={documentationError.hasError} errorMessage={documentationError.errorMessage} />\n                            </div>\n                            <div className={style.ActionDiv}>\n                                <div style={{flexGrow: 1}}>\n                                    <Button type=\"transparent\" className=\"icon-button\" onClick={onBacktoDatabaseTable}> <FaArrowLeft/> Back</Button>\n                                </div>\n                                <div>\n                                    <Button buttonType=\"submit\" className=\"icon-button\">  Save & Continue <FaRegArrowAltCircleRight/></Button>\n                                </div>\n                            </div>\n                        </form>\n                    </Tab>\n                </Tabs>\n            </DashboardBody>\n        </>\n    )\n}\n\nexport default ProviderForm"
  },
  {
    "path": "ui/src/pages/Configuration/ProviderForm/ProviderForm.module.css",
    "content": ".ActionDiv {\n    border-radius: 8px;\n    background: var(--neural-7);\n    padding: 17px 16px;\n    display: flex;\n}\n\n.ExpandRowContainer {\n    padding: 10px 22px;\n}\n\n.ExpandRowDiv{\n    border-radius: 4px;\n    background: #F5FAFF;\n    padding: 0px 0px 0px 42px;\n    display: flex;\n    align-items: center;\n    margin: 2px 0px;\n}\n\n.ExpandRowCol {\n    width: 200px;\n    padding: 12px 0px;\n}\n\n\n.SelectDropDownLabel {\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px;\n    margin-bottom: 5px;\n    margin-left: 4.23px;\n    display: block;\n}\n\n.SelectDropDown {\n    position: relative;\n    margin-bottom: 24px;\n}\n\n  \n.SelectDropDown select {\n    appearance: none;\n    width: 100%;\n    font-size: 12pz;\n    padding: 0.675em 6em 0.675em 1em;\n    background-color: #fff;\n    border: 1px solid #caced1;\n    border-radius: 4px;\n    color: #000;\n    cursor: pointer;\n\n}\n  \n.SelectDropDown::before,\n.SelectDropDown::after {\n    --size: 0.3rem;\n    content: \"\";\n    position: absolute;\n    margin-top: .5rem;\n    right: 1rem;\n    pointer-events: none;\n}\n  \n.SelectDropDown::before {\n    border-left: var(--size) solid transparent;\n    border-right: var(--size) solid transparent;\n    border-bottom: var(--size) solid black;\n    top: 40%;\n}\n  \n.SelectDropDown::after {\n    border-left: var(--size) solid transparent;\n    border-right: var(--size) solid transparent;\n    border-top: var(--size) solid black;\n    top: 55%;\n}\n\n\n.SelectHasError {\n    border-color: #FF7F6D;\n}\n\n.SelectHasError:hover {\n    border-color: #FFB9AF;\n}\n\n.SelectHasError:focus {\n    border-color: #FF7F6D;\n}\n\n.SelectErrorMessage {\n    color: #FF7F6D;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 16px; /* 133.333% */\n    margin-left: 4px;\n}\n\n.SelectHasError:hover ~ .SelectErrorMessage {\n    color: #FFB9AF;\n}\n\n.SelectHasError:focus ~ .SelectErrorMessage {\n    color: #FF7F6D;\n}\n.Hint {\n    font-size: 12px;\n    color:#6b7280;\n     \n    margin-bottom: 30px;\n    display: block;\n}\n"
  },
  {
    "path": "ui/src/pages/Configuration/SchemaTable/SchemaTable.jsx",
    "content": "import React, { useState, useRef, useMemo } from \"react\";\nimport style from \"./SchemaTable.module.css\";\nimport expandIcon from \"./assets/tableExpandIcon.svg\";\nimport collapseIcon from \"./assets/tableCollapseIcon.svg\";\nimport tableIcon from \"./assets/table.svg\";\nimport columnIcon from \"./assets/rows.svg\";\nimport pencilIcon from \"./assets/pencil.svg\";\nimport leftIcon from \"./assets/ChevronLeft.svg\";\nimport rightIcon from \"./assets/ChevronRight.svg\";\n\nfunction SchemaTable({ data, itemsPerPage = 8 }) {\n  const [expandedRows, setExpandedRows] = useState({});\n  const [expandedColRows, setExpandedColRows] = useState({});\n  const [currentPage, setCurrentPage] = useState(1);\n  const textAreaRefs = useRef({});\n  const colTextAreaRefs = useRef({});\n\n  // Pagination logic\n  const paginatedData = useMemo(() => {\n    const startIndex = (currentPage - 1) * itemsPerPage;\n    return data.slice(startIndex, startIndex + itemsPerPage);\n  }, [data, currentPage, itemsPerPage]);\n\n  const totalPages = Math.ceil(data.length / itemsPerPage);\n\n  const toggleRow = (id, event) => {\n    setExpandedRows((prev) => ({\n      ...Object.fromEntries(Object.keys(prev).map((k) => [k, false])),\n      [id]: !prev[id],\n    }));\n\n    const items = document.querySelectorAll(`[data-key]`);\n    items.forEach((item) => {\n      if (item.getAttribute(\"data-key\") === id) {\n        item.style.display = item.style.display === \"block\" ? \"none\" : \"block\";\n      } else {\n        item.style.display = \"none\";\n      }\n    });\n    if (event) {\n      event.target.parentNode.nextElementSibling.firstChild.lastChild.focus();\n      event.stopPropagation();\n    }\n  };\n\n  const toggleColRow = (id, event) => {\n    setExpandedColRows((prev) => ({\n      ...Object.fromEntries(Object.keys(prev).map((k) => [k, false])),\n      [id]: !prev[id],\n    }));\n    const items = document.querySelectorAll(`[data-col-key]`);\n\n    items.forEach((item) => {\n      if (item.getAttribute(\"data-col-key\") === id) {\n        item.style.display = item.style.display === \"block\" ? \"none\" : \"block\";\n      } else {\n        item.style.display = \"none\";\n      }\n    });\n    if (event) {\n      event.target.parentNode.nextElementSibling.lastChild.focus();\n      event.stopPropagation();\n    }\n  };\n\n  const handleDescriptionChange = (event, id, colId) => {\n    const newDescription = event.target.value;\n    const dbSchema = JSON.parse(localStorage.getItem(\"dbschema\") || \"{}\");\n    if (colId) {\n      if (dbSchema[id]) {\n        console.log(newDescription);\n        dbSchema[id].columns[colId].description = newDescription;\n        localStorage.setItem(\"dbschema\", JSON.stringify(dbSchema));\n      }\n    } else if (dbSchema[id]) {\n      dbSchema[id].description = newDescription;\n      localStorage.setItem(\"dbschema\", JSON.stringify(dbSchema));\n    }\n  };\n\n  const handlePageChange = (newPage) => {\n    setCurrentPage(newPage);\n    setExpandedRows({});\n    setExpandedColRows({});\n    const rowItems = document.querySelectorAll(`[data-key]`);\n    const colItems = document.querySelectorAll(`[data-col-key]`);\n    [...rowItems, ...colItems].forEach((item) => {\n      item.style.display = \"none\";\n    });\n  };\n\n  const getPaginationButtons = (currentPage, totalPages) => {\n    const pages = [];\n\n    if (totalPages <= 5) {\n      // Show all pages if there are 5 or fewer\n      for (let i = 1; i <= totalPages; i++) {\n        pages.push(i);\n      }\n    } else {\n      // Always show page 1\n      pages.push(1);\n\n      // Show first 4 pages if current page is within them\n      if (currentPage <= 3) {\n        pages.push(2, 3, 4, \"...\");\n      }\n      // Show last 4 pages if current page is near the end\n      else if (currentPage >= totalPages - 2) {\n        pages.push(\"...\", totalPages - 3, totalPages - 2, totalPages - 1);\n      }\n      // Show middle pages around current page\n      else {\n        pages.push(\"...\", currentPage - 1, currentPage, currentPage + 1, \"...\");\n      }\n\n      // Always show the last page\n      pages.push(totalPages);\n    }\n\n    return pages;\n  };\n\n  return (\n    <div className={style.tableContainer}>\n      <div className={style.tableHeader}>NAME</div>\n      {paginatedData.map((item, index) => (\n        <div key={item.table_id}>\n          <div\n            className={`${style.rowTitle} ${\n              expandedRows[item.table_id] ? style.tdOnfocus : \"\"\n            }`}\n            onClick={() => toggleRow(item.table_id)}\n          >\n            <div>\n              <img\n                src={expandedRows[item.table_id] ? collapseIcon : expandIcon}\n              />\n              <img src={tableIcon} />\n              {item.table_name}\n            </div>\n            <img\n              src={pencilIcon}\n              onClick={(event) => toggleRow(item.table_id, event)}\n            />\n          </div>\n          <div>\n            <div\n              className={style.descriptionContainer}\n              data-key={item.table_id}\n              style={{ display: \"none\" }}\n            >\n              <span>Description</span>\n              <textarea\n                ref={(el) => (textAreaRefs.current[index] = el)}\n                className={style.descriptionTextarea}\n                defaultValue={item.description}\n                onChange={(event) =>\n                  handleDescriptionChange(event, item.table_id)\n                }\n              />\n            </div>\n            {item.columns.map((column, colIndex) => (\n              <div\n                className={style.dbColumnContainer}\n                key={colIndex}\n                data-key={item.table_id}\n                style={{ display: \"none\" }}\n              >\n                <div\n                  className={`${style.dbColumnTd} ${style.rowTitle} ${\n                    expandedColRows[column.column_id] ? style.colOnfocus : \"\"\n                  }`}\n                  onClick={() => toggleColRow(column.column_id)}\n                >\n                  <div className={style.columnIndent}>\n                    <img\n                      src={\n                        expandedColRows[column.column_id]\n                          ? collapseIcon\n                          : expandIcon\n                      }\n                    />\n                    <img src={columnIcon} />\n                    {column.column_name}\n                  </div>\n                  <img\n                    src={pencilIcon}\n                    onClick={(event) => toggleColRow(column.column_id, event)}\n                  />\n                </div>\n                <div\n                  className={`${style.descriptionContainer} ${style.coldescription}`}\n                  data-col-key={column.column_id}\n                  style={{ display: \"none\" }}\n                >\n                  <span>Description</span>\n                  <textarea\n                    ref={(el) => (colTextAreaRefs.current[colIndex] = el)}\n                    className={style.descriptionTextarea}\n                    defaultValue={column.description}\n                    onChange={(event) =>\n                      handleDescriptionChange(\n                        event,\n                        item.table_id,\n                        column.column_id\n                      )\n                    }\n                  />\n                </div>\n              </div>\n            ))}\n          </div>\n        </div>\n      ))}\n\n      {/* Pagination Controls */}\n      <div className={style.paginationContainer}>\n        <button\n          onClick={() => handlePageChange(currentPage - 1)}\n          disabled={currentPage === 1}\n        >\n          <img src={leftIcon}></img>\n        </button>\n\n        {/* Render Pagination Buttons */}\n        {getPaginationButtons(currentPage, totalPages).map((page, index) => (\n          <button\n            key={index}\n            onClick={() => typeof page === \"number\" && handlePageChange(page)}\n            className={currentPage === page ? style.activePage : \"\"}\n            disabled={page === \"...\"}\n          >\n            {page}\n          </button>\n        ))}\n\n        <button\n          onClick={() => handlePageChange(currentPage + 1)}\n          disabled={currentPage === totalPages}\n        >\n          <img src={rightIcon}></img>\n        </button>\n      </div>\n    </div>\n  );\n}\n\nexport default SchemaTable;\n"
  },
  {
    "path": "ui/src/pages/Configuration/SchemaTable/SchemaTable.module.css",
    "content": "\n  .tableContainer {\n    width: 100%;\n    height: auto;\n    max-width: 100%;\n    border-collapse: collapse;\n    background-color: #F9F9F9;\n    border-radius: 8px;\n    overflow: hidden;\n    min-height: 512px;\n    position: relative;\n    padding-bottom: 52px;\n  }\n\n  .tableHeader {\n    padding: 12px 21px;\n    text-align: left;\n    color: #888787;\n    font-family: Inter;\n    font-size: 11px;\n    font-style: normal;\n    font-weight: 600;\n    line-height: 16px; \n  }\n\n  .rowTitle {\n    border-top: 1px solid #EFEFEF; /* divide-gray-200 equivalent */\n  }\n\n  .rowTitle {\n    padding: 0 25px;\n    height: 58px;\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    background-color: #F9F9F9;\n    cursor: pointer;\n  }\n  .rowTitle div {\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px;\n    display: flex;\n    align-items: center;\n    gap: 6px;\n  }\n\n  .rowTitle:hover {\n    background: #F1F1F1;\n  }\n\n  .tdOnfocus {\n    background-color: #F1F1F1;\n  }\n\n  .dbColumnContainer {\n    display: block;\n  }\n\n  .columnIndent {\n    margin-left: 22px;\n  }\n  .dbColumnTd {\n    height: 39px !important;\n    border-top: 1px solid #E6E6E6 ;\n    background-color: #F1F1F1;\n  }\n\n  .dbColumnTd:hover {\n    background-color: #EAEAEA !important;\n  }\n\n  .colOnfocus {\n    background-color: #EAEAEA !important;\n  }\n\n  .expandedRow {\n    display: block;\n  }\n\n  .descriptionContainer {\n    padding: 0 54px 0 70px;\n    background-color: #F1F1F1;\n  }\n  \n  .coldescription {\n    background-color: #EAEAEA ;\n  }\n\n  .descriptionContainer span{\n    font-family: Inter;\n    font-size: 11px;\n    font-style: normal;\n    font-weight: 600;\n    line-height: 16px;\n    color: #888787;\n  }\n\n  .descriptionTextarea {\n    color: #323232;\n    box-sizing: border-box;\n    border-radius: 8px;\n    width: 100%;\n    margin-top: 6px;\n    margin-bottom: 18px;\n    resize: none; \n    overflow-y: auto;\n    padding: 14px 10px;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px;\n    height: 50px;\n    background-color: #D8D8D8;\n  }\n  .descriptionTextarea:hover {\n    border: 1px solid #C6E0FF;\n    background: #FFF;\n    box-shadow: 0px 1px 2px 0px rgba(10, 13, 18, 0.05);\n  }\n  .descriptionTextarea:focus {\n    outline: none;\n    border: 1px solid #3893FF;\n    background: #FFF;\n    box-shadow: 0px 1px 2px 0px rgba(10, 13, 18, 0.05);\n  }\n\n  .paginationContainer {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    margin: 10px 0;\n    gap: 0px;\n    position: absolute;\n    bottom: 0;\n    left: 0;\n    right: 0;\n}\n\n.paginationContainer button {\n    cursor: pointer;\n    border: none;\n    background-color: #F9F9F9;\n    height: 32px;\n    width: 32px;\n    padding: 0px;\n    color: #151414;\n    text-align: center;\n    font-family: Inter;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: 400;\n\n}\n\n.paginationContainer button img {\n    height: 10px;\n    width: 10px;\n}\n\n.paginationContainer button:disabled {\n    cursor: not-allowed;\n}\n\n.activePage {\n  background-color: #FFFFFF !important;\n  color: #3893FF;\n  box-shadow: 0px 1px 4px 0px rgba(26, 26, 67, 0.10);\n  border-radius: 4px;\n}"
  },
  {
    "path": "ui/src/pages/Deploy/Deploy.jsx",
    "content": "import { useEffect, useState } from 'react';\nimport RouteTab from 'src/components/RouteTab/RouteTab';\nimport TitleDescription from 'src/components/TitleDescription/TitleDescription';\nimport TitleDescriptionContainer from 'src/components/TitleDescription/TitleDescriptionContainer';\nimport Button from 'src/components/Button/Button';\nimport style from \"./Deploy.module.css\"\nimport { deployTabroutes } from './deployTabRoutes';\nimport { RiRestartLine } from 'react-icons/ri';\nimport { API_URL } from 'src/config/const';\nimport PostService from 'src/utils/http/PostService';\nimport { toast } from 'react-toastify';\n\n\nconst Deploy = ({currentConfigID}) => {\n\n  const generateYMAL = ()=>{\n    PostService(API_URL + `/connector/createyaml/${currentConfigID}`,{},{loaderText: \"Restarting Chatbot\"}).then(()=>{\n        toast.success(\"Chatbot Restarted\")\n    }).catch(()=>{\n        toast.error(\"Failed to restart bot\")\n    })\n  }\n\n  return (\n    <div>\n      <div className={style.DeployURLContainer}>\n      <TitleDescriptionContainer>\n          <TitleDescription orderNumber={1} title='Restart your Chatbot' description='Deploy your chatbot to experience real-time updates based on your configuration changes.' />\n        </TitleDescriptionContainer>\n      <div className={`${style.DeployPageButton}`}>\n        <Button onClick={generateYMAL} > \n          Restart Chatbot  <RiRestartLine/>\n        </Button>\n\n      </div>\n        <TitleDescriptionContainer>\n          <TitleDescription orderNumber={2} title='Deployment details' description='Get the URL to preview your chatbot live and the embed code to integrate it into your website or app.' />\n        </TitleDescriptionContainer>\n        <div>\n\n        </div>\n        \n        <div style={{padding: \"0px 30px\"}}>\n          <RouteTab Deployroutes={deployTabroutes(currentConfigID)}/>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default Deploy;\n"
  },
  {
    "path": "ui/src/pages/Deploy/Deploy.module.css",
    "content": ".DeployPageButton{\n    display: inline-flex;\n    gap: 10px;\n    margin-bottom: 30px;\n    margin-left: 35px;\n}\n.LightButton{\n    border-radius: var(--4, 4px);\n    background: #ECF5FF;\n    color: #3893FF;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 500;\n    display: inline-flex;\n    align-content: center;\n    align-items: center;\n    gap: 10px\n}\n\n.DeployURLContainer{\n    max-width: 1180px;\n}\n\n\n\n.SmallTabContainer{\n    width: 397px;\n    display: flex;\n}\n\n"
  },
  {
    "path": "ui/src/pages/Deploy/DeployTabs/CopyEmbedCode.jsx",
    "content": "import RouteTab from 'src/components/RouteTab/RouteTab'\nimport TitleDescription from 'src/components/TitleDescription/TitleDescription'\nimport { ChatBotEmbeddedCodeTabs } from '../deployTabRoutes'\n\nconst CopyEmbedCode = ({currentConfigID}) => {\n    return (\n        <div>\n            <TitleDescription showOrder={false} title={\"Select Chatbot Layout\"} description={\"Pick the ideal table layout to fit your website or app's design.\"} />\n            <RouteTab ContainerStyle={{width:\"350px\"}} TabStyle={{padding:\"13px 4px\", width:\"fitcontent\",fontSize:\"14px\"}} Deployroutes={ChatBotEmbeddedCodeTabs(currentConfigID)} />\n        </div>\n    )\n}\n\nexport default CopyEmbedCode"
  },
  {
    "path": "ui/src/pages/Deploy/DeployTabs/CopyURL.jsx",
    "content": "import { useRef } from 'react'\nimport style from './DeployTabs.module.css'\nimport { PiCopySimpleBold } from \"react-icons/pi\";\nimport Button from 'src/components/Button/Button';\nimport TitleDescription from 'src/components/TitleDescription/TitleDescription';\nimport preview from \"src/assets/icons/preview-arrow.svg\"\nimport { v4 } from 'uuid';\n\n\nconst CopyURL = () => {\n\n   \n    const CopyUrlRef = useRef(null)\n    const previewURL = `http://${window.location.host}/${v4()}/chat`\n    const handleCopyUrl=()=>{\n       try {\n            var copyText = CopyUrlRef.current.innerText;\n            if(copyText){\n                navigator.clipboard.writeText(copyText);\n            }\n       } catch {}\n    }\n    return (\n        <>\n            <div>\n                <TitleDescription showOrder={false} title={\"Copy URL for live preview\"} description={\"Provide your database connection details and database data description can make your application more efficient.\"} />\n            </div>\n            <div className={`${style.CopyContainer}`}>\n                <div className={`${style.CopyLinkContainer}`}>\n                    <div className={`${style.CopyLinkInputBox}`}>\n                        <div ref={CopyUrlRef} contentEditable={false} className={`${style.CopyText}`}>{previewURL}</div><span onClick={handleCopyUrl} className={`${style.CopyNow}`}><span >Copy URL</span><PiCopySimpleBold size={18} /></span>\n                    </div>\n                </div>\n                <a href={previewURL} target='_blank'>\n                    <Button buttonType=\"submit\" className={`${style.ButtonClass}`}>Preview<img src={preview} alt=\"previewIcon\"/></Button>\n                </a>\n            </div>\n        </>\n    )\n}\n\nexport default CopyURL"
  },
  {
    "path": "ui/src/pages/Deploy/DeployTabs/DeployTabs.module.css",
    "content": ".CopyLinkInputBox {\n    flex-grow: 1;\n    display: flex;\n    border-radius: 6px;\n    border: 0.5px #F9F9F9;\n    outline: none;\n    background: #F9F9F9;\n    padding: 10px 3.84px 10px 16px;\n}\n\n.CopyLinkInputBox:focus {\n    border: 0.5px solid #3893FF;\n    outline: none;\n}\n\n.CopyNow {\n    color: #3893FF;\n    cursor: pointer;\n    border-radius: var(--4, 4px);\n    background: #ECF5FF;\n    font-family: Inter;\n    font-size: 16px;\n    padding: 4px 13px;\n    margin-right: 4px;\n    display: inline-flex;\n    font-style: normal;\n    gap: 6px;\n}\n\n.CopyText {\n    outline: none;\n    flex-grow: 1;\n    color: #888787;\n    font-feature-settings: 'liga' off, 'clig' off;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px;\n    /* 142.857% */\n    display: inline-flex;\n    align-content: center;\n    align-items: center;\n    outline: n;\n    overflow-x: auto;\n    white-space: nowrap;\n    max-width: 600px; \n}\n\n.CopyLinkContainer {\n    flex-grow: 1;\n\n}\n\n.CopyContainer{\n    max-width: 900px;\n    display: flex;\n    gap: 10px;\n    align-items: center;\n}\n\n.ButtonClass {\n    border-radius: var(--4, 4px);\n}\n\n.MiniMaxContainer{\n    display: flex;\n    justify-items: start;\n    align-content: flex-end;\n    align-items: flex-start;\n    gap: 50px;\n}\n\n.MiniMaxContainer .SubContents:nth-child(2) {\n    margin-top: 42px;\n    width: 380;\n    height: 270px;\n}\n\n.SubContents{\n    /* width: 50%; */\n}\n\n@media (max-width: 1366px) {\n    .MiniMaxContainer {\n        flex-direction: column;\n        gap: 10px;\n    }\n    .MiniMaxContainer .SubContents:nth-child(2) {\n        margin-top: 0;\n    }\n}"
  },
  {
    "path": "ui/src/pages/Deploy/DeployTabs/MaximizedLayout.jsx",
    "content": "\nimport CodeBlock from 'src/components/CodeBlock/CodeBlock'\nimport TitleDescription from 'src/components/TitleDescription/TitleDescription'\nimport style from './DeployTabs.module.css'\nimport Screenshot from \"src/assets/images/screen_shot.svg\"\nimport { API_URL } from \"src/config/const\"\n\nconst MaximizedLayout = ({ currentConfigID }) => {\n    return (\n        <>\n            <TitleDescription showOrder={false} title='Copy code for Maximized Layout' description='Experience a rich view environment with the minimized view' />\n            <div className={style.MiniMaxContainer}>\n                <div className={style.SubContents}>\n                <CodeBlock codeString={`<script>\n(function injectChatbot() {\n    const script = document.createElement('script');\n    script.src = 'http://${window.location.host}/ui/dist-library/chatbot.js';\n    script.type = 'text/javascript';\n    script.onload = function () {\n    const container = document.createElement('div');\n    container.id = 'chatbox-container';\n    document.body.appendChild(container);\n    if (ChatBot.mountChatbox) {\n        ChatBot.mountChatbox('chatbox-container', {\n        apiURL: '${API_URL}',\n        configID: ${currentConfigID},\n        uiSize: 'large',\n        });\n    } else {\n        console.error('ChatBot object is not defined.');\n    }\n    };\n    document.head.appendChild(script);\n})();\n</script>`} />\n                </div>\n                <div className={style.SubContents}>\n                    <img src={Screenshot} alt=\"raggnie UI\" />\n                </div>\n            </div>\n        </>\n    )\n}\n\nexport default MaximizedLayout"
  },
  {
    "path": "ui/src/pages/Deploy/DeployTabs/MinimizedLayout.jsx",
    "content": "import CodeBlock from 'src/components/CodeBlock/CodeBlock'\nimport TitleDescription from 'src/components/TitleDescription/TitleDescription'\nimport style from './DeployTabs.module.css'\nimport Screenshot from \"src/assets/images/screen_shot_small.svg\"\nimport { API_URL } from \"src/config/const\"\n\nconst MinimizedLayout = ({ currentConfigID }) => {\n    return (\n        <>\n            <TitleDescription showOrder={false} title='Copy code for Minimized Layout' description='Experience a rich view environment with the minimized view' />\n            <div className={style.MiniMaxContainer}>\n                <div className={style.SubContents}>\n                <CodeBlock codeString={`<script>\n(function injectChatbot() {\n    const script = document.createElement('script');\n    script.src = 'http://${window.location.host}/ui/dist-library/chatbot.js';\n    script.type = 'text/javascript';\n    script.onload = function () {\n    const container = document.createElement('div');\n    container.id = 'chatbox-container';\n    document.body.appendChild(container);\n    if (ChatBot.mountChatbox) {\n        ChatBot.mountChatbox('chatbox-container', {\n        apiURL: '${API_URL}',\n        configID: ${currentConfigID}\n        });\n    } else {\n        console.error('ChatBot object is not defined.');\n    }\n    };\n    document.head.appendChild(script);\n})();\n</script>`} />\n                </div>\n                <div className={style.SubContents}>\n                    <img src={Screenshot} alt=\"raggnie UI\" />\n                </div>\n\n            </div>\n        </>\n    )\n}\n\nexport default MinimizedLayout"
  },
  {
    "path": "ui/src/pages/Deploy/deployTabRoutes.jsx",
    "content": "import CopyEmbedCode from \"./DeployTabs/CopyEmbedCode\";\nimport CopyURL from \"./DeployTabs/CopyURL\";\nimport MaximizedLayout from \"./DeployTabs/MaximizedLayout\";\nimport MinimizedLayout from \"./DeployTabs/MinimizedLayout\";\n\nexport const deployTabroutes = (currentConfigID) => [\n  {\n    title: \"Get URL for live preview\",\n    path: \"/copyURL\",\n    icon: \"\",\n    page: <CopyURL />,\n    isPrivate: true,\n  },\n  {\n    title: \"Copy Chatbot embed code\",\n    path: \"/copyEmbedCode\",  \n    icon: \"\",\n    page: <CopyEmbedCode currentConfigID={currentConfigID}/>,\n    isPrivate: true,\n  },\n];\n\nexport const ChatBotEmbeddedCodeTabs = (currentConfigID) => [\n  {\n    title: \"Minimized Layout\",\n    path: \"/minimzedLayout\",\n    icon: \"\",\n    page: <MinimizedLayout currentConfigID={currentConfigID}/>,\n    isPrivate: true,\n  },\n  {\n    title: \"Expanded Layout\",\n    path: \"/maximizedLayout\",  \n    icon: \"\",\n    page: <MaximizedLayout currentConfigID={currentConfigID}/>,\n    isPrivate: true,\n  },\n];\n"
  },
  {
    "path": "ui/src/pages/Preview/ChatBox.jsx",
    "content": "import ChatBox from \"src/components/ChatBox/ChatBox\"\nimport {  useEffect, useRef, useState } from \"react\"\nimport GetService from \"src/utils/http/GetService\"\nimport { API_URL } from \"src/config/const\"\nimport PostService from \"src/utils/http/PostService\"\nimport { v4 as uuidv4 } from 'uuid';\nimport { useNavigate, useParams } from \"react-router-dom\"\nimport EmptyPreview from \"./EmptyPreview\"\nimport { getConnectors } from \"src/services/Connectors\"\nimport { getBotConfiguration, getBotConfigurationById, restartBot } from \"src/services/BotConfifuration\"\nimport { toast } from \"react-toastify\"\nimport { isEmptyJSON } from \"src/utils/utils\"\nimport useAppSettings from \"src/store/authStore\";\n\n\n\nconst PreviewChatBox = ({urlPrex = \"/preview\", selectedOption, setSelectedOption})=>{ \n    const { envID } = useAppSettings();\n    const [feedbackStatus, setFeedbackStatus] = useState(false); // for dislike and like activation\n    const [currentConfigID, setCurrentConfigID] = useState(0)\n    const [conversations, setConversation] = useState([])\n    const [chatHistory,setchatHistory] = useState([])\n    const [currentChat, setCurrentChat] = useState({})\n    const [isChatLoading, setIsChatLoading] = useState(false) \n    const [enableChatbox, setEnableChatbox] = useState(false)\n    const [currentState, setCurrentState] = useState(1)\n    // currentState Values\n    // 1. to add plungs\n    // 2. setup bot configuration\n    // 3. restart bot\n\n\n    let { contextId } = useParams()\n    const navigate = useNavigate()\n    const messageBoxRef = useRef(null)\n\n    const chatQuery = (message)=>{\n\n        setCurrentChat({isBot: false, message: message})\n        \n            let axiosConfig = {\n                headers: {}\n            }\n            setIsChatLoading(true)\n            PostService(API_URL + `/query/query?contextId=${contextId}&configId=${currentConfigID}&envId=${envID}`,\n                    { \"content\": message, \"role\":\"user\" }, {showLoader: false,allowAuthHeaders:true}, axiosConfig).then(response=>{\n                       \n                let res = response.data\n                let chatMessage =  res.response.content\n                let chatError = isEmptyJSON(res.response.error) ? \"\" : res.response.error\n                let chatEntity =  res.response.main_entity\n                let chatFormat = res.response.main_format\n                let chatKind = res.response.kind\n                let chatData =  { \n                        chart: {\n                            data: res.response.data,\n                            title: res.response.title,\n                            xAxis: res.response.x,\n                            yAxis: res.response.y\n                        },\n                        query: res.response.query\n                    }\n                \n              \n                setCurrentChat({isBot: true, message: chatMessage, entity: chatEntity, error: chatError, format: chatFormat, kind: chatKind, data: chatData })\n                setIsChatLoading(false)\n                getChatHistory()\n                \n            }).catch((err)=>{\n                setIsChatLoading(false)\n                setCurrentChat({isBot: true, message: \"Oops somethings went wrong, try again\", error: err.message, format: \"general_message\", kind: \"none\", data: [] })\n            })\n    }\n\n    const onChatBoyKeyDown = (e)=>{\n\n        if(e.keyCode  == 13){\n            e.preventDefault()\n            let message = e.target.innerText;\n            if(message != \"\"){\n                chatQuery(message)\n                e.target.innerText = \"\"\n            }\n        }\n    }\n    \n    const onSendClick = ()=>{\n        let message = messageBoxRef.current.innerText;\n        if(message != \"\"){\n            chatQuery(message)\n            messageBoxRef.current.innerText = \"\"\n        }\n    }\n\n    const getChatByContexts =(contextId)=>{\n        GetService(API_URL + `/chat/get/${contextId}`,{},{allowAuthHeaders:false}).then(response=>{\n            const chats = response.data.data.chats\n            let tempChat = [];\n            let tempChatDetails = [];\n\n            chats?.map(chat =>{ \n\n                let chatData =  { \n                    chart: {\n                        data: chat.chat_answer.data,\n                        title: chat.chat_answer.title,\n                        xAxis: chat.chat_answer.x,\n                        yAxis: chat.chat_answer.y\n                    },\n                    query: chat.chat_answer.query\n                }\n\n               \n                tempChat.push({isBot: false, message: chat.chat_query, chat_context_id: chat.chat_context_id, chat_id: chat.chat_id, feedback_status: 0, })\n                tempChat.push({isBot: true, message: chat.chat_answer.content, error:  isEmptyJSON(chat.chat_answer.error) ? \"\" : chat.chat_answer.error, entity: chat.chat_answer.main_entity, format: chat.chat_answer.main_format, kind: chat.chat_answer.kind, data: chatData })\n            })\n            setConversation(tempChat)\n        }).catch(() => {\n            navigate('/error')\n        })\n    }\n\n// ===================CHAT HISTROY START==============================\n    const getChatHistory = () => {\n        GetService(API_URL + `/chat/list/context/all/${envID}`,{},{allowAuthHeaders:false}).then(response => {  \n            let chatHistory = []; \n            let chats = response.data.data.chats;\n            \n            chats?.map((item) => {\n                chatHistory.push({\n                    chatId: item.chat_id,\n                    chatContextId: item.chat_context_id,\n                    chatQuery: item.chat_query,\n                    chatSummary: item.chat_summary,\n                    chatConfigurationId: item.configuration_id,\n                    date: new Date(item.created_at), // Convert date string to Date object\n                });\n            });     \n            chatHistory = chatHistory.reverse()      \n            setchatHistory(chatHistory);\n        })\n    }\n\n    function generateContextUUID() {\n        return uuidv4();\n    }\n\n    const onCreateNewChat=()=>{\n        navigate(`${urlPrex}/${generateContextUUID()}/chat`)\n      }\n\n    const handleNavigateChatContext=(e, contextId, configId)=>{\n        getBotConfigurationById(configId).then((response) => { \n            const option = { value: configId, label: response.data?.data?.configuration?.name }\n            setSelectedOption(option)\n        })\n        setCurrentConfigID(configId)\n        navigate(`${urlPrex}/${contextId}/chat`)    \n    }\n\n// ===================CHAT HISTROY END==============================\n\n    const getPluginList = ()=>{  \n            getConnectors().then(response=>{\n                if (response.data.data.connectors?.length > 0){\n                    getConfig()\n                }else{\n                    setCurrentState(1)\n                }\n            })\n    }\n\n    const getConfig = ()=>{\n        getBotConfiguration().then(response=>{\n            let configs = response.data?.data?.configurations\n            if(configs?.length > 0){\n                if(configs[0].inference[0]?.id){\n                    if(configs[0].status == 1){\n                        setCurrentState(3)\n                    }else{\n                        setEnableChatbox(true)\n                    }\n                }else {\n                    setCurrentState(2)\n                }\n            }else{\n                setCurrentState(2)\n            }\n        })\n    }\n\n\n    const onFeedback = (e, feedbackStatus, feedbackMessage = \"\", message) => {\n\n        PostService(API_URL + `/chat/feedback`, {\n            chat_context_id: message.chat_context_id,\n            chat_id: message.chat_id,\n            feedback_status: feedbackStatus === true ? 1 : 0, \n            feedback_json: { reason: feedbackMessage }\n        })\n        .then(response => {\n            setFeedbackStatus(response.data.feedback_status === 1 ? true : false );\n        })\n    };\n\n    const restartChatBot = ()=>{\n        restartBot(currentConfigID).then(()=>{\n            toast.success(\"Chatbot Restarted\")\n            setEnableChatbox(true)\n        }).catch(()=>{\n            toast.error(\"Failed to restart bot\")\n        })\n    }\n\n\n    \n    useEffect(()=>{\n        if(currentChat.message){\n            let tempConversation = JSON.parse(JSON.stringify(conversations))\n            tempConversation.push(currentChat)\n            setConversation(tempConversation)\n        }\n    },[currentChat])\n\n    useEffect(()=>{\n        getChatByContexts(contextId)\n    }, [contextId])\n\n    useEffect(() => {\n        if (selectedOption?.value) {\n            setCurrentConfigID(selectedOption.value);\n        }\n    }, [selectedOption])\n\n\n    useEffect(()=>{\n        getChatHistory()\n        getPluginList();\n        if(contextId == undefined){\n            onCreateNewChat()\n        }\n     },[])\n \n\n    return(\n        <>\n            {enableChatbox ? <ChatBox messageBoxRef={messageBoxRef} handleNavigateChatContext={handleNavigateChatContext} onCreateNewChat={onCreateNewChat} chatHistory={chatHistory} isLoading={isChatLoading} conversations={conversations} onKeyDown={onChatBoyKeyDown} onSendClick={onSendClick}  /> :<EmptyPreview currentState={currentState} onRestartBot={restartChatBot} />} \n            \n        </>\n    )\n}\n\nexport default PreviewChatBox"
  },
  {
    "path": "ui/src/pages/Preview/EmptyPreview.jsx",
    "content": "import emptyConfiguationImg from \"src/assets/images/empty-configuration.svg\"\nimport style from \"./Preview.module.css\"\nimport Button from \"src/components/Button/Button\"\nimport { HiOutlinePlusCircle } from \"react-icons/hi\";\nimport { FaRegArrowAltCircleRight } from \"react-icons/fa\";\nimport restartIcon from \"src/assets/icons/restart.svg\"\nimport { Link } from \"react-router-dom\";\n\nconst EmptyPreview = ({currentState = 1, onRestartBot = ()=>{}})=>{\n\n    return(\n        <>\n            <div className={style.EmptyDataContainer}>\n                <div className={style.EmptyDataHeader}>\n                    <h1 className={style.EmptyDataHeading}>Set Up Your Bot in 3 Easy Steps</h1>\n                    <p className={style.EmptyDataParagraph}>Easily configure and launch your AI. Connect data, customize, and embed it for instant use</p>\n                </div>\n                <div className={style.StatusTimelimeContainer}>\n                    <ul className={style.StatusTimeline}>\n                        <li data-index=\"1\"  className={currentState == 1 ? style.Current: currentState > 1 ? style.Completed : \"\"}>\n\n                            <div className={style.StatusTimelineContent}>\n                                <h6 className={style.StatusTimelineTitle}>Add Plugin</h6>\n                                <div className={currentState != 1 ? style.StatusTimelineContentHide : \"\"}>\n                                    <p className={style.StatusTimelineDescription}>You don't have any plugins added, click here to add one.</p>\n                                    <Link to={\"/plugins\"}>\n                                        <Button>Connect Plugin <HiOutlinePlusCircle size={22}/></Button>\n                                    </Link>\n                                </div>\n                               \n                            </div>\n\n                        </li>\n                        <li data-index=\"2\" className={currentState == 2 ? style.Current: currentState > 2 ? style.Completed : \"\"} >\n                            <div className={style.StatusTimelineContent}>\n                                <h6 className={style.StatusTimelineTitle}>Bot Configuration</h6>\n                                <div className={`${currentState != 2 ? style.StatusTimelineContentHide : \"\"}`}>\n                                    <p className={style.StatusTimelineDescription}>Your chatbot configuration is incomplete.</p>\n                                    <Link to={\"/bot-configuration\"}>\n                                        <Button>Go to Bot Configuration <FaRegArrowAltCircleRight size={18}/></Button>\n                                    </Link>\n                                </div>\n                            </div>\n\n                        </li>\n                        <li data-index=\"3\" className={currentState == 3 ? style.Current: currentState > 3 ? style.Completed : \"\"}>\n                            <div className={style.StatusTimelineContent}>\n                                <h6 className={style.StatusTimelineTitle}>Restart Bot</h6>\n                                <div className={`${currentState != 3 ? style.StatusTimelineContentHide : \"\"}`}>\n                                    <p className={style.StatusTimelineDescription}>Please restart your chatbot to see recent configuration.</p>\n                                    <Button onClick={onRestartBot} >Restart Chatbot <img src={restartIcon}/> </Button>\n                                </div>\n                            </div>\n\n                        </li>\n                    </ul>\n                </div>\n            </div>\n        </>\n    )\n}\n\nexport default EmptyPreview"
  },
  {
    "path": "ui/src/pages/Preview/Preview.jsx",
    "content": "import { useState, useEffect } from \"react\";\nimport DashboardBody from \"src/layouts/dashboard/DashboadBody\"\nimport PreviewChatBox from \"./ChatBox\"\nimport { getBotConfiguration } from \"src/services/BotConfifuration\";\n\n\nconst Preview = ()=>{ \n    const [select, setSelect] = useState(false);\n    const [options, setOptions] = useState([]);\n    const [selectedOption, setSelectedOption] = useState(null);\n    \n\n    const getConfig = ()=>{\n            getBotConfiguration().then(response=>{\n                let configs = response.data?.data?.configurations\n                if(configs?.length > 0){\n                    setSelect(true)\n                    let configList = []\n                    configs.map(item => {\n                        configList.push({ value: item.id, label: item.name})\n                    })\n                    setOptions(configList);  \n                    setSelectedOption(configList[0])\n                }\n            })\n        }\n    \n    useEffect(() => {\n        getConfig(); \n    }, []);\n\n    return(\n        <DashboardBody title=\"Preview\" options={options} select={select} selectedOption={selectedOption} setSelectedOption={setSelectedOption} containerStyle={{padding: \"0px 0px\", height: \"calc(100vh - 76px)\"}}>\n            <PreviewChatBox selectedOption={selectedOption} setSelectedOption={setSelectedOption}/>\n        </DashboardBody>\n    )\n}\n\nexport default Preview"
  },
  {
    "path": "ui/src/pages/Preview/Preview.module.css",
    "content": ".PreviewBody{\n    display: flex;\n    align-content: space-between;\n    justify-content: space-around;\n}\n.EmptyDataContainer {\n    text-align: center;\n    margin-top: 10vh;\n}\n\n\n.EmptyDataHeader {\n    \n}\n\n.EmptyDataHeading {\n    color: #323232;\n    text-align: center;\n    font-family: Inter;\n    font-size: 20px;\n    font-style: normal;\n    font-weight: 500;\n}\n\n.EmptyDataParagraph {\n\n    color: #888787;\n    text-align: center;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    text-align: center;\n    width: 500px;\n    margin: auto;\n\n}\n\n\n.StatusTimeline {\n    margin: 2.5em 0;\n    padding: 0;\n    display: inline-block;\n    margin-left: 35px;\n}\n  \n.StatusTimeline li {\n    list-style: none;\n    margin: auto;\n    min-height: 30px;\n    border-left: 3px solid #F0F0F0;\n    padding: 0 0 40px 30px;\n    position: relative;\n    cursor: pointer;\n}\n  \n.StatusTimeline li:last-child {\n    border-left: 0;\n}\n\n  \n.StatusTimeline li::before {\n    position: absolute;\n    left: -28px;\n    border-radius: 500%;\n    background: #F0F0F0;\n    height: 32px;\n    width: 32px;\n    content:  attr(data-index);\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    color: #323232;\n    border: 10px solid white;\n    font-family: Inter;\n}\n\n.StatusTimeline li.Current::before {\n    background: #FCBD73;\n    color: #FFFFFF;\n}\n\n.StatusTimeline li.Completed::before {\n    background: #76D3AC;\n    color: #FFFFFF;\n}\n\n\n\n.StatusTimeline li:last-child::before {\n    left: -25px;\n}\n\n.StatusTimelineContent {\n    padding-top: 14px;\n    text-align: left;\n}\n\n.StatusTimelineContentHide {\n    display: none;\n}\n\n\n.StatusTimelineTitle {\n    color: #323232;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 24px;\n    margin: 0px;\n}\n\n.StatusTimelineDescription {\n    color: #888787;\n    font-family: Inter;\n    font-size: 16px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 26px;\n}\n  \n\n\n/* end Empty Configuration Page ****/"
  },
  {
    "path": "ui/src/pages/Samples/EmptySample.jsx",
    "content": "import Button from \"src/components/Button/Button\"\nimport { HiOutlinePlusCircle } from \"react-icons/hi\";\nimport emptySampleImg from \"./assets/empty-icon.svg\"\nimport style from \"./Samples.module.css\"\n\nconst EmptySample = ( {onCreateClick = ()=>{}} )=>{\n\n    return(\n        <>\n            <div className={style.EmptySample}>\n                    <div> <img src={emptySampleImg}/> </div>\n                    <div><p>You don't have any samples created, to get started <br/> go and add a sample</p> </div>\n                    <div> <Button onClick={onCreateClick}>Create Sample <HiOutlinePlusCircle/></Button> </div>\n            </div>\n        </>\n    )\n}\n\nexport default EmptySample"
  },
  {
    "path": "ui/src/pages/Samples/SampleForm.jsx",
    "content": "import Button from \"src/components/Button/Button\"\nimport Input from \"src/components/Input/Input\"\nimport Textarea from \"src/components/Textarea/Textarea\"\nimport { FiCheckCircle, FiXCircle} from \"react-icons/fi\"\nimport { Controller, useForm } from \"react-hook-form\"\nimport Select from \"src/components/Select/Select\"\nimport { useEffect, useState } from \"react\"\nimport { getConnectors } from \"src/services/Connectors\"\nimport { saveSamples } from \"src/services/Sample\"\nimport { toast } from \"react-toastify\"\n\nconst SampleForm = ({ sample = {}, afterCreate = ()=>{}, onCancel = ()=>{}})=>{\n\n\n    const [connectors, setConnectors] = useState([])\n    // const [sampleId, setSampleId] = use\n\n    const { register, handleSubmit, setValue , control, formState , reset: resetForm } = useForm({mode : \"all\"})\n    const { errors, isValid: isFormValid } = formState\n\n\n    const getAllConnectors = ()=>{\n        getConnectors([2, 5]).then(response=>{\n\n            let tempOptions = [];\n            response.data?.data?.connectors?.map(item=>{\n                tempOptions.push({label: item.connector_name, value: item.connector_id})\n            })\n            setConnectors(tempOptions)\n        })\n    }\n\n\n    const saveSample = (data)=>{\n        saveSamples(sample.id, {\n            connect_id: data.connector,\n            metadata: data.metadata,\n            query: data.query,\n            question: data.question\n        }).then(response=>{\n            toast.success(\"Sample saved successfully\")\n            afterCreate(response.data?.data)\n        }).catch(()=>{\n            toast.error(\"Sample saved failed\")\n        })\n    }\n\n    useEffect(()=>{\n        resetForm()\n        if(sample.id){\n            setValue(\"question\", sample.description)\n            setValue(\"query\", sample.sql_metadata?.query)\n            setValue(\"metadata\", sample.sql_metadata?.metadata)\n            setValue(\"connector\", sample.connector_id)\n        }\n    },[sample])\n\n    useEffect(()=>{\n        getAllConnectors()\n    },[])\n\n    return(\n        <div>\n            <form onSubmit={handleSubmit(saveSample)}>\n                <div>\n                    <Input label={<span className=\"span-important\">Question</span>} hasError={errors[\"question\"]?.message} errorMessage={errors[\"question\"]?.message} {...register(\"question\", {required: \"This is required\"})} />\n                </div>\n                <div>\n                    <Controller\n                        control={control}\n                        name=\"connector\"\n                        rules={{\n                            required: \"This field is required\"\n                        }}\n                        render={({ field: { onChange, value, ref } })=>(\n                            <Select\n                                inputRef={ref}\n                                label={ <span className=\"span-important\">Connector</span> }\n                                value={connectors.find(c => c.value === value)}\n                                options={connectors}\n                                onChange={val=>onChange(val.value)} />\n                        )}\n\n                    />\n\n                </div>\n                <div>\n                    <Textarea label={<span className=\"span-important\">Query</span>} rows={6} style={{resize: \"vertical\"}} hasError={errors[\"query\"]?.message} errorMessage={errors[\"query\"]?.message} {...register(\"query\", {required: \"This is required\"})}  />\n                </div>\n                <div>\n                    <Textarea label=\"Metadata\" rows={6} style={{resize: \"vertical\"}} hasError={errors[\"metadata\"]?.message} errorMessage={errors[\"metadata\"]?.message} {...register(\"metadata\")} />\n                </div>\n                <div className=\"flex flex-gap-10 justify-content-end\">\n                    <div>\n                        <Button variant=\"secondary-danger\" onClick={onCancel}>Cancel <FiXCircle/></Button>\n                    </div>\n                    <div>\n                        <Button  buttonType=\"submit\" disabled={isFormValid ? false: true} onClick={onCancel}>Save <FiCheckCircle/></Button>\n                    </div>\n                </div>\n            </form>\n        </div>\n    )\n\n}\n\nexport default SampleForm"
  },
  {
    "path": "ui/src/pages/Samples/SampleList.jsx",
    "content": "import Button from \"src/components/Button/Button\"\nimport { HiOutlinePlusCircle } from \"react-icons/hi\";\nimport { FaPen } from \"react-icons/fa6\"\nimport { BsQuestionSquare } from \"react-icons/bs\";\nimport Table from \"src/components/Table/Table\"\nimport style from \"./Samples.module.css\"\nimport TitleDescription from \"src/components/TitleDescription/TitleDescription\";\n\n\nconst SampleList = ({data, onCreate=()=>{}, onEdit = ()=>{}})=>{\n\n\n    const tableColums = [\n        {\n            name: 'Question List',\n            selector: row =><div className=\"flex flex-align-center flex-gap-10\"> <span> <BsQuestionSquare color=\"#BEBEBE\" size={18}/></span> <span> {row.description}</span> </div>  ,\n            grow: 1,\n        },\n        {\n            name: '',\n            selector: row => <><span onClick={()=>onEdit(row)}> <FaPen color=\"#84BCFF\" size={16}/> </span></> ,\n            width: \"80px\"\n        },\n    ]\n\n    const rowExpandComponent = (row)=>{\n        return(\n             <div className={style.SampleExpandContaner}>\n                <div className={style.SampleExpandRow}>\n                    <span className={style.SampleRowLabel}>Query :</span> <span>{row.data?.sql_metadata?.query}</span>\n                </div>\n                <div className={style.SampleExpandRow}>\n                    <span className={style.SampleRowLabel} style={{marginRight: \"5px\"}}>Metadata :</span><span>{row.data?.sql_metadata?.metadata}</span>\n                </div>\n            </div>\n        )\n    }\n\n\n    return(\n        <div>\n            <div className=\"text-align-right\" style={{marginBottom: \"41px\"}}>\n                <Button onClick={onCreate}>Create Sample <HiOutlinePlusCircle/></Button>\n            </div>\n            <div>\n                <TitleDescription title=\"Samples List\" description=\"Please provide additional samples to enhance the accuracy and effectiveness of the results. More examples will help improve the quality of analysis and ensure better outcomes.\" />\n            </div>\n            <div>\n                <Table columns={tableColums} data={data} expandableRows={true} expandableRowsComponent={rowExpandComponent} />\n            </div>\n        </div>\n    )\n\n}\n\nexport default SampleList"
  },
  {
    "path": "ui/src/pages/Samples/Samples.jsx",
    "content": "import DashboardBody from \"src/layouts/dashboard/DashboadBody\"\nimport EmptySample from \"./EmptySample\"\nimport Modal from \"src/components/Modal/Modal\"\nimport { useEffect, useState } from \"react\"\nimport SampleForm from \"./SampleForm\"\nimport { getSamples } from \"src/services/Sample\"\nimport SampleList from \"./SampleList\"\nimport { useNavigate } from \"react-router-dom\";\n\n\nconst Samples = ()=>{\n    const navigate = useNavigate()\n    const [sampleList, setSampleList] = useState([])\n    const [showSampleModal, setSampleModal] = useState(false)\n    const [editSample, setEditSample] = useState({})\n\n    const  getAllSamples = ()=>{\n        getSamples().then(response=>{\n            setSampleList(response.data?.data?.sql ?? [])\n        }).catch(() => {\n            navigate('/error')\n        })\n    }\n\n    const onEdit = (sampleData)=>{\n        setSampleModal(true)\n        setEditSample(sampleData)\n    }\n\n    const onCreateNew = ()=>{\n        setSampleModal(true)\n        setEditSample({})\n    }\n\n\n    useEffect(()=>{\n        getAllSamples()\n    }, [])\n\n    return(\n       <DashboardBody title=\"Samples\">\n\n        { sampleList?.length == 0 && <EmptySample onCreateClick={()=>setSampleModal(true)} /> }\n        { sampleList?.length > 0 && <SampleList data={sampleList} onCreate={onCreateNew} onEdit={onEdit} /> }\n\n        <Modal title=\"Create Sample\" show={showSampleModal} onClose={()=>setSampleModal(false)} >\n            <SampleForm sample={editSample} afterCreate={getAllSamples} onCancel={()=>setSampleModal(false)} />\n        </Modal>\n       </DashboardBody>\n    )\n}\n\nexport default Samples"
  },
  {
    "path": "ui/src/pages/Samples/Samples.module.css",
    "content": "\n\n\n\n\n/* Empty Sample */\n\n.EmptySample {\n    margin-top: 25vh;\n    display: flex;\n    flex-direction: column;\n    text-align: center;\n    gap: 14px;\n}\n\n\n/* Row Expand */\n \n.SampleExpandContaner{\n    display: flex;\n    flex-direction: column;\n    gap: 2px;\n    padding: 10px 20px;\n}\n\n.SampleExpandRow {\n    border-radius: 4px;\n    background: #F5FAFF;\n    padding: 9px 20px;\n\n}\n\n.SampleRowLabel {\n    color: #323232;\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px;\n    width: 100px;\n    display: inline-block;\n}"
  },
  {
    "path": "ui/src/pages/Sources/Connetor.jsx",
    "content": "\nimport { Link } from \"react-router-dom\"\nimport style from \"./Sources.module.css\"\nimport { BACKEND_SERVER_URL } from \"src/config/const\"\n\nconst  Connector = ({connectorId, image, title, description, enabled, plugInkey})=>{\n\n    \n\n\n    return(\n        <>\n            <Link className={style.ConnectLink} to={enabled == true ? `/plugins/${connectorId}/${plugInkey}` : \"\" }>\n                <div className={style.SourceContainer}>\n                    {enabled == false && <div className={style.sourceOverlay}></div>}\n                    <div className={style.ConnectorImageContainer}>\n                        <img src={`${BACKEND_SERVER_URL}${image}`}/>\n                    </div>\n                    <div>\n                        <h6 className={style.ConnectorTitle}>{title}</h6>\n                        <span className={style.ConnectorDescription}>{description}</span>\n                    </div>\n                </div>\n            </Link>\n        </>\n    )\n}\n\nexport default Connector"
  },
  {
    "path": "ui/src/pages/Sources/Sources.jsx",
    "content": "import DashboardBody from \"src/layouts/dashboard/DashboadBody\"\nimport style from \"./Sources.module.css\"\nimport SearchInput from \"src/components/SearchInput/SearchInput\"\nimport Connector from \"./Connetor\"\nimport { useEffect, useState } from \"react\"\nimport { getProviders } from \"src/services/Plugins\"\nimport { useNavigate } from \"react-router-dom\";\n\nconst Sources = ()=>{\n\n\n    const navigate = useNavigate()\n    const [sources, setSource] = useState([])\n    const [searchedSource, setSearchSource] = useState([])\n\n    const loadSources = ()=>{\n        getProviders().then(response=>{\n            setSource(response.data.data.providers ?? [])\n            setSearchSource(response.data.data.providers ?? [])\n        }).catch(() => {\n            navigate('/error')\n        })\n    }\n\n    const onSearchSource = (e)=>{\n        let searchValue = e.target.value;\n        let searchResult = sources.filter(item=>item.name.toLowerCase().includes(searchValue))\n        setSearchSource(searchResult)\n    }\n\n\n\n\n    useEffect(()=>{\n       loadSources()\n    },[])\n\n    return (\n        <>\n            <DashboardBody title=\"Plugin List\">\n                    <SearchInput  placeholder=\"Search...\" style={{width: \"400px\"}} onChange={onSearchSource} />\n                    <div className={style.SourceList}>\n                        {searchedSource.map((item, index)=>{\n                            return  <Connector connectorId={item.id} plugInkey={item.key} image={item.icon} title={item.name} description={item.description} enabled={item.enable} />\n                        })}\n                        \n                        \n                    </div>\n            </DashboardBody>\n        </>\n    )\n}\n\n\nexport default Sources"
  },
  {
    "path": "ui/src/pages/Sources/Sources.module.css",
    "content": "\n/* sources page */\n.SourceList{\n    display: flex;\n    gap: 25px;\n    flex-wrap: wrap;\n    margin-top: 44px;\n\n}\n\n.ConnectorLink {\n    text-decoration:  none;\n}\n\n/*  */\n\n.ConnectLink {\n    text-decoration: none;\n}\n\n.SourceContainer {\n    display: flex;\n    width: 294px;\n    align-items: center;\n    gap: 11px;\n    cursor: pointer;\n    border-radius: 10px;\n    padding-right: 10px;\n    position: relative;\n}\n\n.sourceOverlay {\n    background-color: #fffefea3;\n    width: 100%;\n    height: 10px;\n    position: absolute;\n    height: 100%;\n    cursor: no-drop;\n    /* pointer-events: none; */\n}\n\n.SourceContainer:hover {\n    background-color: #F4F4F4;\n}\n\n.ConnectorImageContainer{\n    height: 80px;\n}\n\n.ConnectorImageContainer img {\n    height: 80px;\n    width: 80px;\n}\n\n.ConnectorTitle{\n    color: var(--neural-1);\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 600;\n    line-height: 20px;\n    margin: 0px;\n}\n\n.ConnectorDescription{\n    color: var(  --neural-3);\n    font-family: Inter;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 20px\n}"
  },
  {
    "path": "ui/src/routes/DashboardRoute.jsx",
    "content": "\nimport { Routes, Route } from \"react-router-dom\"\nimport routes from \"src/config/routes\"\nimport DashboardLayout from \"src/layouts/dashboard/Dashboard\"\n\nconst DashboardRoute = ()=>{\n\n    return(\n        <Routes>\n            <Route path='/' element={<DashboardLayout/>}>\n                {\n                routes.map((item, index)=>{\n                    return (\n                        <Route key={index} path={item.path} element={item.page} />\n                    )\n                })\n                }\n            </Route>\n      </Routes >\n    )\n\n}\n\nexport default DashboardRoute"
  },
  {
    "path": "ui/src/routes/MainRoute.jsx",
    "content": "\nimport { Routes, Route, Navigate} from \"react-router-dom\"\nimport DashboardLayout from \"src/layouts/dashboard/Dashboard\"\nimport routes from \"src/config/routes\"\nimport Chat from \"src/pages/Chat/Chat\"\nimport { v4 } from \"uuid\"\nimport AuthLogin from \"src/layouts/auth/AuthLogin\"\n\nconst MainRoute = () => {\n\n    return (\n        <Routes>\n\n            <Route path=\"/login\" element={<AuthLogin />} />\n            <Route path=\"/:contextId/chat\" element={<Chat/>} />\n            <Route path=\"/\"  element={ <Navigate to={`/preview/${v4()}/chat`} repalce={true} /> } />\n            <Route path='/' element={<DashboardLayout/>}>\n                {\n                routes.map((item, index)=>{\n                    return (\n                        <Route key={index} path={item.path} element={item.page} />\n                    )\n                })\n                }\n            </Route>\n           \n        </Routes>\n    )\n}\n\nexport default MainRoute"
  },
  {
    "path": "ui/src/services/Auth.js",
    "content": "import { redirect } from \"react-router-dom\";\nimport { API_URL } from \"src/config/const\";\nimport GetService from \"src/utils/http/GetService\";\nimport PostService from \"src/utils/http/PostService\";\n\nexport const AuthLoginService = (authCredentials) => {\n    return PostService(API_URL + `/auth/login`, authCredentials, { \n        showLoader: false,allowAuthHeaders:false},{});  \n};\n\nexport const IdpLoginService = (idpId) => {\n    window.location.href = API_URL + `/auth/login/idp/${idpId}`;\n};\n\nexport const GetUserDetails = () =>{\n    return GetService(API_URL + `/auth/user_info`);\n}\n\nexport const GetIdpList = () => {\n    return GetService(API_URL + \"/auth/idp/list\")\n}\n\n\nexport const AuthLogoutService = () => {\n    return PostService(API_URL + `/auth/logout`);  \n   \n};\n\n\n"
  },
  {
    "path": "ui/src/services/BotConfifuration.js",
    "content": "import { API_URL } from \"src/config/const\"\nimport DeleteService from \"src/utils/http/DeleteService\"\nimport GetService from \"src/utils/http/GetService\"\nimport PostService from \"src/utils/http/PostService\"\n\nexport const getBotConfiguration = ()=>{\n    return  GetService(API_URL + \"/connector/configuration/list\")\n}\n\nexport const getBotConfigurationById = (configId)=>{\n    return GetService(API_URL + `/connector/configuration/${configId}`)\n}\n\nexport const deleteBotConfiguration = (configId)=>{\n    return DeleteService(API_URL + `/connector/configuration/${configId}`)\n}\n\n\nexport const getLLMProviders = ()=>{\n    return GetService(API_URL + \"/provider/llmproviders\")\n}\n\n\nexport const saveBotConfiguration = (configID, saveData = {})=>{\n    let apiURL = \"/connector/configuration/create\"\n    if(configID){\n       apiURL = `/connector/configuration/update/${configID}`\n    }\n   return PostService(`${API_URL}${apiURL}`, {\n       short_description: saveData.botShortDescription,\n       long_description: saveData.botLongDescription,\n       name: saveData.botName,\n       connectors: saveData.connectors,\n       status: 1,\n       capabilities: []\n   })\n}\n\n\nexport const testInference = (configID, data)=>{\n    return PostService(`${API_URL}/provider/test-inference-credentials`, {\n        \"name\": data.inferenceName,\n        \"apikey\": data.inferenceAPIKey,\n        \"llm_provider\": data.inferenceLLMProvider,\n        \"model\":data.inferenceModelName ,\n        \"config_id\": configID,\n        \"endpoint\": data.inferenceEndpoint\n    })\n}\n\nexport const saveBotInferene = (configID, inferenceID, saveData = {})=>{\n    let apiURL = \"/inference/create\"\n\n    if(inferenceID){\n        apiURL = `/inference/update/${inferenceID}`\n    }\n\n    return PostService(`${API_URL}${apiURL}`, {\n        \"name\": saveData.inferenceName,\n        \"apikey\": saveData.inferenceAPIKey,\n        \"llm_provider\": saveData.inferenceLLMProvider,\n        \"model\":saveData.inferenceModelName ,\n        \"config_id\": configID,\n        \"endpoint\": saveData.inferenceEndpoint\n    })\n}\n\nexport const restartBot = (configID)=>{\n   return PostService(API_URL + `/connector/createyaml/${configID}`,{},{loaderText: \"Restarting Chatbot\"})\n}\n\n\nexport const getVectorDBList = () => {\n    return GetService(API_URL + \"/vectordb/list/all\")\n}\n\nexport const getEmbeddings = () => {\n    return GetService(API_URL + \"/vectordb/embedding/all\")\n}\n\nexport const testVectorDB = (data) => {\n    return PostService(`${API_URL}/vectordb/test_credentials`, data)\n}\n\nexport const saveVectorDB = (vectordbID, data) => { \n    let apiURL = \"/vectordb/create\"\n    if(vectordbID){\n        apiURL = `/vectordb/update/${vectordbID}`\n    }\n    return PostService(`${API_URL}${apiURL}`, data)\n}\n\n\n"
  },
  {
    "path": "ui/src/services/Capability.js",
    "content": "import { API_URL } from \"src/config/const\"\nimport DeleteService from \"src/utils/http/DeleteService\"\nimport PostService from \"src/utils/http/PostService\"\n\nexport const saveBotCapability = async (configurationId, capabilityName, capabilityDescription, params = {}) => {\n    \n    let saveData = {\n        config_id: configurationId,\n        name: capabilityName,\n        description: capabilityDescription,\n        requirements : params,\n    }\n\n    return  PostService(`${API_URL}/capability/create`, saveData, {loaderText : \"Saving Capability\"})\n}\n\nexport const updateBotCapability = async (capabilityId, configurationId, capabilityName, capabilityDescription, params = {}) => {\n    let updateData = {\n        config_id: configurationId,\n        name: capabilityName,\n        description: capabilityDescription,\n        requirements : params,\n    }\n\n    return PostService(`${API_URL}/capability/update/${capabilityId}`, updateData, {loaderText : \"Updating Capability\"})\n}\n\nexport const deleteBotCapability = async (capabilityId) => {\n    return PostService(`${API_URL}/capability/delete/${capabilityId}`,{},{loaderText: \"Deleting Capability\"})\n}"
  },
  {
    "path": "ui/src/services/Connectors.js",
    "content": "import { API_URL } from \"src/config/const\";\nimport DeleteService from \"src/utils/http/DeleteService\";\nimport GetService from \"src/utils/http/GetService\";\nimport PostService from \"src/utils/http/PostService\";\n\nexport const getConnectors = (provider_category_id = null)=>{\n    if (provider_category_id) {\n        return GetService(API_URL + `/connector/list?provider_category_id=${provider_category_id}`);\n    }\n    return GetService(API_URL + \"/connector/list\")\n}\n\nexport const getConnector = (connectorId)=>{\n    return GetService(API_URL + `/connector/get/${connectorId}`)\n}\n\nexport const saveConnector = (connectorId = undefined, connectorType, connectorName, connectorDescription, connectorConfig = {})=>{\n    let apiURL = \"/connector/create\";\n    if(connectorId){\n        apiURL = `/connector/update/${connectorId}`;\n    }\n    return PostService(API_URL + apiURL,{\n        connector_type: connectorType,\n        connector_name: connectorName,\n        connector_description: connectorDescription,\n        connector_config: connectorConfig\n    })\n}\n\nexport const deleteConnector = (connectorId)=>{\n    return PostService(API_URL + `/connector/delete/${connectorId}`);\n}\n\nexport const updateDocument = (connectorId, document)=>{\n    return PostService(API_URL + `/connector/update/${connectorId}`,{connector_docs: document})\n}\n\nexport const updateSchema = (connectorId, schema)=>{\n    return PostService(API_URL + `/connector/schema/update/${connectorId}`,{schema_config: schema})\n}\n\nexport const healthCheck=(providerId, parameters={})=>{\n    return PostService(API_URL + `/provider/${providerId}/test-credentials`,parameters)\n}"
  },
  {
    "path": "ui/src/services/Plugins.js",
    "content": "import { API_URL } from \"src/config/const\"\nimport GetService from \"src/utils/http/GetService\"\n\nexport const getProviders = ()=>{\n    return GetService(API_URL + \"/provider/list\")\n}\n\nexport const getProviderInfo= (providerId)=>{\n    return GetService(API_URL + `/provider/get/${providerId}`)\n}"
  },
  {
    "path": "ui/src/services/Sample.js",
    "content": "import { API_URL } from \"src/config/const\";\nimport GetService from \"src/utils/http/GetService\";\nimport PostService from \"src/utils/http/PostService\";\n\nexport const getSamples = ()=>{\n    return GetService(API_URL + \"/sql/list\")\n}\n\nexport const saveSamples = (sampleId, data)=>{\n    let apiURL = \"/sql/create\";\n    if(sampleId){\n        apiURL = `/sql/update/${sampleId}`;\n    }\n\n    return PostService(API_URL + apiURL, {\n        connector_id: data.connect_id,\n        description:  data.question,\n        sql_metadata: {\n            query: data.query,\n            metadata:  data.metadata\n        }\n    })\n}\n\n\n"
  },
  {
    "path": "ui/src/store/authStore.js",
    "content": "import { create } from \"zustand\";\nimport { persist } from 'zustand/middleware'\n\nconst useAppSettings = create((set) => ({\n  username: '',\n  isAuthenticated: false,\n  authEnabled: false,\n  envID: '',\n  setUsername: (username) => set({ username }),\n  setIsAuthenticated: (isAuthenticated) => set({ isAuthenticated }),\n  setAuthEnabled: (authEnabled)=>set({authEnabled}),\n  setEnvID: (envID) => set({ envID })\n}));\n\n\nexport const useTokenStore = create(\n  persist(\n    (set) => ({\n      token: '',\n      setToken: (token) => set({ token }),\n    }),\n    { name: 'auth_token' },\n  )\n);\n\nexport const storeToken = (token) => {\n  const setToken = useTokenStore.getState().setToken;\n  setToken(token); \n};\n\nexport default useAppSettings;\n"
  },
  {
    "path": "ui/src/test/setup.js",
    "content": "import '@testing-library/jest-dom'\n\n"
  },
  {
    "path": "ui/src/utils/ConfirmDialog.jsx",
    "content": "import { confirmAlert } from \"react-confirm-alert\";\nimport 'react-confirm-alert/src/react-confirm-alert.css';\n\nconst defaultValue = {\n    icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"31\" height=\"30\" viewBox=\"0 0 31 30\" fill=\"none\">\n        <path d=\"M15.5 20V15M15.5 10H15.5125M28 15C28 21.9036 22.4036 27.5 15.5 27.5C8.59644 27.5 3 21.9036 3 15C3 8.09644 8.59644 2.5 15.5 2.5C22.4036 2.5 28 8.09644 28 15Z\" stroke=\"#FF7F6D\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n    </svg>,\n    cancelButtonText: \"Cancel\",\n    confirmButtonText: \"Delete\",\n    deleteButtonIconsvg: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\">\n        <path d=\"M10.6667 4.00016V3.46683C10.6667 2.72009 10.6667 2.34672 10.5213 2.06151C10.3935 1.81063 10.1895 1.60665 9.93865 1.47882C9.65344 1.3335 9.28007 1.3335 8.53333 1.3335H7.46667C6.71993 1.3335 6.34656 1.3335 6.06135 1.47882C5.81046 1.60665 5.60649 1.81063 5.47866 2.06151C5.33333 2.34672 5.33333 2.72009 5.33333 3.46683V4.00016M6.66667 7.66683V11.0002M9.33333 7.66683V11.0002M2 4.00016H14M12.6667 4.00016V11.4668C12.6667 12.5869 12.6667 13.147 12.4487 13.5748C12.2569 13.9511 11.951 14.2571 11.5746 14.4488C11.1468 14.6668 10.5868 14.6668 9.46667 14.6668H6.53333C5.41323 14.6668 4.85318 14.6668 4.42535 14.4488C4.04903 14.2571 3.74307 13.9511 3.55132 13.5748C3.33333 13.147 3.33333 12.5869 3.33333 11.4668V4.00016\" stroke=\"#FF7F6D\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n    </svg>,\n    cancelButtonIconsvg: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\">\n        <circle cx=\"8\" cy=\"8\" r=\"7.5\" stroke=\"#3893FF\" strokeWidth=\"1\"/>\n        <path d=\"M5 5L11 11M11 5L5 11\" stroke=\"#3893FF\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n    </svg>,\n    onCancel: () => { },\n    onConfirm: () => { }\n};\n\nconst confirmDialogStyle = {\n    dialogBody: {\n        borderRadius: \"8px\",\n        boxShadow: \"0px 4px 20px 0px rgba(0, 0, 0, 0.12)\",\n        padding: \"28px 40px\",\n        width: \"329px\"\n    },\n    iconContainer: {\n        textAlign: \"center\"\n    },\n    icon: {\n        margin: \"auto\",\n        display: \"block\",\n        marginBottom: \"23px\",\n    },\n    dialogText: {\n        textAlign: \"center\"\n    },\n    dialogMainText: {\n        padding: \"0px\",\n        margin: \"0px\",\n        color: '#32324D',\n        textAlign: \"center\",\n        fontFamily: \"Inter\",\n        fontSize: \"18px\",\n        fontStyle: \"normal\",\n        fontWeight: \"600\",\n        lineHeight: \"22px\"\n    },\n    dialogSubText: {\n        color: \"#32324D\",\n        textAlign: \"center\",\n        fontFamily: \"Inter\",\n        fontSize: \"14px\",\n        fontStyle: \"normal\",\n        fontWeight: \"400\",\n        lineHeight: \"20px\",\n        marginBottom: \"30px\"\n    },\n    actionContainer: {\n        textAlign: \"center\"\n    },\n    cancelButton: {\n        padding: \"3px 13px\",\n        borderRadius: \"4px\",\n        background: \"#ECF5FF\",\n        border: \"none\",\n        focus: \"none\",\n        color: \"#3893FF\",\n        fontFamily: \"Inter\",\n        fontSize: \"16px\",\n        fontStyle: \"normal\",\n        fontWeight: \"500\",\n        lineHeight: \"150%\",\n        marginLeft: \"10px\"\n    },\n    deleteButton: {\n        padding: \"3px 13px\",\n        borderRadius: \"4px\",\n        background: \"#FFF2F0\",\n        border: \"none\",\n        focus: \"none\",\n        color: \"#FF7F6D\",\n        fontFamily: \"Inter\",\n        fontSize: \"16px\",\n        fontStyle: \"normal\",\n        fontWeight: \"500\",\n        lineHeight: \"150%\",\n        marginRight: \"10px\"\n    },\n    buttonContentAlign: {\n        display: \"flex\",\n        flexDirection: \"row\"\n    },\n    ButtonIcon: {\n        marginLeft: \"5px\"\n    }\n};\n\nconst confirmDialog = (\n    title,\n    message,\n    deleteButtonIconsvg = defaultValue.deleteButtonIconsvg,\n    cancelButtonIconsvg = defaultValue.cancelButtonIconsvg,\n    confirmButtonText = defaultValue.confirmButtonText,\n    onConfirm = defaultValue.onConfirm,\n    config = {}\n) => {\n    const allConfig = { ...defaultValue, ...config };\n\n    confirmAlert({\n        closeOnEscape: true,\n        customUI: ({ onClose }) => {\n            return (\n                <div>\n                    <div style={confirmDialogStyle.dialogBody}>\n                        <div style={confirmDialogStyle.iconContainer}>\n                            {allConfig.icon || defaultValue.icon}\n                        </div>\n                        <div style={confirmDialogStyle.dialogText}>\n                            <h6 style={confirmDialogStyle.dialogMainText}>{title}</h6>\n                            <p style={confirmDialogStyle.dialogSubText}>{message}</p>\n                        </div>\n                        <div style={confirmDialogStyle.actionContainer}>\n                            <button\n                                style={confirmDialogStyle.deleteButton}\n                                onClick={() => {\n                                    onConfirm();\n                                    onClose();\n                                }}\n                            >\n                                <div style={confirmDialogStyle.buttonContentAlign}>\n                                    <div>\n                                        {confirmButtonText}\n                                    </div>\n                                    {deleteButtonIconsvg && (\n                                        <div style={confirmDialogStyle.ButtonIcon}>\n                                            {deleteButtonIconsvg}\n                                        </div>\n                                    )}\n                                </div>\n                            </button>\n                            <button\n                                style={confirmDialogStyle.cancelButton}\n                                onClick={() => {\n                                    allConfig.onCancel();\n                                    onClose();\n                                }}\n                            >\n                                <div style={confirmDialogStyle.buttonContentAlign}>\n                                    <div>\n                                        {allConfig.cancelButtonText}\n                                    </div>\n                                    {cancelButtonIconsvg && (\n                                        <div style={confirmDialogStyle.ButtonIcon}>\n                                            {cancelButtonIconsvg}\n                                        </div>\n                                    )}\n                                </div>\n                            </button>\n                        </div>\n                    </div>\n                </div>\n            );\n        }\n    });\n};\n\nexport default confirmDialog;"
  },
  {
    "path": "ui/src/utils/form/GenerateConfigs.jsx",
    "content": "import React from 'react'\nimport FileUpload from 'src/components/FileUpload/FileUpload';\nimport Input from 'src/components/Input/Input'\nimport Textarea from 'src/components/Textarea/Textarea';\nimport style from \"src/pages/Configuration/ProviderForm/ProviderForm.module.css\"\n\n\nconst GenerateConfigs = ({ register = () => { }, errors = \" \", configs = \" \", fileConfig = {}, restForm = () => { } }) => {\n    \n\n    const parseValue = (value = '')=>{\n        try{\n            return JSON.stringify(value, undefined, 3)\n        }\n        catch(error){\n            console.log({parseValue: error})\n            return value\n        }\n    }\n\n\n    return (\n        <>\n            {configs?.map((item, index) => {\n\n                switch (item.config_type) {\n                    case 1: return <Input key={index} type=\"text\" label={item.name} placeholder={item.description} defaultValue={ parseValue(item.value)} required={item.required} hasError={errors[item.slug]?.message ? true : false} errorMessage={errors[item.slug]?.message} {...register(item.slug, { required: item.required ? \"This is required\" : false })} onChange={restForm} />\n                    case 2: return <Input key={index} type=\"password\" label={item.name} placeholder={item.description} defaultValue={ parseValue(item.value)} required={item.required} hasError={errors[item.slug]?.message ? true : false} errorMessage={errors[item.slug]?.message}  {...register(item.slug, { required: item.required ? \"This is required\" : false })} onChange={restForm} />\n                    case 3: return <Input key={index} type=\"number\" label={item.name} placeholder={item.description} defaultValue={ parseValue(item.value)} required={item.required} hasError={errors[item.slug]?.message ? true : false} errorMessage={errors[item.slug]?.message} {...register(item.slug, { required: item.required ? \"This is required\" : false })} onChange={restForm} />\n                    case 4: return <Input key={index} type=\"url\" label={<> {item.name} <span style={{ color: \"#C8C8C8\" }}>(Include http or https in the url)</span> </>} defaultValue={ parseValue(item.value)} required={item.required} placeholder={item.placeholder || \"https://www.raggenie.com\"} hasError={errors[item.slug]?.message ? true : false} errorMessage={errors[item.slug]?.message} {...register(item.slug, { required: item.required ? \"This is required\" : false })} onChange={restForm} />\n                    case 5: return <Input key={index} type=\"email\" label={`${item.name}  `} defaultValue={ parseValue(item.value)} required={item.required} placeholder={item.description} hasError={errors[item.slug]?.message ? true : false} errorMessage={errors[item.slug]?.message} {...register(item.slug, { required: item.required ? \"This is required\" : false })} onChange={restForm} />\n                    case 6: return (\n                        <div className={style.SelectDropDown}>\n                            <label className={style.SelectDropDownLabel}>{item.name} {item.required && <span className=\"span-important\"></span>} </label>\n                            <select name=\"selectOption\" key={index} className={`${errors[item.slug]?.message ? style.SelectHasError : \"\"}`}  {...register(item.slug, { required: \"This is required\" })} onChange={(e) => restForm(e)}>\n                                {item.value?.map((val, valIndex) => {\n                                    return (\n                                        <option key={valIndex} value={val.value}>\n                                            {val.label}\n                                        </option>\n                                    );\n                                })}\n                            </select>\n\n                            {errors[item.slug]?.message != \"\" && <label className={style.SelectErrorMessage}>{errors[item.slug]?.message}</label>}\n                        </div>\n                    )\n                    case 7: return <Textarea key={index} rows=\"5\" label={item.name} defaultValue={ parseValue(item.value)} required={item.required} placeholder={item.description} hasError={errors[item.slug]?.message ? true : false} errorMessage={errors[item.slug]?.message} {...register(item.slug, { required: item.required ? \"This is required\" : false })} onChange={restForm} />\n                    case 8: return (\n                        <FileUpload\n                            {...fileConfig}\n                        />\n                    )\n                    default: return <Input key={index} type=\"text\" label={item.name} defaultValue={ parseValue(item.value)} required={item.required} placeholder={item.description} hasError={errors[item.slug]?.message ? true : false} errorMessage={errors[item.slug]?.message} {...register(item.slug, { required: item.required ? \"This is required\" : false })} onChange={restForm} />\n                }\n\n            })}\n        </>\n    )\n}\n\nexport default GenerateConfigs"
  },
  {
    "path": "ui/src/utils/http/DeleteService.js",
    "content": "import Request from \"./Request\"\n\nconst DeleteService = (url, data = {} , config = {}, axiosConfig = {})=>{\n    return Request(\"delete\", url, data, {}, config, axiosConfig)\n}\n\nexport default DeleteService"
  },
  {
    "path": "ui/src/utils/http/GetService.js",
    "content": "import Request from \"./Request\"\n\n\nconst GetService = (url, params = {}, config = {}, axiosConfig = {})=>{\n     return Request(\"get\", url, {}, params, config, axiosConfig)\n}\n\nexport default GetService"
  },
  {
    "path": "ui/src/utils/http/PostService.js",
    "content": "import Request from \"./Request\"\n\nconst PostService = (url, data = {} , config = {}, axiosConfig = {})=>{\n    return Request(\"post\", url, data, {}, config, axiosConfig)\n}\n\nexport default PostService"
  },
  {
    "path": "ui/src/utils/http/Request.js",
    "content": "import axios from \"axios\";\nimport { useTokenStore } from \"src/store/authStore\";\n\nconst defaultConfig = {\n    showLoader: true,\n    fullLoader: false,\n    loaderText: \"Getting Data\",\n    allowAuthHeaders: true,\n}\n\nconst defaultAxiosConfig = { }\n\n\n\n\n\nconst Request = (method, url, data = {}, params = {}, config = {}, axiosConfig = {} )=>{\n    \n    let allConfig = {...defaultConfig, ...config}\n    let allAxiosConfig = {...defaultAxiosConfig, ...axiosConfig}\n\n\n    let loaderContainer = document.querySelector(\".dashboard-loader-container\")\n    let loaderTextPara = document.querySelector(\".dashboard-loader-message\")\n\n    const token = useTokenStore.getState().token;\n\n    if (loaderContainer && allConfig.showLoader) {\n\n        if(allConfig.showLoader){\n            loaderContainer.style.display = \"block\"\n        }\n    \n        if(allConfig.fullLoader){\n            loaderContainer.style.width = \"100%\"\n            loaderContainer.style.h = \"100%\"\n        }\n    \n        if(allConfig.loaderText){\n            loaderTextPara.innerHTML = allConfig.loaderText\n        }\n    }\n\n    \n\n    let requestConfig = {\n        method: method,\n        url: url,\n        data: data,\n        params: params,\n        headers: {\n            ...(allConfig.allowAuthHeaders && { Authorization: `Bearer ${token}` }),\n            ...allAxiosConfig.headers,\n        }\n    };\n    \n\n    return new Promise((resolve, reject)=> {\n        axios.request(requestConfig).then(response => {\n            if (loaderContainer) {\n                loaderContainer.style.display = \"none\";\n            }\n            \n            if (response.data?.status == false) {\n                return  reject(response);\n            }\n            return  resolve(response)\n    \n        }).catch(error => {\n            if (loaderContainer) {\n                loaderContainer.style.display = \"none\";\n            }\n            if (error.response?.status == 401) {\n                window.location.href = '/ui/login';\n                return null\n            }\n            return reject(error)\n        });\n    })\n       \n}\n\nexport default Request"
  },
  {
    "path": "ui/src/utils/http/UploadFile.js",
    "content": "import axios from \"axios\";\nimport { useTokenStore } from \"src/store/authStore\";\n\nconst UploadFile = (url, formData, onProgress) => {\n  return new Promise((resolve, reject) => {\n    const startTime = new Date().getTime(); // Record the start time\n    const token = useTokenStore.getState().token;\n    axios.post(url, formData, {\n      headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${token}` },\n      onUploadProgress: (event) => {\n        const { loaded, total } = event;\n        const percentage = Math.floor((loaded / total) * 100);\n\n        // Time calculations\n        const currentTime = new Date().getTime();\n        const elapsedTime = (currentTime - startTime) / 1000; \n        const uploadSpeed = loaded / elapsedTime; \n        const remainingBytes = total - loaded;\n        const remainingTime = remainingBytes / uploadSpeed; \n\n        const remainingTimeFormatted = formatRemainingTime(remainingTime);\n\n        onProgress(percentage, remainingTimeFormatted); \n      },\n    })\n    .then(response => resolve(response))\n    .catch(error => reject(new Error(`File upload failed: ${error.response?.data?.message || error.message}`)));\n  });\n};\n\n\n\nconst formatRemainingTime = (timeInSeconds) => {\n  const minutes = Math.floor(timeInSeconds / 60);\n  const seconds = Math.floor(timeInSeconds % 60);\n  return `${minutes > 0 ? `${minutes}m ` : \"\"}${seconds}s`;\n};\n\nexport default UploadFile;\n"
  },
  {
    "path": "ui/src/utils/utils.js",
    "content": "\n\nexport const showDashboardLoader = ()=>{\n    let loaderDiv = document.querySelector(\".dashboard-loader-container\");\n    loaderDiv.style.display = \"block\"\n}\n\nexport const hideDashboardLoader = ()=>{\n    let loaderDiv = document.querySelector(\".dashboard-loader-container\");\n    loaderDiv.style.display = \"none\"\n}\n\nexport const isEmptyJSON = (json)=>{\n\n    if(!json){\n        return true\n    }\n\n    if(typeof(json) == \"string\" && json == \"\"){\n        return true\n    }\n    if(typeof(json) == \"object\" && Object.keys(json).length == 0){\n        return true\n    }\n\n    return false\n}\n\n"
  },
  {
    "path": "ui/vite.config.js",
    "content": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react-swc'\n\nexport default defineConfig({\n  base: \"/ui/\",\n  plugins: [react()],\n  resolve: {\n        alias: {\n          src: \"/src\",\n        },\n      },\n  server: {\n      port: 5000,\n      strictPort: true,\n  },\n  test: {\n    globals: true,\n    environment: 'jsdom',\n    setupFiles: './src/test/setup.js',\n  },\n});\n"
  },
  {
    "path": "ui/vite.library.config.js",
    "content": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react-swc'\nimport path from 'path';\nimport ViteCssInjectedByJs from 'vite-plugin-css-injected-by-js';\n\nexport default defineConfig({\n  base: \"/\",\n  plugins: [react(),ViteCssInjectedByJs()],\n  define: {\n    'process.env': {}, // Provide a mock for process.env in browser\n  },\n  resolve: {\n    alias: {\n      src: \"/src\",\n    },\n  },\n  server: {\n    port: 5000,\n    strictPort: true,\n  },\n  test: {\n    globals: true,\n    environment: 'jsdom',\n    setupFiles: './src/test/setup.js',\n  },\n  build: {\n      outDir: 'dist-library',  \n      lib: {\n        entry: path.resolve(__dirname, './src/embedbot/index.jsx'), // Entry point for the library\n        name: 'ChatBot', // Global variable name for UMD\n        fileName: (format) => `chatbot.js`, // Output filename\n        formats: ['umd'], // Output format\n      },\n      rollupOptions: {\n        output: {\n          assetFileNames: ({ name }) => {\n            if (/\\.(png|jpg|jpeg|gif|svg)$/.test(name ?? '')) {\n              return 'assets/images/[name][extname]'; // Handle images\n            }\n            return 'assets/[name][extname]';\n          },\n        },\n      },\n    }\n});\n"
  },
  {
    "path": "zitadel-docker-compose.yaml",
    "content": "services:\n  zitadel:\n    restart: 'always'\n    networks:\n      - 'zitadel'\n    image: 'ghcr.io/zitadel/zitadel:latest'\n    command: 'start-from-init --masterkey \"MasterkeyNeedsToHave32Characters\" --tlsMode disabled'\n    environment:\n      ZITADEL_DATABASE_POSTGRES_HOST: db\n      ZITADEL_DATABASE_POSTGRES_PORT: 5432\n      ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel\n      ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel\n      ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: zitadel\n      ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable\n      ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: postgres\n      ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: postgres\n      ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable\n      ZITADEL_EXTERNALSECURE: false\n    depends_on:\n      db:\n        condition: 'service_healthy'\n    ports:\n      - '8080:8080'\n\n  db:\n    restart: 'always'\n    image: postgres:16-alpine\n    environment:\n      PGUSER: postgres\n      POSTGRES_PASSWORD: postgres\n    networks:\n      - 'zitadel'\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready\", \"-d\", \"zitadel\", \"-U\", \"postgres\"]\n      interval: '10s'\n      timeout: '30s'\n      retries: 5\n      start_period: '20s'\n\nnetworks:\n  zitadel:"
  }
]