├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── ci.yml │ └── codeql-analysis.yml ├── .gitignore ├── .gitmodules ├── .pylintrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── ROADMAP.md ├── cobalt-strike-logo.png ├── mpp ├── __init__.py ├── blocks │ ├── __init__.py │ └── block.py ├── constants.py ├── options │ ├── __init__.py │ └── option.py ├── profile.py └── statements │ ├── __init__.py │ └── statement.py ├── poetry.lock ├── pyproject.toml ├── renovate.json └── tests ├── data ├── amazon.profile ├── bing_maps.profile └── mayoclinic.profile └── mpp ├── options └── test_option.py ├── statements └── test_statement.py └── test_profile.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [brett-fitz] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] " 5 | labels: bug 6 | assignees: brett-fitz 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Environment (please complete the following information):** 23 | - OS: [e.g. Ubuntu 20] 24 | - Version [e.g. 0.3] 25 | - Python Version [e.g. 3.10] 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: 'CI: pyMalleableProfileParser' 2 | 3 | on: 4 | # manual trigger 5 | workflow_dispatch: 6 | push: 7 | branches: 8 | - main 9 | paths: 10 | - 'mpp/**' 11 | - 'tests/**' 12 | - 'poetry.lock' 13 | - 'pyproject.toml' 14 | pull_request: 15 | branches: 16 | - main 17 | paths: 18 | - 'mpp/**' 19 | - 'tests/**' 20 | - 'poetry.lock' 21 | - 'pyproject.toml' 22 | 23 | jobs: 24 | # Build 25 | python-test: 26 | name: pytest 27 | runs-on: ${{ matrix.os }} 28 | strategy: 29 | matrix: 30 | os: [ ubuntu-latest ] 31 | python: ["3.8", "3.9", "3.10", "3.11"] 32 | steps: 33 | - name: Clone repository 34 | uses: actions/checkout@v4 35 | 36 | - name: Install Poetry 37 | run: pipx install poetry 38 | 39 | - name: Set up Python 40 | uses: actions/setup-python@v5 41 | with: 42 | python-version: ${{ matrix.python }} 43 | architecture: x64 44 | cache: poetry 45 | 46 | - name: Install pyMalleableProfileParser 47 | run: poetry install --no-interaction --no-ansi 48 | 49 | - name: Run Tests 50 | run: poetry run pytest --cov mpp 51 | 52 | - name: Upload coverage reports to Codecov 53 | uses: codecov/codecov-action@v5 54 | env: 55 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 56 | if: ${{ matrix.os == 'ubuntu-latest' && matrix.python == 3.9 }} 57 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '22 11 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'python' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v4 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v3 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v3 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v3 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | .idea/ 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "data/Malleable-C2-Profiles"] 2 | path = data/Malleable-C2-Profiles 3 | url = https://github.com/BC-SECURITY/Malleable-C2-Profiles.git 4 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MESSAGES CONTROL] 2 | # Format style used to check logging format string. `old` means using % 3 | # formatting, while `new` is for `{}` formatting. 4 | disable=logging-fstring-interpolation,broad-except,too-many-arguments 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this this project will be documented in this file. 3 | 4 | The format is based on [changelog.md](https://changelog.md/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.4] 8 | 9 | ## [0.3.3] - 2022-11-18 10 | * Fixed a typo 11 | 12 | ## [0.3.2] - 2021-10-22 13 | * Multiple bug fixes when parsing beacon configs 14 | 15 | ## [0.3.1] - 2021-10-21 16 | * Bug fix when validating Malleable Profiles for version 4.3+ 17 | 18 | ## [0.3] - 2021-10-21 19 | * Complete overhaul of data types 20 | * Validate Malleable Profiles 21 | * Native statement support 22 | * Tests 23 | 24 | ## [0.2] - 2021-09-07 25 | * Publish on PyPi 26 | * Update docs 27 | 28 | ## [0.1] - 2021-09-07 29 | * Initial development release 30 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this repository 2 | 3 | ## Getting started 4 | 5 | Before you begin: 6 | - Check out the [existing issues](https://github.com/brett-fitz/pyMalleableProfileParser/issues) 7 | 8 | ### Don't see your issue? Open one 9 | 10 | If you spot something new, open an issue. We'll use the issue to have a conversation about the problem you want to fix, 11 | and I'll try to get to it as soon as I can. 12 | 13 | ### Ready to make a change? Follow these steps 14 | * Fork the repo 15 | * Make your update 16 | * Open a pull request 17 | * Submit your PR & get it reviewed! 18 | 19 | I'll try to review PRs as soon as they are made available but please be patient. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 brett-fitz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyMalleableProfileParser 2 | Parses Cobalt Strike malleable C2 profiles. 3 | 4 | [![Latest version released on PyPi](https://img.shields.io/pypi/v/pymalleableprofileparser?style=flat-square)](https://pypi.org/project/pyMalleableProfileParser/) 5 | [![License](https://img.shields.io/github/license/brett-fitz/pyMalleableProfileParser?style=flat-square)](https://github.com/brett-fitz/pyMalleableProfileParser/blob/main/LICENSE) 6 | [![Issues](https://img.shields.io/github/issues/brett-fitz/pyMalleableProfileParser?style=flat-square)](https://github.com/brett-fitz/pyMalleableProfileParser/issues) 7 | 8 | ![Cobalt Strike Logo](https://raw.githubusercontent.com/brett-fitz/pyMalleableProfileParser/main/cobalt-strike-logo.png) 9 | 10 | 11 | ## Installation :gear: 12 | ```shell 13 | pip3 install pyMalleableProfileParser 14 | ``` 15 | 16 | ### Upgrading to the latest version 17 | ```shell 18 | pip3 install --upgrade pyMalleableProfileParser 19 | ``` 20 | 21 | 22 | ## Usage 23 | 24 | ### MalleableProfile class 25 | ```python 26 | from mpp import MalleableProfile 27 | mp = MalleableProfile(profile='/path/to/profile') 28 | mp.profile 29 | ``` 30 | 31 | ### Get attributes easily 32 | 33 | ### Options 34 | Here is an example of getting the global option `jitter`: 35 | ```python 36 | >> mp.jitter 37 | Option(option="jitter", value="0") 38 | >> mp.jitter.option 39 | 'jitter' 40 | >> mp.jitter.value 41 | '0' 42 | ``` 43 | You can also access options in any block: 44 | ```python 45 | >> mp.http_get.uri 46 | Option(option="uri", value="/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books") 47 | ``` 48 | 49 | ### Statements 50 | You can get statements in any block or sub-block: 51 | ```python 52 | >> mp.http_get.client.Host 53 | Statement(statement=header, key="Host", value="www.amazon.com") 54 | ``` 55 | ```python 56 | >> mp = MalleableProfile('bing_maps.profile') 57 | >> mp.stage.transform_x86.ReflectiveLoader 58 | Statement(statement=strrep, string="ReflectiveLoader", replace="") 59 | ``` 60 | 61 | ### Blocks 62 | Like statements, you can access any block or sub-block: 63 | ```python 64 | >> mp.http_get 65 | Block(name=http-get, data=[Option(option="uri", value="/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books"), 66 | Block(name=client, data=[Statement(statement=header, key="Accept", value="*/*"), Statement(statement=header, key="Host", 67 | value="www.amazon.com"), Block(name=metadata, data=[Statement(statement=base64, value=""), Statement(statement=prepend, 68 | value="session-token="), Statement(statement=prepend, value="skin=noskin;"), Statement(statement=append, 69 | value="csm-hit=s-24KU11BB82RZSYGJ3BDK|1419899012996"), Statement(statement=header, key="Cookie", value="")])]), 70 | Block(name=server, data=[Statement(statement=header, key="Server", value="Server"), Statement(statement=header, 71 | key="x-amz-id-1", value="THKUYEZKCKPGY5T42PZT"), Statement(statement=header, key="x-amz-id-2", 72 | value="a21yZ2xrNDNtdGRsa212bGV3YW85amZuZW9ydG5rZmRuZ2tmZGl4aHRvNDVpbgo="), Statement(statement=header, 73 | key="X-Frame-Options", value="SAMEORIGIN"), Statement(statement=header, key="Content-Encoding", value="gzip"), Block( 74 | name=output, data=[Statement(statement=print, value="")])])]) 75 | >> mp.http_get.server.output 76 | Block(name=output, data=[Statement(statement=print, value="")]) 77 | ``` 78 | 79 | 80 | ## Validate a Profile 81 | By default, `validate()` will validate Malleable Profiles for 4.0+. You can also specify a specific version. Note: a 82 | warning will be displayed when setting dns options globally but will fail the validation if you specify version `4.3`. 83 | 84 | **Example** 85 | ```python 86 | >>> from mpp.profile import MalleableProfile 87 | >>> mp = MalleableProfile('bing_maps.profile') 88 | >>> mp.validate() 89 | starting with v4.3, dns options have been moved into 'dns-beacon' block: dns_idle 90 | starting with v4.3, dns options have been moved into 'dns-beacon' block: maxdns 91 | starting with v4.3, dns options have been moved into 'dns-beacon' block: dns_sleep 92 | starting with v4.3, dns options have been moved into 'dns-beacon' block: dns_stager_prepend 93 | starting with v4.3, dns options have been moved into 'dns-beacon' block: dns_stager_subhost 94 | starting with v4.3, dns options have been moved into 'dns-beacon' block: dns_max_txt 95 | starting with v4.3, dns options have been moved into 'dns-beacon' block: dns_ttl 96 | True 97 | >>> mp.validate(version=4.3) 98 | [(Option(option="dns_idle", value="8.8.8.8"), 'INVALID_OPTION'), (Option(option="maxdns", value="245"), 'INVALID_OPTION'), (Option(option="dns_sleep", value="0"), 'INVALID_OPTION'), (Option(option="dns_stager_prepend", value=""), 'INVALID_OPTION'), (Option(option="dns_stager_subhost", value=""), 'INVALID_OPTION'), (Option(option="dns_max_txt", value="252"), 'INVALID_OPTION'), (Option(option="dns_ttl", value="1"), 'INVALID_OPTION')] 99 | >>> 100 | 101 | ``` 102 | 103 | 104 | ## Profile Structure (Dict) 105 | 106 | **Example: amazon.profile** 107 | ```python 108 | {'sleeptime': Option(option="sleeptime", value="5000"), 109 | 'jitter': Option(option="jitter", value="0"), 110 | 'maxdns': Option(option="maxdns", value="255"), 111 | 'useragent': Option(option="useragent", value="Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"), 112 | 'http-get': Block(name=http-get, data=[Option(option="uri", value="/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books"), 113 | Block(name=client, data=[Statement(statement=header, key="Accept", value="*/*"), 114 | Statement(statement=header, key="Host", value="www.amazon.com"), 115 | Block(name=metadata, data=[Statement(statement=base64, value=""), 116 | Statement(statement=prepend, value="session-token="), 117 | Statement(statement=prepend, value="skin=noskin;"), 118 | Statement(statement=append, value="csm-hit=s-24KU11BB82RZSYGJ3BDK|1419899012996"), 119 | Statement(statement=header, key="Cookie", value="")])]), 120 | Block(name=server, data=[Statement(statement=header, key="Server", value="Server"), 121 | Statement(statement=header, key="x-amz-id-1", value="THKUYEZKCKPGY5T42PZT"), 122 | Statement(statement=header, key="x-amz-id-2", value="a21yZ2xrNDNtdGRsa212bGV3YW85amZuZW9ydG5rZmRuZ2tmZGl4aHRvNDVpbgo="), 123 | Statement(statement=header, key="X-Frame-Options", value="SAMEORIGIN"), 124 | Statement(statement=header, key="Content-Encoding", value="gzip"), 125 | Block(name=output, data=[Statement(statement=print, value="")])])]), 126 | 'http-post': Block(name=http-post, data=[Option(option="uri", value="/N4215/adj/amzn.us.sr.aps"), 127 | Block(name=client, data=[Statement(statement=header, key="Accept", value="*/*"), 128 | Statement(statement=header, key="Content-Type", value="text/xml"), 129 | Statement(statement=header, key="X-Requested-With", value="XMLHttpRequest"), 130 | Statement(statement=header, key="Host", value="www.amazon.com"), 131 | Statement(statement=parameter, key="sz", value="160x600"), 132 | Statement(statement=parameter, key="oe", value="oe=ISO-8859-1;"), 133 | Block(name=id, data=[Statement(statement=parameter, key="sn", value="")]), 134 | Statement(statement=parameter, key="s", value="3717"), 135 | Statement(statement=parameter, key="dc_ref", value="http%3A%2F%2Fwww.amazon.com"), 136 | Block(name=output, data=[Statement(statement=base64, value=""), 137 | Statement(statement=print, value="")])]), 138 | Block(name=server, data=[Statement(statement=header, key="Server", value="Server"), 139 | Statement(statement=header, key="x-amz-id-1", value="THK9YEZJCKPGY5T42OZT"), 140 | Statement(statement=header, key="x-amz-id-2", value="a21JZ1xrNDNtdGRsa219bGV3YW85amZuZW9zdG5rZmRuZ2tmZGl4aHRvNDVpbgo="), 141 | Statement(statement=header, key="X-Frame-Options", value="SAMEORIGIN"), 142 | Statement(statement=header, key="x-ua-compatible", value="IE=edge"), 143 | Block(name=output, data=[Statement(statement=print, value="")])])])} 144 | ``` 145 | 146 | ## Help :construction_worker: 147 | 148 | #### Join us in discussions 149 | I use GitHub Discussions to talk about all sorts of topics related to this repo. 150 | 151 | #### Open an issue 152 | First, check out the [existing issues](https://github.com/brett-fitz/pyMalleableProfileParser/issues). If you spot 153 | something new, open an issue. We'll use the issue to have a conversation about the problem you want to fix, and I'll 154 | try to get to it as soon as I can. -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | Roadmap for the project. 3 | 4 | *Updated: 2023-07-16* 5 | 6 | ## [0.4] :construction: 7 | * Allow modification to Malleable Profiles 8 | * Write Malleable Profiles 9 | * Poetry 10 | * Code Coverage 11 | * Move from Unittest to Pytest 12 | * Add support for options introduced in 4.6+ 13 | * Add support for profile variants 14 | 15 | 16 | ## [0.3] :rocket: 17 | * Validate Malleable Profiles 18 | * Native statement support 19 | * Tests 20 | 21 | ## [0.2] :rocket: 22 | * Publish on PyPi 23 | * Update docs 24 | 25 | ## [0.1] :rocket: 26 | * Initial release (MVP) 27 | -------------------------------------------------------------------------------- /cobalt-strike-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brett-fitz/pyMalleableProfileParser/bbe5c92fbf2b236df017cb3ef198f30dcb6ee50b/cobalt-strike-logo.png -------------------------------------------------------------------------------- /mpp/__init__.py: -------------------------------------------------------------------------------- 1 | from .profile import * 2 | -------------------------------------------------------------------------------- /mpp/blocks/__init__.py: -------------------------------------------------------------------------------- 1 | from .block import Block 2 | -------------------------------------------------------------------------------- /mpp/blocks/block.py: -------------------------------------------------------------------------------- 1 | """mpp.blocks module: block 2 | """ 3 | import logging 4 | import re 5 | from typing import List, Tuple, Union 6 | 7 | import regex 8 | 9 | from mpp.constants import (DATA_TRANSFORM_BLOCKS, INVALID_BLOCK, 10 | INVALID_OPTION, INVALID_STATEMENT, 11 | INVALID_TERMINATION_STATEMENT, PROFILE, 12 | TERMINATION_STATEMENTS) 13 | from mpp.options import Option 14 | from mpp.statements import HeaderParameter, Statement, StringReplace 15 | 16 | 17 | __all__ = [ 18 | "Block" 19 | ] 20 | 21 | 22 | logger = logging.getLogger(__name__) 23 | 24 | 25 | class Block: 26 | """Block Class 27 | """ 28 | # Regex to parse blocks with support for variants 29 | # https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_profile-variants.htm 30 | BLOCK_REGEX = r'^\s*([\w\-\_]+)\s*(?:"([\w\s]+)"\s*)?(\{(?:[^{}"\']+|\'(?:[^\']+|\\.)*\'|"(?:[^"\\]+|\\.)*"|(?R))*\})' 31 | NON_BLOCK_DATA_REGEX = r'\{(?:[^{}"\']+|\'(?:[^\']+|\\.)*\'|"(?:[^"\\]+|\\.)*"|(?R))*\}' 32 | 33 | def __init__(self, name: str, data: List, variant: str = None): 34 | self.name = name 35 | self.data = data 36 | # TODO Support variants 37 | self.variant = variant 38 | # TODO add properties to easily get options, statements, blocks 39 | 40 | def __getattr__(self, item): 41 | # TODO return all matches for statements 42 | tmp = item.replace('_', '-') 43 | for i in self.data: 44 | if isinstance(i, Block): 45 | if tmp == i.name or item == i.name: 46 | return i 47 | elif isinstance(i, Option): 48 | if tmp == i.option or item == i.option: 49 | return i 50 | elif isinstance(i, HeaderParameter): 51 | if tmp == i.key or item == i.key: 52 | return i 53 | elif isinstance(i, StringReplace): 54 | if tmp == i.string or item == i.string: 55 | return i 56 | elif isinstance(i, Statement): 57 | if i.value == '': 58 | if tmp == i.statement or item == i.statement: 59 | return i 60 | else: 61 | if tmp == i.value or item == i.value: 62 | return i 63 | 64 | def __str__(self, depth: int = 1): 65 | def generate_string(obj, curr_depth): 66 | indentation = '\t' * curr_depth 67 | if isinstance(obj, Block): 68 | name = f'{obj.name} "{obj.variant}"' if obj.variant else obj.name 69 | block_data = [generate_string(item, curr_depth + 1) for item in obj.data] 70 | block_string = f"\n{indentation}".join(block_data) 71 | return f'{name} {{\n{indentation}{block_string}\n{indentation[:-1]}}}' 72 | return str(obj) 73 | return generate_string(self, depth) 74 | 75 | def __repr__(self): 76 | return f'Block(name={self.name}, data={self.data})' 77 | 78 | @property 79 | def options(self) -> List: 80 | """Get all options in the root block 81 | 82 | Returns: 83 | _description_ 84 | """ 85 | return [ 86 | item 87 | for item in self.data 88 | if isinstance(item, Option) 89 | ] 90 | 91 | @property 92 | def statements(self) -> List: 93 | """Get all statements in the root block 94 | 95 | Returns: 96 | _description_ 97 | """ 98 | return [ 99 | item 100 | for item in self.data 101 | if isinstance(item, Statement) 102 | ] 103 | 104 | @classmethod 105 | def from_string(cls, string: str): 106 | """Parse a block and its nested blocks from a string in the following format: 107 | name "" { 108 | data 109 | } 110 | 111 | Args: 112 | string: _description_ 113 | 114 | Returns: 115 | _description_ 116 | """ 117 | data = [] 118 | 119 | # Get block 120 | block = regex.search(Block.BLOCK_REGEX, string, flags=re.MULTILINE | re.DOTALL) 121 | if block: 122 | logger.info(f'found block in string: {string}') 123 | # Get Non block data 124 | non_block_data = "".join( 125 | [ 126 | item 127 | for item in regex.split(Block.NON_BLOCK_DATA_REGEX, block.groups()[2].strip()[1:-1], flags=re.MULTILINE) 128 | if item is not None 129 | ] 130 | ) 131 | logger.info(f'non-block data: {non_block_data}') 132 | # Get Options 133 | data += Option.from_string(string=non_block_data) 134 | 135 | # Get statements 136 | data += Statement.from_string(string=non_block_data) 137 | data += HeaderParameter.from_string(string=non_block_data) 138 | data += StringReplace.from_string(string=non_block_data) 139 | 140 | # Get nested block 141 | for nested_block in regex.finditer( 142 | pattern=Block.BLOCK_REGEX, 143 | string=block.groups()[2], 144 | flags=re.MULTILINE | re.DOTALL 145 | ): 146 | if nested_block: 147 | data.append(cls.from_string(string=nested_block.group())) 148 | else: 149 | logger.warning(f'did not find a valid block in string:{string}') 150 | return None 151 | 152 | return cls( 153 | name=block.groups()[0], 154 | data=data, 155 | variant=block.groups()[1] 156 | ) 157 | 158 | def validate( 159 | self, 160 | name: str = '' 161 | ) -> Union[bool, List[Tuple]]: 162 | """Validate a block and it's sub-blocks 163 | 164 | Args: 165 | name: Name of the block. Defaults to ''. 166 | 167 | Returns: 168 | _description_ 169 | """ 170 | if name != '': 171 | name = name + '.' + self.name 172 | else: 173 | name = self.name 174 | valid_options = PROFILE[name]['options'] 175 | valid_statements = PROFILE[name]['statements'] 176 | valid_blocks = PROFILE[name]['blocks'] 177 | i = 0 178 | invalid_values = [] 179 | while i < len(self.data): 180 | if i == len(self.data) - 1 and self.name in DATA_TRANSFORM_BLOCKS: 181 | if self.data[i].statement not in TERMINATION_STATEMENTS: 182 | invalid_values.append((self.data[i], INVALID_TERMINATION_STATEMENT)) 183 | elif self.name == 'output' and self.data[i].statement != 'print' and 'client' not in name: 184 | invalid_values.append((self.data[i], INVALID_TERMINATION_STATEMENT)) 185 | elif isinstance(self.data[i], Statement) and self.data[i].statement not in valid_statements: 186 | invalid_values.append((self.data[i], INVALID_STATEMENT)) 187 | elif isinstance(self.data[i], Option) and self.data[i].option not in valid_options: 188 | invalid_values.append((self.data[i], INVALID_OPTION)) 189 | elif isinstance(self.data[i], Block) and self.data[i].name not in valid_blocks: 190 | invalid_values.append((self.data[i], INVALID_BLOCK)) 191 | elif isinstance(self.data[i], Block): 192 | tmp = self.data[i].validate(name=name) 193 | if isinstance(tmp, list): 194 | invalid_values += tmp 195 | i += 1 196 | if invalid_values: 197 | return invalid_values 198 | return True 199 | -------------------------------------------------------------------------------- /mpp/constants.py: -------------------------------------------------------------------------------- 1 | """mpp module: Constants 2 | 3 | Package-wide constants are stored here. 4 | """ 5 | from typing import Set, Dict 6 | 7 | # Constants 8 | DELIM: str = ';' 9 | START_BLOCK_DELIM: str = '{' 10 | END_BLOCK_DELIM: str = '}' 11 | 12 | # Errors 13 | INVALID_STATEMENT: str = 'INVALID_STATEMENT' 14 | INVALID_TERMINATION_STATEMENT: str = 'INVALID_TERMINATION_STATEMENT' 15 | INVALID_TRANSFORM_STATEMENT: str = 'INVALID_TRANSFORM_STATEMENT' 16 | INVALID_OPTION: str = 'INVALID_OPTION' 17 | INVALID_BLOCK: str = 'INVALID_BLOCK' 18 | INVALID_VARIANT: str = 'INVALID_VARIANT' 19 | 20 | # Special Strings 21 | SPECIAL_STRINGS: Set[str] = { 22 | '\n', 23 | '\r', 24 | '\t', 25 | r'\u####', 26 | r'\x##', 27 | r'\\' 28 | } 29 | 30 | # All Statements 31 | STATEMENTS: Set[str] = { 32 | 'append', 33 | 'base64', 34 | 'base64url', 35 | 'CreateRemoteThread', 36 | 'CreateThread', 37 | 'data', 38 | 'header', 39 | 'mask', 40 | 'netbios', 41 | 'netbiosu', 42 | 'NtQueueApcThread', 43 | 'NtQueueApcThread-s', 44 | 'parameter', 45 | 'prepend', 46 | 'print', 47 | 'RtlCreateUserThread', 48 | 'SetThreadContext', 49 | 'string', 50 | 'stringw', 51 | 'strrep', 52 | 'uri-append' 53 | } 54 | 55 | # General Statements 56 | # Data Transform 57 | DATA_TRANSFORM_STATEMENTS: Set[str] = { 58 | 'append', 59 | 'base64', 60 | 'base64url', 61 | 'mask', 62 | 'netbios', 63 | 'netbiosu', 64 | 'prepend' 65 | } 66 | 67 | # Termination 68 | TERMINATION_STATEMENTS: Set[str] = { 69 | 'header', 70 | 'parameter', 71 | 'print', 72 | 'uri-append' 73 | } 74 | HTTP_SERVER_TERMINATION_STATEMENTS: Set[str] = { 75 | 'print' 76 | } 77 | 78 | # Global Options 79 | GLOBAL_OPTIONS: Set[str] = { 80 | 'data_jitter', 81 | 'headers_remove', 82 | 'host_stage', 83 | 'jitter', 84 | 'pipename_stager', 85 | 'pipename', 86 | 'sample_name', 87 | 'sleeptime', 88 | 'smb_frame_header', 89 | 'ssh_banner', 90 | 'ssh_pipename', 91 | 'tcp_frame_header', 92 | 'tcp_port', 93 | 'useragent', 94 | 'tasks_max_size', # added in 4.6 95 | 'tasks_proxy_max_size', # added in 4.6 96 | 'tasks_dns_proxy_max_size' # added in 4.6 97 | } 98 | 99 | # Blocks 100 | # Profile Variants 101 | PROFILE_VARIANTS: Set[str] = { 102 | 'http-get', 103 | 'http-post', 104 | 'http-stager', 105 | 'https-certificate', 106 | 'dns-beacon' 107 | } 108 | PROFILE_BLOCKS: Set[str] = { 109 | 'http-config', 110 | 'http-get', 111 | 'http-post', 112 | 'http-stager', 113 | 'https-certificate', 114 | 'code-signer', 115 | 'dns-beacon', 116 | 'stage', 117 | 'process-inject', 118 | 'post-inject', 119 | 'post-ex' 120 | } 121 | DATA_TRANSFORM_BLOCKS: Set[str] = { 122 | 'metadata', 123 | 'output', 124 | 'id' 125 | } 126 | 127 | # http-config 128 | HTTP_CONFIG_STATEMENTS: Set[str] = { 129 | 'header' 130 | } 131 | HTTP_CONFIG_OPTIONS: Set[str] = { 132 | 'trust_x_forwarded_for', 133 | 'block_useragents', 134 | 'allow_useragents' 135 | } 136 | # http-get, http-post, http-stager generics 137 | HTTP_OPTIONS: Set[str] = { 138 | 'uri', 139 | 'verb' 140 | } 141 | HTTP_BLOCKS: Set[str] = { 142 | 'client', 143 | 'server' 144 | } 145 | HTTP_CLIENT_STATEMENTS: Set[str] = { 146 | 'header', 147 | 'parameter' 148 | } 149 | HTTP_SERVER_BLOCKS: Set[str] = { 150 | 'output' 151 | } 152 | 153 | # http-get 154 | # http-get.client 155 | HTTP_GET_CLIENT_BLOCKS: Set[str] = { 156 | 'metadata' 157 | } 158 | 159 | # http-post 160 | # http-post.client 161 | HTTP_POST_CLIENT_BLOCKS: Set[str] = { 162 | 'id', 163 | 'output' 164 | } 165 | 166 | # http-stager 167 | HTTP_STAGER_OPTIONS: Set[str] = { 168 | 'uri_x86', 169 | 'uri_x64' 170 | } 171 | 172 | # https-certificate 173 | HTTPS_CERTIFICATE_OPTIONS: Set[str] = { 174 | 'CN', 175 | 'C', 176 | 'L', 177 | 'OU', 178 | 'O', 179 | 'ST', 180 | 'validity', 181 | 'keystore', 182 | 'password' 183 | } 184 | 185 | # dns-beacon 186 | DNS_BEACON_OPTIONS: Set[str] = { 187 | 'dns_idle', 188 | 'dns_max_txt', 189 | 'dns_sleep', 190 | 'dns_stager_prepend', 191 | 'dns_stager_subhost', 192 | 'dns_ttl', 193 | 'maxdns', 194 | 'beacon', 195 | 'get_AAAA', 196 | 'get_A', 197 | 'get_TXT', 198 | 'put_metadata', 199 | 'put_output', 200 | 'ns_response' 201 | } 202 | 203 | # code-signer 204 | CODE_SIGNER_OPTIONS: Set[str] = { 205 | 'alias', 206 | 'digest_algorithm', 207 | 'keystore', 208 | 'password', 209 | 'timestamp', 210 | 'timestamp_url' 211 | } 212 | 213 | # stage 214 | STAGE_STATEMENTS: Set[str] = { 215 | 'stringw', 216 | 'string', 217 | 'data' 218 | } 219 | STAGE_BLOCKS: Set[str] = { 220 | 'transform-x86', 221 | 'transform-x64' 222 | } 223 | STAGE_TRANSFORM_STATEMENTS: Set[str] = { 224 | 'prepend', 225 | 'append', 226 | 'strrep' 227 | } 228 | STAGE_OPTIONS: Set[str] = { 229 | 'allocator', 230 | 'cleanup', 231 | 'magic_mz_x86', 232 | 'magic_mz_x64', 233 | 'magic_pe', 234 | 'module_x64', 235 | 'module_x86', 236 | 'obfuscate', 237 | 'sleep_mask', 238 | 'smartinject', 239 | 'userwx', 240 | 'stomppe', 241 | 'syscall_method', # added in 4.8 242 | 'checksum', 243 | 'compile_time', 244 | 'entry_point', 245 | 'image_size_x64', 246 | 'image_size_x86', 247 | 'name', 248 | 'rich_header' 249 | } 250 | 251 | # process-inject 252 | PROCESS_INJECT_BLOCKS: Set[str] = { 253 | 'transform-x86', 254 | 'transform-x64', 255 | 'execute' 256 | } 257 | PROCESS_INJECT_OPTIONS: Set[str] = { 258 | 'allocator', 259 | 'bof_allocator', # added in 4.7 260 | 'bof_reuse_memory', # added in 4.7 261 | 'min_alloc', 262 | 'startrwx', 263 | 'userwx' 264 | } 265 | PROCESS_INJECT_TRANSFORM_STATEMENTS: Set[str] = { 266 | 'prepend', 267 | 'append' 268 | } 269 | PROCESS_INJECT_EXECUTE_STATEMENTS: Set[str] = { 270 | 'CreateThread', 271 | 'CreateRemoteThread', 272 | 'NtQueueApcThread', 273 | 'NtQueueApcThread-s', 274 | 'RtlCreateUserThread', 275 | 'SetThreadContext' 276 | } 277 | 278 | # post-ex 279 | POST_EX_OPTIONS: Set[str] = { 280 | 'spawnto_x86', 281 | 'spawnto_x64', 282 | 'obfuscate', 283 | 'pipename', 284 | 'smartinject', 285 | 'thread_hint', 286 | 'amsi_disable', 287 | 'keylogger' 288 | } 289 | 290 | PROFILE: Dict = { 291 | 'http-config': { 292 | 'options': HTTP_CONFIG_OPTIONS, 293 | 'statements': HTTP_CONFIG_STATEMENTS, 294 | 'blocks': set() 295 | }, 296 | 'http-get': { 297 | 'options': HTTP_OPTIONS, 298 | 'statements': set(), 299 | 'blocks': HTTP_BLOCKS 300 | }, 301 | 'http-get.client': { 302 | 'options': set(), 303 | 'statements': HTTP_CLIENT_STATEMENTS, 304 | 'blocks': HTTP_GET_CLIENT_BLOCKS 305 | }, 306 | 'http-get.client.metadata': { 307 | 'options': set(), 308 | 'statements': DATA_TRANSFORM_STATEMENTS, 309 | 'blocks': set() 310 | }, 311 | 'http-get.server': { 312 | 'options': set(), 313 | 'statements': HTTP_CLIENT_STATEMENTS, 314 | 'blocks': HTTP_SERVER_BLOCKS 315 | }, 316 | 'http-get.server.output': { 317 | 'options': set(), 318 | 'statements': DATA_TRANSFORM_STATEMENTS, 319 | 'blocks': set() 320 | }, 321 | 'http-post': { 322 | 'options': HTTP_OPTIONS, 323 | 'statements': set(), 324 | 'blocks': HTTP_BLOCKS 325 | }, 326 | 'http-post.client': { 327 | 'options': set(), 328 | 'statements': HTTP_CLIENT_STATEMENTS, 329 | 'blocks': HTTP_POST_CLIENT_BLOCKS 330 | }, 331 | 'http-post.client.id': { 332 | 'options': set(), 333 | 'statements': DATA_TRANSFORM_STATEMENTS, 334 | 'blocks': set() 335 | }, 336 | 'http-post.client.output': { 337 | 'options': set(), 338 | 'statements': DATA_TRANSFORM_STATEMENTS, 339 | 'blocks': set() 340 | }, 341 | 'http-post.server': { 342 | 'options': set(), 343 | 'statements': HTTP_CLIENT_STATEMENTS, 344 | 'blocks': HTTP_SERVER_BLOCKS 345 | }, 346 | 'http-post.server.output': { 347 | 'options': set(), 348 | 'statements': DATA_TRANSFORM_STATEMENTS, 349 | 'blocks': set() 350 | }, 351 | 'http-stager': { 352 | 'options': HTTP_STAGER_OPTIONS, 353 | 'statements': set(), 354 | 'blocks': HTTP_BLOCKS 355 | }, 356 | 'http-stager.client': { 357 | 'options': set(), 358 | 'statements': HTTP_CLIENT_STATEMENTS, 359 | 'blocks': set() 360 | }, 361 | 'http-stager.server': { 362 | 'options': set(), 363 | 'statements': HTTP_CLIENT_STATEMENTS, 364 | 'blocks': HTTP_SERVER_BLOCKS 365 | }, 366 | 'http-stager.server.output': { 367 | 'options': set(), 368 | 'statements': DATA_TRANSFORM_STATEMENTS, 369 | 'blocks': set() 370 | }, 371 | 'https-certificate': { 372 | 'options': HTTPS_CERTIFICATE_OPTIONS, 373 | 'statements': set(), 374 | 'blocks': set() 375 | }, 376 | 'code-signer': { 377 | 'options': CODE_SIGNER_OPTIONS, 378 | 'statements': set(), 379 | 'blocks': set() 380 | }, 381 | 'dns-beacon': { 382 | 'options': DNS_BEACON_OPTIONS, 383 | 'statements': set(), 384 | 'blocks': set() 385 | }, 386 | 'stage': { 387 | 'options': STAGE_OPTIONS, 388 | 'statements': STAGE_STATEMENTS, 389 | 'blocks': STAGE_BLOCKS 390 | }, 391 | 'stage.transform-x86': { 392 | 'options': set(), 393 | 'statements': STAGE_TRANSFORM_STATEMENTS, 394 | 'blocks': set() 395 | }, 396 | 'stage.transform-x64': { 397 | 'options': set(), 398 | 'statements': STAGE_TRANSFORM_STATEMENTS, 399 | 'blocks': set() 400 | }, 401 | 'process-inject': { 402 | 'options': PROCESS_INJECT_OPTIONS, 403 | 'statements': set(), 404 | 'blocks': PROCESS_INJECT_BLOCKS 405 | }, 406 | 'process-inject.transform-x64': { 407 | 'options': set(), 408 | 'statements': DATA_TRANSFORM_STATEMENTS, 409 | 'blocks': set() 410 | }, 411 | 'process-inject.transform-x86': { 412 | 'options': set(), 413 | 'statements': DATA_TRANSFORM_STATEMENTS, 414 | 'blocks': set() 415 | }, 416 | 'process-inject.execute': { 417 | 'options': set(), 418 | 'statements': PROCESS_INJECT_EXECUTE_STATEMENTS, 419 | 'blocks': set() 420 | }, 421 | 'post-ex': { 422 | 'options': POST_EX_OPTIONS, 423 | 'statements': set(), 424 | 'blocks': set() 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /mpp/options/__init__.py: -------------------------------------------------------------------------------- 1 | """mpp.options module 2 | """ 3 | from .option import Option 4 | -------------------------------------------------------------------------------- /mpp/options/option.py: -------------------------------------------------------------------------------- 1 | """mpp.options module: Option 2 | """ 3 | import logging 4 | import re 5 | from typing import Set 6 | 7 | from mpp.constants import DELIM 8 | 9 | 10 | __all__ = [ 11 | "Option" 12 | ] 13 | 14 | 15 | # logger 16 | logger = logging.getLogger(__file__) 17 | 18 | 19 | class Option: 20 | """Option Class 21 | """ 22 | # This regex will parse an option, ignoring anything after a comment and any whitespace 23 | # that may occur between values 24 | OPTION_REGEX = re.compile(r'^\s*set\s+(\w+)\s+"([^"]*)"\s*;(?:\s*#.*|//.*)?', re.MULTILINE) 25 | 26 | def __init__(self, option: str, value: str): 27 | self.option = option 28 | self.value = value 29 | 30 | def __str__(self): 31 | return f'set {self.option} "{self.value}"{DELIM}' 32 | 33 | def __repr__(self): 34 | return f'Option(option="{self.option}", value="{self.value}")' 35 | 36 | @classmethod 37 | def from_string(cls, string: str): 38 | """Parses options in the following format and returns a list of class 39 | objects if options are found. 40 | Format: set [option] "[value]"; 41 | 42 | Args: 43 | string: _description_ 44 | 45 | Returns: 46 | _description_ 47 | """ 48 | matches = cls.OPTION_REGEX.findall(string) 49 | if matches: 50 | return [ 51 | cls(option=match[0], value=match[1]) 52 | for match in matches 53 | ] 54 | return [] 55 | 56 | def validate(self, valid_options: Set) -> bool: 57 | """Validate an option 58 | 59 | Args: 60 | valid_options: Valid options for a block or general. 61 | 62 | Returns: 63 | Boolean indicating validity. 64 | """ 65 | return self.option in valid_options 66 | -------------------------------------------------------------------------------- /mpp/profile.py: -------------------------------------------------------------------------------- 1 | """mpp module: Profile 2 | """ 3 | import logging 4 | import re 5 | from typing import Any, Dict, List, Tuple, Union 6 | 7 | import regex 8 | 9 | from mpp.blocks import Block 10 | from mpp.constants import (DNS_BEACON_OPTIONS, GLOBAL_OPTIONS, INVALID_BLOCK, 11 | INVALID_OPTION, INVALID_VARIANT, PROFILE_BLOCKS, 12 | PROFILE_VARIANTS) 13 | from mpp.options import Option 14 | 15 | 16 | # logger 17 | logger = logging.getLogger('MalleableProfile') 18 | 19 | 20 | __all__ = [ 21 | "BlockNotFound", 22 | "get_attr_recursively", 23 | "MalleableProfile", 24 | "OptionNotFound" 25 | ] 26 | 27 | 28 | class OptionNotFound(KeyError): 29 | """option was not found in the profile""" 30 | 31 | 32 | class BlockNotFound(KeyError): 33 | """block was not found in the profile""" 34 | 35 | 36 | class MalleableProfile: 37 | """MalleableProfile Class 38 | """ 39 | 40 | def __init__(self, profile: Union[str, List]): 41 | """Init Class Object 42 | 43 | Usage: 44 | Starting with mpp v0.4, users should leverage the class 45 | methods to initialize a class object. Backwards compatibility 46 | exists for filenames. 47 | 48 | Args: 49 | profile: Filename to open and parse or profile dict. 50 | 51 | 52 | Raises: 53 | FileNotFoundError: _description_ 54 | """ 55 | if isinstance(profile, list): 56 | self.profile = profile 57 | elif isinstance(profile, str): 58 | if '{' in profile: 59 | self.profile = self.from_string(string=profile) 60 | else: 61 | self.profile = self.from_file(filename=profile).profile 62 | else: 63 | raise TypeError(profile) 64 | 65 | def __str__(self): 66 | return "\n".join( 67 | [ 68 | str(item) 69 | for item in self.profile 70 | ] 71 | ) 72 | 73 | @property 74 | def blocks(self) -> List: 75 | """Get all root blocks 76 | 77 | Returns: 78 | List of root blocks. 79 | """ 80 | return [ 81 | item 82 | for item in self.profile 83 | if isinstance(item, Block) 84 | ] 85 | 86 | @property 87 | def options(self) -> List: 88 | """Get all global options 89 | 90 | Returns: 91 | List of global options. 92 | """ 93 | return [ 94 | item 95 | for item in self.profile 96 | if isinstance(item, Option) 97 | ] 98 | 99 | @classmethod 100 | def from_bytes(cls, data: bytes): 101 | """Parse a Malleable Profile from bytes 102 | 103 | Args: 104 | profile: Malleable Profile in bytes 105 | 106 | Returns: 107 | MalleableProfile object 108 | """ 109 | return cls.from_string(string=data.decode('utf-8')) 110 | 111 | @classmethod 112 | def from_file(cls, filename: str): 113 | """Parse Malleable Profile from file 114 | 115 | Args: 116 | profile: Filename 117 | 118 | Returns: 119 | MalleableProfile object 120 | """ 121 | with open(file=filename, mode='r', encoding='utf-8') as file: 122 | return cls.from_string(string=file.read()) 123 | 124 | @classmethod 125 | def from_string(cls, string: str) -> Dict: 126 | """Parse a Malleable Profile from a string and return 127 | a dictionary object containing a mapping of keys to 128 | objects. An object can be a Block, Statement, or Option. 129 | 130 | Args: 131 | profile: Malleable Profile. 132 | 133 | Returns: 134 | Parsed profile mapping. 135 | """ 136 | profile = [] 137 | 138 | # Get global options 139 | options = Option.from_string( 140 | string="".join( 141 | [ 142 | item 143 | for item in regex.split(Block.NON_BLOCK_DATA_REGEX, string, flags=re.MULTILINE | re.DOTALL) 144 | if item is not None 145 | ] 146 | ) 147 | ) 148 | if options: 149 | for option in options: 150 | profile.append(option) 151 | 152 | # Loop through root blocks 153 | blocks = regex.finditer(Block.BLOCK_REGEX, string, flags=re.MULTILINE | re.DOTALL) 154 | for match in blocks: 155 | profile.append(Block.from_string(string=match.group())) 156 | 157 | # Return class object 158 | return cls( 159 | profile=profile 160 | ) 161 | 162 | def validate(self, version: int = 4.0) -> Union[bool, List[Tuple]]: 163 | """Validate a Malleable Profile 164 | 165 | Args: 166 | version: Minimum version compliance (Default: 4.0) 167 | 168 | Returns: 169 | _description_ 170 | """ 171 | invalid_values = [] 172 | for item in self.profile: 173 | # blocks 174 | if isinstance(item, Block) and item.name not in PROFILE_BLOCKS: 175 | invalid_values.append((item, INVALID_BLOCK)) 176 | elif isinstance(item, Block) and item.name in PROFILE_BLOCKS: 177 | # check if variant and if allowed 178 | if item.variant: 179 | if item not in PROFILE_VARIANTS: 180 | invalid_values.append((item, INVALID_VARIANT)) 181 | tmp = item.validate() 182 | if isinstance(tmp, List): 183 | invalid_values += tmp 184 | elif isinstance(item, Option) and item.option not in GLOBAL_OPTIONS: 185 | # check if dns-beacon option (4.0-4.2) 186 | if item.option in DNS_BEACON_OPTIONS: 187 | if version >= 4.3: 188 | invalid_values.append((item, INVALID_OPTION)) 189 | else: 190 | logger.warning( 191 | f'starting with v4.3, dns options have been moved into ' 192 | f'\'dns-beacon\' block: {item.option}' 193 | ) 194 | if invalid_values: 195 | return invalid_values 196 | return True 197 | 198 | def __getattr__(self, item) -> Union[Block, Option, None]: 199 | # TODO return all matches for statements 200 | tmp = item.replace('_', '-') 201 | for i in self.profile: 202 | if isinstance(i, Block): 203 | if i.name in (tmp, item): 204 | return i 205 | elif isinstance(i, Option): 206 | if i.option in (tmp, item): 207 | return i 208 | 209 | def get_attr_recursively(profile, attribute: str) -> Any: 210 | """Recursive implementation to get a profile attribute. 211 | 212 | Args: 213 | profile: _description_ 214 | attribute: _description_ 215 | 216 | Returns: 217 | _description_ 218 | """ 219 | attributes = attribute.split('.') 220 | if len(attributes) > 1: 221 | return get_attr_recursively( 222 | getattr(profile, attributes[0]), 223 | attribute=attribute[len(attributes[0]) + 1:] 224 | ) 225 | return getattr(profile, attributes[0]) 226 | -------------------------------------------------------------------------------- /mpp/statements/__init__.py: -------------------------------------------------------------------------------- 1 | """mpp.statements module 2 | """ 3 | from .statement import * 4 | -------------------------------------------------------------------------------- /mpp/statements/statement.py: -------------------------------------------------------------------------------- 1 | """mpp.statements module: Statement 2 | """ 3 | import logging 4 | import re 5 | from typing import Set 6 | 7 | from mpp.constants import DELIM 8 | 9 | 10 | __all__ = [ 11 | "Statement", 12 | "HeaderParameter", 13 | "StringReplace" 14 | ] 15 | 16 | # logger 17 | logger = logging.getLogger(__file__) 18 | 19 | 20 | class Statement: 21 | """Statement Class 22 | """ 23 | STATEMENT_REGEX = re.compile( 24 | r'^\s*([\w\d]+)\s*(?:(?:"((?:[^"\\]|\\.)*)")|);' 25 | r'\s*(?:#|//).*|^\s*([\w\d]+)\s*(?:(?:"((?:[^"\\]|\\.)*)")|);\s*$', 26 | flags=re.MULTILINE 27 | ) 28 | 29 | def __init__(self, statement: str, value: str = ''): 30 | self.statement = statement 31 | self.value = value 32 | 33 | def validate(self, valid_statements: Set) -> bool: 34 | """Validate a statement 35 | 36 | Args: 37 | valid_statements: _description_ 38 | 39 | Returns: 40 | _description_ 41 | """ 42 | return self.statement in valid_statements 43 | 44 | @classmethod 45 | def from_string(cls, string): 46 | """ 47 | Parses statements in the following format and retuns a list 48 | of class objects if statements are found. 49 | Format: 50 | ; 51 | or 52 | "value"; 53 | 54 | Args: 55 | string: _description_ 56 | 57 | Raises: 58 | InvalidStatement: _description_ 59 | 60 | Returns: 61 | _description_ 62 | """ 63 | matches = cls.STATEMENT_REGEX.findall(string) 64 | if matches: 65 | return [ 66 | cls( 67 | statement=match[0] or match[2], 68 | value=match[1] or match[3] 69 | ) 70 | for match in matches 71 | ] 72 | return [] 73 | 74 | def __str__(self): 75 | if self.value: 76 | return f'{self.statement} "{self.value}"{DELIM}' 77 | return f'{self.statement}{DELIM}' 78 | 79 | def __repr__(self): 80 | return f'Statement(statement={self.statement}, value="{self.value}")' 81 | 82 | 83 | class HeaderParameter(Statement): 84 | """Header or Parameter Statement 85 | 86 | Args: 87 | Statement: _description_ 88 | """ 89 | STATEMENT_REGEX = re.compile( 90 | r'^\s*(header|parameter)\s+"([^"]+)"\s+"((?:[^"\\]|\\.)+)"\s*;', 91 | flags=re.MULTILINE 92 | ) 93 | 94 | def __init__(self, statement: str, key: str, value: str = ''): 95 | super().__init__(statement=statement) 96 | self.key = key 97 | self.value = value 98 | 99 | def __str__(self): 100 | if self.value: 101 | return f'{self.statement} "{self.key}" "{self.value}"{DELIM}' 102 | return f'{self.statement} "{self.key}"{DELIM}' 103 | 104 | def __repr__(self): 105 | return f'Statement(statement={self.statement}, key="{self.key}", value="{self.value}")' 106 | 107 | @classmethod 108 | def from_string(cls, string): 109 | """ 110 | Parses statements in the following format and retuns a list 111 | of class objects if statements are found. 112 | 113 | Args: 114 | string: _description_ 115 | 116 | Raises: 117 | InvalidStatement: _description_ 118 | 119 | Returns: 120 | _description_ 121 | """ 122 | matches = cls.STATEMENT_REGEX.findall(string) 123 | if matches: 124 | return [ 125 | cls( 126 | statement=match[0], 127 | key=match[1], 128 | value=match[2] 129 | ) 130 | for match in matches 131 | ] 132 | return [] 133 | 134 | 135 | class StringReplace(Statement): 136 | """String Replace Statement 137 | 138 | Args: 139 | Statement: _description_ 140 | """ 141 | STATEMENT_REGEX = re.compile(r'^\s*(strrep)\s+"([^"]+)"\s*"(.*?)"\s*;(?:\s*#.*|//.*)?', flags=re.MULTILINE) 142 | 143 | def __init__(self, statement: str, string: str, replace: str = ''): 144 | super().__init__(statement=statement) 145 | self.string = string 146 | self.replace = replace 147 | 148 | def __str__(self): 149 | return f'{self.statement} "{self.string}" "{self.replace}"{DELIM}' 150 | 151 | def __repr__(self): 152 | return ( 153 | f'Statement(statement={self.statement}, ' 154 | f'string="{self.string}", replace="{self.replace}")' 155 | ) 156 | 157 | @classmethod 158 | def from_string(cls, string): 159 | """ 160 | Parses statements in the following format and retuns a list 161 | of class objects if statements are found. 162 | 163 | Args: 164 | string: _description_ 165 | 166 | Raises: 167 | InvalidStatement: _description_ 168 | 169 | Returns: 170 | _description_ 171 | """ 172 | matches = cls.STATEMENT_REGEX.findall(string) 173 | if matches: 174 | return [ 175 | cls( 176 | statement=match[0], 177 | string=match[1], 178 | replace=match[2] 179 | ) 180 | for match in matches 181 | ] 182 | return [] 183 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "appnope" 5 | version = "0.1.4" 6 | description = "Disable App Nap on macOS >= 10.9" 7 | optional = false 8 | python-versions = ">=3.6" 9 | files = [ 10 | {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, 11 | {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, 12 | ] 13 | 14 | [[package]] 15 | name = "astroid" 16 | version = "2.15.8" 17 | description = "An abstract syntax tree for Python with inference support." 18 | optional = false 19 | python-versions = ">=3.7.2" 20 | files = [ 21 | {file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"}, 22 | {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"}, 23 | ] 24 | 25 | [package.dependencies] 26 | lazy-object-proxy = ">=1.4.0" 27 | wrapt = {version = ">=1.14,<2", markers = "python_version >= \"3.11\""} 28 | 29 | [[package]] 30 | name = "asttokens" 31 | version = "2.4.1" 32 | description = "Annotate AST trees with source code positions" 33 | optional = false 34 | python-versions = "*" 35 | files = [ 36 | {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, 37 | {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, 38 | ] 39 | 40 | [package.dependencies] 41 | six = ">=1.12.0" 42 | 43 | [package.extras] 44 | astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] 45 | test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] 46 | 47 | [[package]] 48 | name = "cffi" 49 | version = "1.16.0" 50 | description = "Foreign Function Interface for Python calling C code." 51 | optional = false 52 | python-versions = ">=3.8" 53 | files = [ 54 | {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, 55 | {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, 56 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, 57 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, 58 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, 59 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, 60 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, 61 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, 62 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, 63 | {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, 64 | {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, 65 | {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, 66 | {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, 67 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, 68 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, 69 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, 70 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, 71 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, 72 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, 73 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, 74 | {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, 75 | {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, 76 | {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, 77 | {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, 78 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, 79 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, 80 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, 81 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, 82 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, 83 | {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, 84 | {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, 85 | {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, 86 | {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, 87 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, 88 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, 89 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, 90 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, 91 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, 92 | {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, 93 | {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, 94 | {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, 95 | {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, 96 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, 97 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, 98 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, 99 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, 100 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, 101 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, 102 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, 103 | {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, 104 | {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, 105 | {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, 106 | ] 107 | 108 | [package.dependencies] 109 | pycparser = "*" 110 | 111 | [[package]] 112 | name = "colorama" 113 | version = "0.4.6" 114 | description = "Cross-platform colored terminal text." 115 | optional = false 116 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 117 | files = [ 118 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 119 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 120 | ] 121 | 122 | [[package]] 123 | name = "comm" 124 | version = "0.2.2" 125 | description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." 126 | optional = false 127 | python-versions = ">=3.8" 128 | files = [ 129 | {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, 130 | {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, 131 | ] 132 | 133 | [package.dependencies] 134 | traitlets = ">=4" 135 | 136 | [package.extras] 137 | test = ["pytest"] 138 | 139 | [[package]] 140 | name = "coverage" 141 | version = "7.4.4" 142 | description = "Code coverage measurement for Python" 143 | optional = false 144 | python-versions = ">=3.8" 145 | files = [ 146 | {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, 147 | {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, 148 | {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, 149 | {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, 150 | {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, 151 | {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, 152 | {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, 153 | {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, 154 | {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, 155 | {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, 156 | {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, 157 | {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, 158 | {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, 159 | {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, 160 | {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, 161 | {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, 162 | {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, 163 | {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, 164 | {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, 165 | {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, 166 | {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, 167 | {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, 168 | {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, 169 | {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, 170 | {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, 171 | {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, 172 | {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, 173 | {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, 174 | {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, 175 | {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, 176 | {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, 177 | {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, 178 | {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, 179 | {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, 180 | {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, 181 | {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, 182 | {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, 183 | {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, 184 | {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, 185 | {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, 186 | {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, 187 | {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, 188 | {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, 189 | {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, 190 | {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, 191 | {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, 192 | {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, 193 | {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, 194 | {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, 195 | {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, 196 | {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, 197 | {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, 198 | ] 199 | 200 | [package.extras] 201 | toml = ["tomli"] 202 | 203 | [[package]] 204 | name = "debugpy" 205 | version = "1.8.1" 206 | description = "An implementation of the Debug Adapter Protocol for Python" 207 | optional = false 208 | python-versions = ">=3.8" 209 | files = [ 210 | {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, 211 | {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, 212 | {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, 213 | {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, 214 | {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, 215 | {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, 216 | {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, 217 | {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, 218 | {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, 219 | {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, 220 | {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, 221 | {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, 222 | {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, 223 | {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, 224 | {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, 225 | {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, 226 | {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, 227 | {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, 228 | {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, 229 | {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, 230 | {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, 231 | {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, 232 | ] 233 | 234 | [[package]] 235 | name = "decorator" 236 | version = "5.1.1" 237 | description = "Decorators for Humans" 238 | optional = false 239 | python-versions = ">=3.5" 240 | files = [ 241 | {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, 242 | {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, 243 | ] 244 | 245 | [[package]] 246 | name = "dill" 247 | version = "0.3.8" 248 | description = "serialize all of Python" 249 | optional = false 250 | python-versions = ">=3.8" 251 | files = [ 252 | {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, 253 | {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, 254 | ] 255 | 256 | [package.extras] 257 | graph = ["objgraph (>=1.7.2)"] 258 | profile = ["gprof2dot (>=2022.7.29)"] 259 | 260 | [[package]] 261 | name = "executing" 262 | version = "2.0.1" 263 | description = "Get the currently executing AST node of a frame, and other information" 264 | optional = false 265 | python-versions = ">=3.5" 266 | files = [ 267 | {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, 268 | {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, 269 | ] 270 | 271 | [package.extras] 272 | tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] 273 | 274 | [[package]] 275 | name = "gitdb" 276 | version = "4.0.11" 277 | description = "Git Object Database" 278 | optional = false 279 | python-versions = ">=3.7" 280 | files = [ 281 | {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, 282 | {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, 283 | ] 284 | 285 | [package.dependencies] 286 | smmap = ">=3.0.1,<6" 287 | 288 | [[package]] 289 | name = "gitpython" 290 | version = "3.1.45" 291 | description = "GitPython is a Python library used to interact with Git repositories" 292 | optional = false 293 | python-versions = ">=3.7" 294 | files = [ 295 | {file = "gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77"}, 296 | {file = "gitpython-3.1.45.tar.gz", hash = "sha256:85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c"}, 297 | ] 298 | 299 | [package.dependencies] 300 | gitdb = ">=4.0.1,<5" 301 | 302 | [package.extras] 303 | doc = ["sphinx (>=7.1.2,<7.2)", "sphinx-autodoc-typehints", "sphinx_rtd_theme"] 304 | test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] 305 | 306 | [[package]] 307 | name = "iniconfig" 308 | version = "2.0.0" 309 | description = "brain-dead simple config-ini parsing" 310 | optional = false 311 | python-versions = ">=3.7" 312 | files = [ 313 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 314 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 315 | ] 316 | 317 | [[package]] 318 | name = "ipykernel" 319 | version = "6.30.1" 320 | description = "IPython Kernel for Jupyter" 321 | optional = false 322 | python-versions = ">=3.9" 323 | files = [ 324 | {file = "ipykernel-6.30.1-py3-none-any.whl", hash = "sha256:aa6b9fb93dca949069d8b85b6c79b2518e32ac583ae9c7d37c51d119e18b3fb4"}, 325 | {file = "ipykernel-6.30.1.tar.gz", hash = "sha256:6abb270161896402e76b91394fcdce5d1be5d45f456671e5080572f8505be39b"}, 326 | ] 327 | 328 | [package.dependencies] 329 | appnope = {version = ">=0.1.2", markers = "platform_system == \"Darwin\""} 330 | comm = ">=0.1.1" 331 | debugpy = ">=1.6.5" 332 | ipython = ">=7.23.1" 333 | jupyter-client = ">=8.0.0" 334 | jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" 335 | matplotlib-inline = ">=0.1" 336 | nest-asyncio = ">=1.4" 337 | packaging = ">=22" 338 | psutil = ">=5.7" 339 | pyzmq = ">=25" 340 | tornado = ">=6.2" 341 | traitlets = ">=5.4.0" 342 | 343 | [package.extras] 344 | cov = ["coverage[toml]", "matplotlib", "pytest-cov", "trio"] 345 | docs = ["intersphinx-registry", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] 346 | pyqt5 = ["pyqt5"] 347 | pyside6 = ["pyside6"] 348 | test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0,<9)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] 349 | 350 | [[package]] 351 | name = "ipython" 352 | version = "8.22.2" 353 | description = "IPython: Productive Interactive Computing" 354 | optional = false 355 | python-versions = ">=3.10" 356 | files = [ 357 | {file = "ipython-8.22.2-py3-none-any.whl", hash = "sha256:3c86f284c8f3d8f2b6c662f885c4889a91df7cd52056fd02b7d8d6195d7f56e9"}, 358 | {file = "ipython-8.22.2.tar.gz", hash = "sha256:2dcaad9049f9056f1fef63514f176c7d41f930daa78d05b82a176202818f2c14"}, 359 | ] 360 | 361 | [package.dependencies] 362 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 363 | decorator = "*" 364 | jedi = ">=0.16" 365 | matplotlib-inline = "*" 366 | pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} 367 | prompt-toolkit = ">=3.0.41,<3.1.0" 368 | pygments = ">=2.4.0" 369 | stack-data = "*" 370 | traitlets = ">=5.13.0" 371 | 372 | [package.extras] 373 | all = ["ipython[black,doc,kernel,nbconvert,nbformat,notebook,parallel,qtconsole,terminal]", "ipython[test,test-extra]"] 374 | black = ["black"] 375 | doc = ["docrepr", "exceptiongroup", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "stack-data", "typing-extensions"] 376 | kernel = ["ipykernel"] 377 | nbconvert = ["nbconvert"] 378 | nbformat = ["nbformat"] 379 | notebook = ["ipywidgets", "notebook"] 380 | parallel = ["ipyparallel"] 381 | qtconsole = ["qtconsole"] 382 | test = ["pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "testpath"] 383 | test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] 384 | 385 | [[package]] 386 | name = "isort" 387 | version = "5.13.2" 388 | description = "A Python utility / library to sort Python imports." 389 | optional = false 390 | python-versions = ">=3.8.0" 391 | files = [ 392 | {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, 393 | {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, 394 | ] 395 | 396 | [package.extras] 397 | colors = ["colorama (>=0.4.6)"] 398 | 399 | [[package]] 400 | name = "jedi" 401 | version = "0.19.1" 402 | description = "An autocompletion tool for Python that can be used for text editors." 403 | optional = false 404 | python-versions = ">=3.6" 405 | files = [ 406 | {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, 407 | {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, 408 | ] 409 | 410 | [package.dependencies] 411 | parso = ">=0.8.3,<0.9.0" 412 | 413 | [package.extras] 414 | docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] 415 | qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] 416 | testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] 417 | 418 | [[package]] 419 | name = "jupyter-client" 420 | version = "8.6.1" 421 | description = "Jupyter protocol implementation and client libraries" 422 | optional = false 423 | python-versions = ">=3.8" 424 | files = [ 425 | {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, 426 | {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, 427 | ] 428 | 429 | [package.dependencies] 430 | jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" 431 | python-dateutil = ">=2.8.2" 432 | pyzmq = ">=23.0" 433 | tornado = ">=6.2" 434 | traitlets = ">=5.3" 435 | 436 | [package.extras] 437 | docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] 438 | test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] 439 | 440 | [[package]] 441 | name = "jupyter-core" 442 | version = "5.7.2" 443 | description = "Jupyter core package. A base package on which Jupyter projects rely." 444 | optional = false 445 | python-versions = ">=3.8" 446 | files = [ 447 | {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, 448 | {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, 449 | ] 450 | 451 | [package.dependencies] 452 | platformdirs = ">=2.5" 453 | pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} 454 | traitlets = ">=5.3" 455 | 456 | [package.extras] 457 | docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] 458 | test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] 459 | 460 | [[package]] 461 | name = "lazy-object-proxy" 462 | version = "1.10.0" 463 | description = "A fast and thorough lazy object proxy." 464 | optional = false 465 | python-versions = ">=3.8" 466 | files = [ 467 | {file = "lazy-object-proxy-1.10.0.tar.gz", hash = "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69"}, 468 | {file = "lazy_object_proxy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977"}, 469 | {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab7004cf2e59f7c2e4345604a3e6ea0d92ac44e1c2375527d56492014e690c3"}, 470 | {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc0d2fc424e54c70c4bc06787e4072c4f3b1aa2f897dfdc34ce1013cf3ceef05"}, 471 | {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e2adb09778797da09d2b5ebdbceebf7dd32e2c96f79da9052b2e87b6ea495895"}, 472 | {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1f711e2c6dcd4edd372cf5dec5c5a30d23bba06ee012093267b3376c079ec83"}, 473 | {file = "lazy_object_proxy-1.10.0-cp310-cp310-win32.whl", hash = "sha256:76a095cfe6045c7d0ca77db9934e8f7b71b14645f0094ffcd842349ada5c5fb9"}, 474 | {file = "lazy_object_proxy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:b4f87d4ed9064b2628da63830986c3d2dca7501e6018347798313fcf028e2fd4"}, 475 | {file = "lazy_object_proxy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fec03caabbc6b59ea4a638bee5fce7117be8e99a4103d9d5ad77f15d6f81020c"}, 476 | {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c83f957782cbbe8136bee26416686a6ae998c7b6191711a04da776dc9e47d4"}, 477 | {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009e6bb1f1935a62889ddc8541514b6a9e1fcf302667dcb049a0be5c8f613e56"}, 478 | {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75fc59fc450050b1b3c203c35020bc41bd2695ed692a392924c6ce180c6f1dc9"}, 479 | {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:782e2c9b2aab1708ffb07d4bf377d12901d7a1d99e5e410d648d892f8967ab1f"}, 480 | {file = "lazy_object_proxy-1.10.0-cp311-cp311-win32.whl", hash = "sha256:edb45bb8278574710e68a6b021599a10ce730d156e5b254941754a9cc0b17d03"}, 481 | {file = "lazy_object_proxy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:e271058822765ad5e3bca7f05f2ace0de58a3f4e62045a8c90a0dfd2f8ad8cc6"}, 482 | {file = "lazy_object_proxy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e98c8af98d5707dcdecc9ab0863c0ea6e88545d42ca7c3feffb6b4d1e370c7ba"}, 483 | {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:952c81d415b9b80ea261d2372d2a4a2332a3890c2b83e0535f263ddfe43f0d43"}, 484 | {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80b39d3a151309efc8cc48675918891b865bdf742a8616a337cb0090791a0de9"}, 485 | {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e221060b701e2aa2ea991542900dd13907a5c90fa80e199dbf5a03359019e7a3"}, 486 | {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92f09ff65ecff3108e56526f9e2481b8116c0b9e1425325e13245abfd79bdb1b"}, 487 | {file = "lazy_object_proxy-1.10.0-cp312-cp312-win32.whl", hash = "sha256:3ad54b9ddbe20ae9f7c1b29e52f123120772b06dbb18ec6be9101369d63a4074"}, 488 | {file = "lazy_object_proxy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:127a789c75151db6af398b8972178afe6bda7d6f68730c057fbbc2e96b08d282"}, 489 | {file = "lazy_object_proxy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4ed0518a14dd26092614412936920ad081a424bdcb54cc13349a8e2c6d106a"}, 490 | {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ad9e6ed739285919aa9661a5bbed0aaf410aa60231373c5579c6b4801bd883c"}, 491 | {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fc0a92c02fa1ca1e84fc60fa258458e5bf89d90a1ddaeb8ed9cc3147f417255"}, 492 | {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0aefc7591920bbd360d57ea03c995cebc204b424524a5bd78406f6e1b8b2a5d8"}, 493 | {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5faf03a7d8942bb4476e3b62fd0f4cf94eaf4618e304a19865abf89a35c0bbee"}, 494 | {file = "lazy_object_proxy-1.10.0-cp38-cp38-win32.whl", hash = "sha256:e333e2324307a7b5d86adfa835bb500ee70bfcd1447384a822e96495796b0ca4"}, 495 | {file = "lazy_object_proxy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:cb73507defd385b7705c599a94474b1d5222a508e502553ef94114a143ec6696"}, 496 | {file = "lazy_object_proxy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366c32fe5355ef5fc8a232c5436f4cc66e9d3e8967c01fb2e6302fd6627e3d94"}, 497 | {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2297f08f08a2bb0d32a4265e98a006643cd7233fb7983032bd61ac7a02956b3b"}, 498 | {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18dd842b49456aaa9a7cf535b04ca4571a302ff72ed8740d06b5adcd41fe0757"}, 499 | {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:217138197c170a2a74ca0e05bddcd5f1796c735c37d0eee33e43259b192aa424"}, 500 | {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a3a87cf1e133e5b1994144c12ca4aa3d9698517fe1e2ca82977781b16955658"}, 501 | {file = "lazy_object_proxy-1.10.0-cp39-cp39-win32.whl", hash = "sha256:30b339b2a743c5288405aa79a69e706a06e02958eab31859f7f3c04980853b70"}, 502 | {file = "lazy_object_proxy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:a899b10e17743683b293a729d3a11f2f399e8a90c73b089e29f5d0fe3509f0dd"}, 503 | {file = "lazy_object_proxy-1.10.0-pp310.pp311.pp312.pp38.pp39-none-any.whl", hash = "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d"}, 504 | ] 505 | 506 | [[package]] 507 | name = "matplotlib-inline" 508 | version = "0.1.6" 509 | description = "Inline Matplotlib backend for Jupyter" 510 | optional = false 511 | python-versions = ">=3.5" 512 | files = [ 513 | {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, 514 | {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, 515 | ] 516 | 517 | [package.dependencies] 518 | traitlets = "*" 519 | 520 | [[package]] 521 | name = "mccabe" 522 | version = "0.7.0" 523 | description = "McCabe checker, plugin for flake8" 524 | optional = false 525 | python-versions = ">=3.6" 526 | files = [ 527 | {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, 528 | {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, 529 | ] 530 | 531 | [[package]] 532 | name = "nest-asyncio" 533 | version = "1.6.0" 534 | description = "Patch asyncio to allow nested event loops" 535 | optional = false 536 | python-versions = ">=3.5" 537 | files = [ 538 | {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, 539 | {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, 540 | ] 541 | 542 | [[package]] 543 | name = "packaging" 544 | version = "24.0" 545 | description = "Core utilities for Python packages" 546 | optional = false 547 | python-versions = ">=3.7" 548 | files = [ 549 | {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, 550 | {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, 551 | ] 552 | 553 | [[package]] 554 | name = "parso" 555 | version = "0.8.3" 556 | description = "A Python Parser" 557 | optional = false 558 | python-versions = ">=3.6" 559 | files = [ 560 | {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, 561 | {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, 562 | ] 563 | 564 | [package.extras] 565 | qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] 566 | testing = ["docopt", "pytest (<6.0.0)"] 567 | 568 | [[package]] 569 | name = "pexpect" 570 | version = "4.9.0" 571 | description = "Pexpect allows easy control of interactive console applications." 572 | optional = false 573 | python-versions = "*" 574 | files = [ 575 | {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, 576 | {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, 577 | ] 578 | 579 | [package.dependencies] 580 | ptyprocess = ">=0.5" 581 | 582 | [[package]] 583 | name = "platformdirs" 584 | version = "4.2.0" 585 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 586 | optional = false 587 | python-versions = ">=3.8" 588 | files = [ 589 | {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, 590 | {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, 591 | ] 592 | 593 | [package.extras] 594 | docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] 595 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] 596 | 597 | [[package]] 598 | name = "pluggy" 599 | version = "1.4.0" 600 | description = "plugin and hook calling mechanisms for python" 601 | optional = false 602 | python-versions = ">=3.8" 603 | files = [ 604 | {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, 605 | {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, 606 | ] 607 | 608 | [package.extras] 609 | dev = ["pre-commit", "tox"] 610 | testing = ["pytest", "pytest-benchmark"] 611 | 612 | [[package]] 613 | name = "prompt-toolkit" 614 | version = "3.0.43" 615 | description = "Library for building powerful interactive command lines in Python" 616 | optional = false 617 | python-versions = ">=3.7.0" 618 | files = [ 619 | {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, 620 | {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, 621 | ] 622 | 623 | [package.dependencies] 624 | wcwidth = "*" 625 | 626 | [[package]] 627 | name = "psutil" 628 | version = "5.9.8" 629 | description = "Cross-platform lib for process and system monitoring in Python." 630 | optional = false 631 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 632 | files = [ 633 | {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, 634 | {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, 635 | {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, 636 | {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, 637 | {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, 638 | {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, 639 | {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, 640 | {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, 641 | {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, 642 | {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, 643 | {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, 644 | {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, 645 | {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, 646 | {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, 647 | {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, 648 | {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, 649 | ] 650 | 651 | [package.extras] 652 | test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] 653 | 654 | [[package]] 655 | name = "ptyprocess" 656 | version = "0.7.0" 657 | description = "Run a subprocess in a pseudo terminal" 658 | optional = false 659 | python-versions = "*" 660 | files = [ 661 | {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, 662 | {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, 663 | ] 664 | 665 | [[package]] 666 | name = "pure-eval" 667 | version = "0.2.2" 668 | description = "Safely evaluate AST nodes without side effects" 669 | optional = false 670 | python-versions = "*" 671 | files = [ 672 | {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, 673 | {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, 674 | ] 675 | 676 | [package.extras] 677 | tests = ["pytest"] 678 | 679 | [[package]] 680 | name = "pycparser" 681 | version = "2.21" 682 | description = "C parser in Python" 683 | optional = false 684 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 685 | files = [ 686 | {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, 687 | {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, 688 | ] 689 | 690 | [[package]] 691 | name = "pygments" 692 | version = "2.17.2" 693 | description = "Pygments is a syntax highlighting package written in Python." 694 | optional = false 695 | python-versions = ">=3.7" 696 | files = [ 697 | {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, 698 | {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, 699 | ] 700 | 701 | [package.extras] 702 | plugins = ["importlib-metadata"] 703 | windows-terminal = ["colorama (>=0.4.6)"] 704 | 705 | [[package]] 706 | name = "pylint" 707 | version = "2.17.7" 708 | description = "python code static checker" 709 | optional = false 710 | python-versions = ">=3.7.2" 711 | files = [ 712 | {file = "pylint-2.17.7-py3-none-any.whl", hash = "sha256:27a8d4c7ddc8c2f8c18aa0050148f89ffc09838142193fdbe98f172781a3ff87"}, 713 | {file = "pylint-2.17.7.tar.gz", hash = "sha256:f4fcac7ae74cfe36bc8451e931d8438e4a476c20314b1101c458ad0f05191fad"}, 714 | ] 715 | 716 | [package.dependencies] 717 | astroid = ">=2.15.8,<=2.17.0-dev0" 718 | colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} 719 | dill = {version = ">=0.3.6", markers = "python_version >= \"3.11\""} 720 | isort = ">=4.2.5,<6" 721 | mccabe = ">=0.6,<0.8" 722 | platformdirs = ">=2.2.0" 723 | tomlkit = ">=0.10.1" 724 | 725 | [package.extras] 726 | spelling = ["pyenchant (>=3.2,<4.0)"] 727 | testutils = ["gitpython (>3)"] 728 | 729 | [[package]] 730 | name = "pytest" 731 | version = "7.4.4" 732 | description = "pytest: simple powerful testing with Python" 733 | optional = false 734 | python-versions = ">=3.7" 735 | files = [ 736 | {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, 737 | {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, 738 | ] 739 | 740 | [package.dependencies] 741 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 742 | iniconfig = "*" 743 | packaging = "*" 744 | pluggy = ">=0.12,<2.0" 745 | 746 | [package.extras] 747 | testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] 748 | 749 | [[package]] 750 | name = "pytest-cov" 751 | version = "4.1.0" 752 | description = "Pytest plugin for measuring coverage." 753 | optional = false 754 | python-versions = ">=3.7" 755 | files = [ 756 | {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, 757 | {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, 758 | ] 759 | 760 | [package.dependencies] 761 | coverage = {version = ">=5.2.1", extras = ["toml"]} 762 | pytest = ">=4.6" 763 | 764 | [package.extras] 765 | testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] 766 | 767 | [[package]] 768 | name = "python-dateutil" 769 | version = "2.9.0.post0" 770 | description = "Extensions to the standard Python datetime module" 771 | optional = false 772 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 773 | files = [ 774 | {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, 775 | {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, 776 | ] 777 | 778 | [package.dependencies] 779 | six = ">=1.5" 780 | 781 | [[package]] 782 | name = "pywin32" 783 | version = "306" 784 | description = "Python for Window Extensions" 785 | optional = false 786 | python-versions = "*" 787 | files = [ 788 | {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, 789 | {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, 790 | {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, 791 | {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, 792 | {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, 793 | {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, 794 | {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, 795 | {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, 796 | {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, 797 | {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, 798 | {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, 799 | {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, 800 | {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, 801 | {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, 802 | ] 803 | 804 | [[package]] 805 | name = "pyzmq" 806 | version = "25.1.2" 807 | description = "Python bindings for 0MQ" 808 | optional = false 809 | python-versions = ">=3.6" 810 | files = [ 811 | {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:e624c789359f1a16f83f35e2c705d07663ff2b4d4479bad35621178d8f0f6ea4"}, 812 | {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:49151b0efece79f6a79d41a461d78535356136ee70084a1c22532fc6383f4ad0"}, 813 | {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9a5f194cf730f2b24d6af1f833c14c10f41023da46a7f736f48b6d35061e76e"}, 814 | {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:faf79a302f834d9e8304fafdc11d0d042266667ac45209afa57e5efc998e3872"}, 815 | {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f51a7b4ead28d3fca8dda53216314a553b0f7a91ee8fc46a72b402a78c3e43d"}, 816 | {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0ddd6d71d4ef17ba5a87becf7ddf01b371eaba553c603477679ae817a8d84d75"}, 817 | {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:246747b88917e4867e2367b005fc8eefbb4a54b7db363d6c92f89d69abfff4b6"}, 818 | {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:00c48ae2fd81e2a50c3485de1b9d5c7c57cd85dc8ec55683eac16846e57ac979"}, 819 | {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a68d491fc20762b630e5db2191dd07ff89834086740f70e978bb2ef2668be08"}, 820 | {file = "pyzmq-25.1.2-cp310-cp310-win32.whl", hash = "sha256:09dfe949e83087da88c4a76767df04b22304a682d6154de2c572625c62ad6886"}, 821 | {file = "pyzmq-25.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:fa99973d2ed20417744fca0073390ad65ce225b546febb0580358e36aa90dba6"}, 822 | {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:82544e0e2d0c1811482d37eef297020a040c32e0687c1f6fc23a75b75db8062c"}, 823 | {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01171fc48542348cd1a360a4b6c3e7d8f46cdcf53a8d40f84db6707a6768acc1"}, 824 | {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc69c96735ab501419c432110016329bf0dea8898ce16fab97c6d9106dc0b348"}, 825 | {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e124e6b1dd3dfbeb695435dff0e383256655bb18082e094a8dd1f6293114642"}, 826 | {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7598d2ba821caa37a0f9d54c25164a4fa351ce019d64d0b44b45540950458840"}, 827 | {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d1299d7e964c13607efd148ca1f07dcbf27c3ab9e125d1d0ae1d580a1682399d"}, 828 | {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4e6f689880d5ad87918430957297c975203a082d9a036cc426648fcbedae769b"}, 829 | {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cc69949484171cc961e6ecd4a8911b9ce7a0d1f738fcae717177c231bf77437b"}, 830 | {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9880078f683466b7f567b8624bfc16cad65077be046b6e8abb53bed4eeb82dd3"}, 831 | {file = "pyzmq-25.1.2-cp311-cp311-win32.whl", hash = "sha256:4e5837af3e5aaa99a091302df5ee001149baff06ad22b722d34e30df5f0d9097"}, 832 | {file = "pyzmq-25.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:25c2dbb97d38b5ac9fd15586e048ec5eb1e38f3d47fe7d92167b0c77bb3584e9"}, 833 | {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:11e70516688190e9c2db14fcf93c04192b02d457b582a1f6190b154691b4c93a"}, 834 | {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:313c3794d650d1fccaaab2df942af9f2c01d6217c846177cfcbc693c7410839e"}, 835 | {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b3cbba2f47062b85fe0ef9de5b987612140a9ba3a9c6d2543c6dec9f7c2ab27"}, 836 | {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc31baa0c32a2ca660784d5af3b9487e13b61b3032cb01a115fce6588e1bed30"}, 837 | {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c9087b109070c5ab0b383079fa1b5f797f8d43e9a66c07a4b8b8bdecfd88ee"}, 838 | {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f8429b17cbb746c3e043cb986328da023657e79d5ed258b711c06a70c2ea7537"}, 839 | {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5074adeacede5f810b7ef39607ee59d94e948b4fd954495bdb072f8c54558181"}, 840 | {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7ae8f354b895cbd85212da245f1a5ad8159e7840e37d78b476bb4f4c3f32a9fe"}, 841 | {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b264bf2cc96b5bc43ce0e852be995e400376bd87ceb363822e2cb1964fcdc737"}, 842 | {file = "pyzmq-25.1.2-cp312-cp312-win32.whl", hash = "sha256:02bbc1a87b76e04fd780b45e7f695471ae6de747769e540da909173d50ff8e2d"}, 843 | {file = "pyzmq-25.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:ced111c2e81506abd1dc142e6cd7b68dd53747b3b7ae5edbea4578c5eeff96b7"}, 844 | {file = "pyzmq-25.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7b6d09a8962a91151f0976008eb7b29b433a560fde056ec7a3db9ec8f1075438"}, 845 | {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967668420f36878a3c9ecb5ab33c9d0ff8d054f9c0233d995a6d25b0e95e1b6b"}, 846 | {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5edac3f57c7ddaacdb4d40f6ef2f9e299471fc38d112f4bc6d60ab9365445fb0"}, 847 | {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0dabfb10ef897f3b7e101cacba1437bd3a5032ee667b7ead32bbcdd1a8422fe7"}, 848 | {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2c6441e0398c2baacfe5ba30c937d274cfc2dc5b55e82e3749e333aabffde561"}, 849 | {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:16b726c1f6c2e7625706549f9dbe9b06004dfbec30dbed4bf50cbdfc73e5b32a"}, 850 | {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:a86c2dd76ef71a773e70551a07318b8e52379f58dafa7ae1e0a4be78efd1ff16"}, 851 | {file = "pyzmq-25.1.2-cp36-cp36m-win32.whl", hash = "sha256:359f7f74b5d3c65dae137f33eb2bcfa7ad9ebefd1cab85c935f063f1dbb245cc"}, 852 | {file = "pyzmq-25.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:55875492f820d0eb3417b51d96fea549cde77893ae3790fd25491c5754ea2f68"}, 853 | {file = "pyzmq-25.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8c8a419dfb02e91b453615c69568442e897aaf77561ee0064d789705ff37a92"}, 854 | {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8807c87fa893527ae8a524c15fc505d9950d5e856f03dae5921b5e9aa3b8783b"}, 855 | {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5e319ed7d6b8f5fad9b76daa0a68497bc6f129858ad956331a5835785761e003"}, 856 | {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3c53687dde4d9d473c587ae80cc328e5b102b517447456184b485587ebd18b62"}, 857 | {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9add2e5b33d2cd765ad96d5eb734a5e795a0755f7fc49aa04f76d7ddda73fd70"}, 858 | {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e690145a8c0c273c28d3b89d6fb32c45e0d9605b2293c10e650265bf5c11cfec"}, 859 | {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:00a06faa7165634f0cac1abb27e54d7a0b3b44eb9994530b8ec73cf52e15353b"}, 860 | {file = "pyzmq-25.1.2-cp37-cp37m-win32.whl", hash = "sha256:0f97bc2f1f13cb16905a5f3e1fbdf100e712d841482b2237484360f8bc4cb3d7"}, 861 | {file = "pyzmq-25.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6cc0020b74b2e410287e5942e1e10886ff81ac77789eb20bec13f7ae681f0fdd"}, 862 | {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:bef02cfcbded83473bdd86dd8d3729cd82b2e569b75844fb4ea08fee3c26ae41"}, 863 | {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e10a4b5a4b1192d74853cc71a5e9fd022594573926c2a3a4802020360aa719d8"}, 864 | {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8c5f80e578427d4695adac6fdf4370c14a2feafdc8cb35549c219b90652536ae"}, 865 | {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5dde6751e857910c1339890f3524de74007958557593b9e7e8c5f01cd919f8a7"}, 866 | {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea1608dd169da230a0ad602d5b1ebd39807ac96cae1845c3ceed39af08a5c6df"}, 867 | {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0f513130c4c361201da9bc69df25a086487250e16b5571ead521b31ff6b02220"}, 868 | {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:019744b99da30330798bb37df33549d59d380c78e516e3bab9c9b84f87a9592f"}, 869 | {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2e2713ef44be5d52dd8b8e2023d706bf66cb22072e97fc71b168e01d25192755"}, 870 | {file = "pyzmq-25.1.2-cp38-cp38-win32.whl", hash = "sha256:07cd61a20a535524906595e09344505a9bd46f1da7a07e504b315d41cd42eb07"}, 871 | {file = "pyzmq-25.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb7e49a17fb8c77d3119d41a4523e432eb0c6932187c37deb6fbb00cc3028088"}, 872 | {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:94504ff66f278ab4b7e03e4cba7e7e400cb73bfa9d3d71f58d8972a8dc67e7a6"}, 873 | {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6dd0d50bbf9dca1d0bdea219ae6b40f713a3fb477c06ca3714f208fd69e16fd8"}, 874 | {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:004ff469d21e86f0ef0369717351073e0e577428e514c47c8480770d5e24a565"}, 875 | {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c0b5ca88a8928147b7b1e2dfa09f3b6c256bc1135a1338536cbc9ea13d3b7add"}, 876 | {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9a79f1d2495b167119d02be7448bfba57fad2a4207c4f68abc0bab4b92925b"}, 877 | {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:518efd91c3d8ac9f9b4f7dd0e2b7b8bf1a4fe82a308009016b07eaa48681af82"}, 878 | {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1ec23bd7b3a893ae676d0e54ad47d18064e6c5ae1fadc2f195143fb27373f7f6"}, 879 | {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db36c27baed588a5a8346b971477b718fdc66cf5b80cbfbd914b4d6d355e44e2"}, 880 | {file = "pyzmq-25.1.2-cp39-cp39-win32.whl", hash = "sha256:39b1067f13aba39d794a24761e385e2eddc26295826530a8c7b6c6c341584289"}, 881 | {file = "pyzmq-25.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:8e9f3fabc445d0ce320ea2c59a75fe3ea591fdbdeebec5db6de530dd4b09412e"}, 882 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a8c1d566344aee826b74e472e16edae0a02e2a044f14f7c24e123002dcff1c05"}, 883 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:759cfd391a0996345ba94b6a5110fca9c557ad4166d86a6e81ea526c376a01e8"}, 884 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c61e346ac34b74028ede1c6b4bcecf649d69b707b3ff9dc0fab453821b04d1e"}, 885 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cb8fc1f8d69b411b8ec0b5f1ffbcaf14c1db95b6bccea21d83610987435f1a4"}, 886 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3c00c9b7d1ca8165c610437ca0c92e7b5607b2f9076f4eb4b095c85d6e680a1d"}, 887 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:df0c7a16ebb94452d2909b9a7b3337940e9a87a824c4fc1c7c36bb4404cb0cde"}, 888 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:45999e7f7ed5c390f2e87ece7f6c56bf979fb213550229e711e45ecc7d42ccb8"}, 889 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ac170e9e048b40c605358667aca3d94e98f604a18c44bdb4c102e67070f3ac9b"}, 890 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b604734bec94f05f81b360a272fc824334267426ae9905ff32dc2be433ab96"}, 891 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a793ac733e3d895d96f865f1806f160696422554e46d30105807fdc9841b9f7d"}, 892 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0806175f2ae5ad4b835ecd87f5f85583316b69f17e97786f7443baaf54b9bb98"}, 893 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ef12e259e7bc317c7597d4f6ef59b97b913e162d83b421dd0db3d6410f17a244"}, 894 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea253b368eb41116011add00f8d5726762320b1bda892f744c91997b65754d73"}, 895 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b9b1f2ad6498445a941d9a4fee096d387fee436e45cc660e72e768d3d8ee611"}, 896 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8b14c75979ce932c53b79976a395cb2a8cd3aaf14aef75e8c2cb55a330b9b49d"}, 897 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:889370d5174a741a62566c003ee8ddba4b04c3f09a97b8000092b7ca83ec9c49"}, 898 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a18fff090441a40ffda8a7f4f18f03dc56ae73f148f1832e109f9bffa85df15"}, 899 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99a6b36f95c98839ad98f8c553d8507644c880cf1e0a57fe5e3a3f3969040882"}, 900 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4345c9a27f4310afbb9c01750e9461ff33d6fb74cd2456b107525bbeebcb5be3"}, 901 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3516e0b6224cf6e43e341d56da15fd33bdc37fa0c06af4f029f7d7dfceceabbc"}, 902 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:146b9b1f29ead41255387fb07be56dc29639262c0f7344f570eecdcd8d683314"}, 903 | {file = "pyzmq-25.1.2.tar.gz", hash = "sha256:93f1aa311e8bb912e34f004cf186407a4e90eec4f0ecc0efd26056bf7eda0226"}, 904 | ] 905 | 906 | [package.dependencies] 907 | cffi = {version = "*", markers = "implementation_name == \"pypy\""} 908 | 909 | [[package]] 910 | name = "regex" 911 | version = "2023.12.25" 912 | description = "Alternative regular expression module, to replace re." 913 | optional = false 914 | python-versions = ">=3.7" 915 | files = [ 916 | {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5"}, 917 | {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8"}, 918 | {file = "regex-2023.12.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586"}, 919 | {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c"}, 920 | {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400"}, 921 | {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e"}, 922 | {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4"}, 923 | {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5"}, 924 | {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd"}, 925 | {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704"}, 926 | {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1"}, 927 | {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392"}, 928 | {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423"}, 929 | {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f"}, 930 | {file = "regex-2023.12.25-cp310-cp310-win32.whl", hash = "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630"}, 931 | {file = "regex-2023.12.25-cp310-cp310-win_amd64.whl", hash = "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105"}, 932 | {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6"}, 933 | {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97"}, 934 | {file = "regex-2023.12.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887"}, 935 | {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb"}, 936 | {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c"}, 937 | {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b"}, 938 | {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa"}, 939 | {file = "regex-2023.12.25-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7"}, 940 | {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0"}, 941 | {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe"}, 942 | {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80"}, 943 | {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd"}, 944 | {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4"}, 945 | {file = "regex-2023.12.25-cp311-cp311-win32.whl", hash = "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87"}, 946 | {file = "regex-2023.12.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f"}, 947 | {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8a0ccf52bb37d1a700375a6b395bff5dd15c50acb745f7db30415bae3c2b0715"}, 948 | {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c3c4a78615b7762740531c27cf46e2f388d8d727d0c0c739e72048beb26c8a9d"}, 949 | {file = "regex-2023.12.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ad83e7545b4ab69216cef4cc47e344d19622e28aabec61574b20257c65466d6a"}, 950 | {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7a635871143661feccce3979e1727c4e094f2bdfd3ec4b90dfd4f16f571a87a"}, 951 | {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d498eea3f581fbe1b34b59c697512a8baef88212f92e4c7830fcc1499f5b45a5"}, 952 | {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43f7cd5754d02a56ae4ebb91b33461dc67be8e3e0153f593c509e21d219c5060"}, 953 | {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51f4b32f793812714fd5307222a7f77e739b9bc566dc94a18126aba3b92b98a3"}, 954 | {file = "regex-2023.12.25-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba99d8077424501b9616b43a2d208095746fb1284fc5ba490139651f971d39d9"}, 955 | {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4bfc2b16e3ba8850e0e262467275dd4d62f0d045e0e9eda2bc65078c0110a11f"}, 956 | {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8c2c19dae8a3eb0ea45a8448356ed561be843b13cbc34b840922ddf565498c1c"}, 957 | {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:60080bb3d8617d96f0fb7e19796384cc2467447ef1c491694850ebd3670bc457"}, 958 | {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b77e27b79448e34c2c51c09836033056a0547aa360c45eeeb67803da7b0eedaf"}, 959 | {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d"}, 960 | {file = "regex-2023.12.25-cp312-cp312-win32.whl", hash = "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5"}, 961 | {file = "regex-2023.12.25-cp312-cp312-win_amd64.whl", hash = "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232"}, 962 | {file = "regex-2023.12.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69"}, 963 | {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7"}, 964 | {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73"}, 965 | {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2"}, 966 | {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482"}, 967 | {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f"}, 968 | {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8"}, 969 | {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a"}, 970 | {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39"}, 971 | {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b"}, 972 | {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347"}, 973 | {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39"}, 974 | {file = "regex-2023.12.25-cp37-cp37m-win32.whl", hash = "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c"}, 975 | {file = "regex-2023.12.25-cp37-cp37m-win_amd64.whl", hash = "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445"}, 976 | {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53"}, 977 | {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64"}, 978 | {file = "regex-2023.12.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415"}, 979 | {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086dd15e9435b393ae06f96ab69ab2d333f5d65cbe65ca5a3ef0ec9564dfe770"}, 980 | {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e81469f7d01efed9b53740aedd26085f20d49da65f9c1f41e822a33992cb1590"}, 981 | {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34e4af5b27232f68042aa40a91c3b9bb4da0eeb31b7632e0091afc4310afe6cb"}, 982 | {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9852b76ab558e45b20bf1893b59af64a28bd3820b0c2efc80e0a70a4a3ea51c1"}, 983 | {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff100b203092af77d1a5a7abe085b3506b7eaaf9abf65b73b7d6905b6cb76988"}, 984 | {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cc038b2d8b1470364b1888a98fd22d616fba2b6309c5b5f181ad4483e0017861"}, 985 | {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:094ba386bb5c01e54e14434d4caabf6583334090865b23ef58e0424a6286d3dc"}, 986 | {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5cd05d0f57846d8ba4b71d9c00f6f37d6b97d5e5ef8b3c3840426a475c8f70f4"}, 987 | {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:9aa1a67bbf0f957bbe096375887b2505f5d8ae16bf04488e8b0f334c36e31360"}, 988 | {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:98a2636994f943b871786c9e82bfe7883ecdaba2ef5df54e1450fa9869d1f756"}, 989 | {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37f8e93a81fc5e5bd8db7e10e62dc64261bcd88f8d7e6640aaebe9bc180d9ce2"}, 990 | {file = "regex-2023.12.25-cp38-cp38-win32.whl", hash = "sha256:d78bd484930c1da2b9679290a41cdb25cc127d783768a0369d6b449e72f88beb"}, 991 | {file = "regex-2023.12.25-cp38-cp38-win_amd64.whl", hash = "sha256:b521dcecebc5b978b447f0f69b5b7f3840eac454862270406a39837ffae4e697"}, 992 | {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31"}, 993 | {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7"}, 994 | {file = "regex-2023.12.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc"}, 995 | {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95"}, 996 | {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1"}, 997 | {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf"}, 998 | {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae"}, 999 | {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6"}, 1000 | {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923"}, 1001 | {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d"}, 1002 | {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca"}, 1003 | {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5"}, 1004 | {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f"}, 1005 | {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20"}, 1006 | {file = "regex-2023.12.25-cp39-cp39-win32.whl", hash = "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9"}, 1007 | {file = "regex-2023.12.25-cp39-cp39-win_amd64.whl", hash = "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91"}, 1008 | {file = "regex-2023.12.25.tar.gz", hash = "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5"}, 1009 | ] 1010 | 1011 | [[package]] 1012 | name = "six" 1013 | version = "1.16.0" 1014 | description = "Python 2 and 3 compatibility utilities" 1015 | optional = false 1016 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 1017 | files = [ 1018 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 1019 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 1020 | ] 1021 | 1022 | [[package]] 1023 | name = "smmap" 1024 | version = "5.0.1" 1025 | description = "A pure Python implementation of a sliding window memory map manager" 1026 | optional = false 1027 | python-versions = ">=3.7" 1028 | files = [ 1029 | {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, 1030 | {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, 1031 | ] 1032 | 1033 | [[package]] 1034 | name = "stack-data" 1035 | version = "0.6.3" 1036 | description = "Extract data from python stack frames and tracebacks for informative displays" 1037 | optional = false 1038 | python-versions = "*" 1039 | files = [ 1040 | {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, 1041 | {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, 1042 | ] 1043 | 1044 | [package.dependencies] 1045 | asttokens = ">=2.1.0" 1046 | executing = ">=1.2.0" 1047 | pure-eval = "*" 1048 | 1049 | [package.extras] 1050 | tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] 1051 | 1052 | [[package]] 1053 | name = "tomlkit" 1054 | version = "0.12.4" 1055 | description = "Style preserving TOML library" 1056 | optional = false 1057 | python-versions = ">=3.7" 1058 | files = [ 1059 | {file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b"}, 1060 | {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"}, 1061 | ] 1062 | 1063 | [[package]] 1064 | name = "tornado" 1065 | version = "6.4" 1066 | description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." 1067 | optional = false 1068 | python-versions = ">= 3.8" 1069 | files = [ 1070 | {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, 1071 | {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, 1072 | {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, 1073 | {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, 1074 | {file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"}, 1075 | {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, 1076 | {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, 1077 | {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, 1078 | {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, 1079 | {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, 1080 | {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "traitlets" 1085 | version = "5.14.2" 1086 | description = "Traitlets Python configuration system" 1087 | optional = false 1088 | python-versions = ">=3.8" 1089 | files = [ 1090 | {file = "traitlets-5.14.2-py3-none-any.whl", hash = "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80"}, 1091 | {file = "traitlets-5.14.2.tar.gz", hash = "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9"}, 1092 | ] 1093 | 1094 | [package.extras] 1095 | docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] 1096 | test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.1)", "pytest-mock", "pytest-mypy-testing"] 1097 | 1098 | [[package]] 1099 | name = "wcwidth" 1100 | version = "0.2.13" 1101 | description = "Measures the displayed width of unicode strings in a terminal" 1102 | optional = false 1103 | python-versions = "*" 1104 | files = [ 1105 | {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, 1106 | {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, 1107 | ] 1108 | 1109 | [[package]] 1110 | name = "wrapt" 1111 | version = "1.16.0" 1112 | description = "Module for decorators, wrappers and monkey patching." 1113 | optional = false 1114 | python-versions = ">=3.6" 1115 | files = [ 1116 | {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, 1117 | {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, 1118 | {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, 1119 | {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, 1120 | {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, 1121 | {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, 1122 | {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, 1123 | {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, 1124 | {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, 1125 | {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, 1126 | {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, 1127 | {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, 1128 | {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, 1129 | {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, 1130 | {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, 1131 | {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, 1132 | {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, 1133 | {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, 1134 | {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, 1135 | {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, 1136 | {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, 1137 | {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, 1138 | {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, 1139 | {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, 1140 | {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, 1141 | {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, 1142 | {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, 1143 | {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, 1144 | {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, 1145 | {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, 1146 | {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, 1147 | {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, 1148 | {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, 1149 | {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, 1150 | {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, 1151 | {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, 1152 | {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, 1153 | {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, 1154 | {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, 1155 | {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, 1156 | {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, 1157 | {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, 1158 | {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, 1159 | {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, 1160 | {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, 1161 | {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, 1162 | {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, 1163 | {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, 1164 | {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, 1165 | {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, 1166 | {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, 1167 | {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, 1168 | {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, 1169 | {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, 1170 | {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, 1171 | {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, 1172 | {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, 1173 | {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, 1174 | {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, 1175 | {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, 1176 | {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, 1177 | {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, 1178 | {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, 1179 | {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, 1180 | {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, 1181 | {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, 1182 | {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, 1183 | {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, 1184 | {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, 1185 | {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, 1186 | ] 1187 | 1188 | [metadata] 1189 | lock-version = "2.0" 1190 | python-versions = "^3.13.7" 1191 | content-hash = "3e4e2bb52f4bbae85a95af65ff68d22b57c7ce9b6365573d9b81343aa8b3a544" 1192 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "pyMalleableProfileParser" 3 | version = "0.4.0" 4 | description = "Parses Cobalt Strike malleable profiles." 5 | authors = ["Brett Fitzpatrick "] 6 | license = "MIT" 7 | readme = "README.md" 8 | homepage = "https://github.com/brett-fitz/pyMalleableProfileParser" 9 | repository = "https://github.com/brett-fitz/pyMalleableProfileParser" 10 | keywords = ["cobalt strike", "malleable profile", "parser"] 11 | classifiers = ["Development Status :: 4 - Beta"] 12 | packages = [ 13 | { include = "mpp" } 14 | ] 15 | 16 | [tool.poetry.dependencies] 17 | python = "^3.13.7" 18 | regex = "^2023.12.25" 19 | 20 | [tool.poetry.group.dev.dependencies] 21 | pytest = "^7.4.4" 22 | pylint = "^2.17.7" 23 | ipykernel = "^6.30.1" 24 | gitpython = "^3.1.45" 25 | pytest-cov = "^4.1.0" 26 | 27 | [build-system] 28 | requires = ["poetry-core"] 29 | build-backend = "poetry.core.masonry.api" 30 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "enabled": true, 4 | "lockFileMaintenance": { 5 | "enabled": true, 6 | "automerge": true 7 | }, 8 | "git-submodules": { 9 | "enabled": true 10 | }, 11 | "packageRules": [ 12 | { 13 | "groupName": "all non-major Python dependencies", 14 | "groupSlug": "all-python-minor-patch", 15 | "matchDatasources": [ 16 | "pypi" 17 | ], 18 | "matchPackagePatterns": [ 19 | "*" 20 | ], 21 | "matchUpdateTypes": [ 22 | "minor", 23 | "patch" 24 | ] 25 | }, 26 | { 27 | "updateTypes": ["minor", "patch", "pin", "digest"], 28 | "automerge": true 29 | } 30 | ], 31 | "rangeStrategy": "bump", 32 | "schedule": "every weekend", 33 | "extends": [ 34 | ":autodetectPinVersions", 35 | ":combinePatchMinorReleases", 36 | ":dependencyDashboard", 37 | ":ignoreUnstable", 38 | ":prConcurrentLimitNone", 39 | ":prHourlyLimitNone", 40 | ":prImmediately", 41 | ":semanticPrefixFixDepsChoreOthers", 42 | ":separateMultipleMajorReleases", 43 | ":updateNotScheduled", 44 | "group:recommended" 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /tests/data/amazon.profile: -------------------------------------------------------------------------------- 1 | # 2 | # Amazon browsing traffic profile 3 | # 4 | # Author: @harmj0y 5 | # 6 | 7 | set sleeptime "5000"; 8 | set jitter "0"; 9 | set maxdns "255"; 10 | set useragent "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"; 11 | 12 | http-get { 13 | 14 | set uri "/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books"; 15 | 16 | client { 17 | 18 | header "Accept" "*/*"; 19 | header "Host" "www.amazon.com"; 20 | 21 | metadata { 22 | base64; 23 | prepend "session-token="; 24 | prepend "skin=noskin;"; 25 | append "csm-hit=s-24KU11BB82RZSYGJ3BDK|1419899012996"; 26 | header "Cookie"; 27 | } 28 | } 29 | 30 | server { 31 | 32 | header "Server" "Server"; 33 | header "x-amz-id-1" "THKUYEZKCKPGY5T42PZT"; 34 | header "x-amz-id-2" "a21yZ2xrNDNtdGRsa212bGV3YW85amZuZW9ydG5rZmRuZ2tmZGl4aHRvNDVpbgo="; 35 | header "X-Frame-Options" "SAMEORIGIN"; 36 | header "Content-Encoding" "gzip"; 37 | 38 | output { 39 | print; 40 | } 41 | } 42 | } 43 | 44 | http-post { 45 | 46 | set uri "/N4215/adj/amzn.us.sr.aps"; 47 | 48 | client { 49 | 50 | header "Accept" "*/*"; 51 | header "Content-Type" "text/xml"; 52 | header "X-Requested-With" "XMLHttpRequest"; 53 | header "Host" "www.amazon.com"; 54 | 55 | parameter "sz" "160x600"; 56 | parameter "oe" "oe=ISO-8859-1;"; 57 | 58 | id { 59 | parameter "sn"; 60 | } 61 | 62 | parameter "s" "3717"; 63 | parameter "dc_ref" "http%3A%2F%2Fwww.amazon.com"; 64 | 65 | output { 66 | base64; 67 | print; 68 | } 69 | } 70 | 71 | server { 72 | 73 | header "Server" "Server"; 74 | header "x-amz-id-1" "THK9YEZJCKPGY5T42OZT"; 75 | header "x-amz-id-2" "a21JZ1xrNDNtdGRsa219bGV3YW85amZuZW9zdG5rZmRuZ2tmZGl4aHRvNDVpbgo="; 76 | header "X-Frame-Options" "SAMEORIGIN"; 77 | header "x-ua-compatible" "IE=edge"; 78 | 79 | output { 80 | print; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /tests/data/bing_maps.profile: -------------------------------------------------------------------------------- 1 | #bing maps profile 2 | #xx0hcd 3 | 4 | ###Global Options### 5 | set sample_name "bing_maps.profile"; 6 | 7 | set sleeptime "38500"; 8 | set jitter "27"; 9 | set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"; 10 | 11 | set host_stage "false"; 12 | 13 | ###DNS options### 14 | set dns_idle "8.8.8.8"; 15 | set maxdns "245"; 16 | set dns_sleep "0"; 17 | set dns_stager_prepend ""; 18 | set dns_stager_subhost ""; 19 | set dns_max_txt "252"; 20 | set dns_ttl "1"; 21 | 22 | ###SMB options### 23 | set pipename "ntsvcs"; 24 | set pipename_stager "scerpc"; 25 | set smb_frame_header ""; 26 | 27 | ###TCP options### 28 | set tcp_port "8000"; 29 | set tcp_frame_header ""; 30 | 31 | ###SSH BANNER### 32 | set ssh_banner "Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-1065-aws x86_64)"; 33 | 34 | ###SSL Options### 35 | #https-certificate { 36 | # set keystore "domain001.store"; 37 | # set password "password123"; 38 | #} 39 | 40 | #code-signer { 41 | #set keystore "your_keystore.jks"; 42 | #set password "your_password"; 43 | #set alias "server"; 44 | #} 45 | 46 | ###HTTP-Config Block### 47 | #http-config { 48 | # set headers "Server, Content-Type"; 49 | # header "Content-Type" "text/html;charset=UTF-8"; 50 | # header "Server" "nginx"; 51 | # 52 | # set trust_x_forwarded_for "false"; 53 | #} 54 | 55 | ###HTTP-GET Block### 56 | http-get { 57 | 58 | set uri "/maps/overlaybfpr"; 59 | 60 | client { 61 | 62 | header "Host" "www.bing.com"; 63 | header "Accept" "*/*"; 64 | header "Accept-Language" "en-US,en;q=0.5"; 65 | header "Connection" "close"; 66 | 67 | 68 | metadata { 69 | base64; 70 | 71 | prepend "_SS="; 72 | prepend "SRCHD=AF=NOFORM;"; 73 | header "Cookie"; 74 | 75 | } 76 | 77 | parameter "q" "san%20diego%20ca%20zoo"; 78 | 79 | } 80 | 81 | server { 82 | 83 | header "Cache-Control" "public"; 84 | header "Content-Type" "text/html;charset=utf-8"; 85 | header "Vary" "Accept-Encoding"; 86 | header "P3P" "\"NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND\""; 87 | header "X-MSEdge-Ref" "Ref A: 20D7023F4A1946FEA6E17C00CC8216CF Ref B: DALEDGE0715"; 88 | header "Connection" "close"; 89 | 90 | output { 91 | 92 | base64; 93 | 94 | prepend "{ 95 | \"_type\": \"Suggestions\", 96 | \"instrumentation\": { 97 | \"pingUrlBase\": \"https://www.bing.com/api/ping?IG=22592B48742E48B7B855897EE3CA6400&CID=34823DAF741A65682A9032BA75E66427&ID=\", 98 | \"pageLoadPingUrl\": \"https://www.bing.com/api/ping/pageload?IG=22592B48742E48B7B855897EE3CA6400&CID=34823DAF741A65682A9032BA75E66427&Type=Event.CPT&DATA=0\" 99 | }, 100 | \"queryContext\": { 101 | \"originalQuery\": \"san diego ca zoo\" 102 | }, 103 | \"value\": [{ 104 | \"_type\": \"Place\", 105 | \"id\": \"sid:\""; 106 | 107 | 108 | 109 | 110 | 111 | append "\" 112 | \"readLink\": \"https://www.bing.com/api/v6/localentities/dbb1c326-5b67-4591-a264-0929e070e5ee\", 113 | \"readLinkPingSuffix\": \"DevEx,5018.1\", 114 | \"entityPresentationInfo\": { 115 | \"entityScenario\": \"ListItem\", 116 | \"entitySubTypeHints\": [\"PopulatedPlace\"] 117 | }, 118 | \"geo\": { 119 | \"latitude\": 32.7157, 120 | \"longitude\": -117.162 121 | }, 122 | \"address\": { 123 | \"addressLocality\": \"San Diego\", 124 | \"addressSubregion\": \"San Diego County\", 125 | \"addressRegion\": \"California\", 126 | \"addressCountry\": \"United States\", 127 | \"countryIso\": \"US\", 128 | \"text\": \"San Diego, California\" 129 | }, 130 | \"formattingRuleId\": \"US\" 131 | }, { 132 | \"_type\": \"LocalBusiness\", 133 | \"id\": \"local_ypid:\"YN873x13020856635161814\"\", 134 | \"readLink\": \"https://www.bing.com/api/v6/localbusinesses/YN873x13020856635161814\", 135 | \"readLinkPingSuffix\": \"DevEx,5019.1\", 136 | \"name\": \"San Diego Zoo\", 137 | \"geo\": { 138 | \"latitude\": 32.7353, 139 | \"longitude\": -117.149 140 | }, 141 | \"address\": { 142 | \"streetAddress\": \"2920 Zoo Dr\", 143 | \"addressLocality\": \"San Diego\", 144 | \"addressRegion\": \"CA\", 145 | \"postalCode\": \"92101\", 146 | \"addressCountry\": \"United States\", 147 | \"countryIso\": \"US\", 148 | \"text\": \"2920 Zoo Dr, San Diego, CA 92101\" 149 | }, 150 | \"formattingRuleId\": \"US\", 151 | \"categories\": [\"90000.90001.90012.90017\"] 152 | }, { 153 | \"_type\": \"Place\", 154 | \"id\": \"sid:\"63101d85-2568-910b-fee1-2518175b6a48\"\", 155 | \"readLink\": \"https://www.bing.com/api/v6/localentities/63101d85-2568-910b-fee1-2518175b6a48\", 156 | \"readLinkPingSuffix\": \"DevEx,5020.1\", 157 | \"entityPresentationInfo\": { 158 | \"entityScenario\": \"ListItem\", 159 | \"entitySubTypeHints\": [\"PopulatedPlace\"] 160 | }, 161 | \"geo\": { 162 | \"latitude\": 10.2573, 163 | \"longitude\": -67.9548 164 | }, 165 | \"address\": { 166 | \"addressLocality\": \"San Diego\", 167 | \"addressRegion\": \"Carabobo\", 168 | \"addressCountry\": \"Venezuela\", 169 | \"countryIso\": \"VE\", 170 | \"text\": \"San Diego, Carabobo\" 171 | }"; 172 | 173 | 174 | print; 175 | } 176 | } 177 | } 178 | 179 | 180 | 181 | ###HTTP-Post Block### 182 | http-post { 183 | 184 | set uri "/fd/ls/lsp.aspx"; 185 | #set verb "GET"; 186 | set verb "POST"; 187 | 188 | client { 189 | 190 | header "Host" "www.bing.com"; 191 | header "Accept" "*/*"; 192 | header "Accept-Language" "en-US"; 193 | header "Content-Type" "text/xml"; 194 | header "Connection" "close"; 195 | 196 | output { 197 | base64url; 198 | 199 | prepend "SRCHUID="; 200 | prepend "SRCHD=AF=NOFORM;"; 201 | header "Cookie"; 202 | } 203 | 204 | id { 205 | base64url; 206 | parameter "lid"; 207 | 208 | } 209 | } 210 | 211 | server { 212 | 213 | header "Cache-Control" "public, max-age=31536000"; 214 | header "Content-Type" "application/json"; 215 | header "Vary" "Accept-Encoding"; 216 | header "X-Cache" "TCO_HIT"; 217 | header "Server" "Microsoft-IIS/10.0"; 218 | header "X-AspNet-Version" "4.0.30319"; 219 | header "X-Powered-By" "ASP.NET"; 220 | 221 | output { 222 | netbios; 223 | 224 | prepend "{ 225 | \"categoryMap\": [ 226 | { 227 | \"categoryId\": 91263, 228 | \"bucketId\": 1848, 229 | \"entry\": \"CommunityPoint\" 230 | }, 231 | { 232 | \"categoryId\": 90892, 233 | \"bucketId\": 1899, 234 | \"entry\": \"Transit\" 235 | }, 236 | { 237 | \"categoryId\": 90014, 238 | \"bucketId\": 300, 239 | \"entry\": \"ZXlJeE5DSTZleUoyWldOMGIzSkpiV0ZuWlNJNmV5SnlaV052Y21SeklqcGJleUp6WTJGc1pWQmhiR1YwZEdWTFpYbEpaQ0k2TFRFc0luTm9ZWEJsVUdGc1pYUjBaVXRsZVVsa0lqb3RNU3dpWjJWdmJXVjBjbmxUZEhKcGJtY2lPaUpOTWk0Mk56Z3NNVEJvTFRVdU16VTFWall1TlROb0xUTXVNalFnSUdNdE1DNDVPREVzTUM0d01qSXRNUzQzTlMwd0xqTTVOQzB5TGpFNE1TMHhMakE1TW1NdE1DNHpNamN0TUM0MU16TXRNQzQxT0RNdE1TNDBORElzTUM0d056SXRNaTQzTld3d0xqRXpOeTB3TGpJek1Xd3hMalU0T1MweUxqSXlNaUFnWXkwd0xqSTFOUzB3TGpFNE15MHdMalEyTmkwd0xqUXhPQzB3TGpZeE9TMHdMamN3TVdNdE1DNDBOREV0TUM0NE1Ua3RNQzR6TFRFdU56ZzJMREF1TkRFNExUSXVPRGN6YkRFdU5qTTVMVEl1TXpJell5MHdMakF6TXkwd0xqQTBOaTB3TGpBMkxUQXVNRGc1TFRBdU1EZzBMVEF1TVRNZ0lHTXRNQzR5TlMwd0xqUXlNeTB3TGpVM01TMHhMak14TlN3d0xqQTVPUzB5TGpVek4yd3lMamN6T0MwMExqRTVPRU10TVM0M05TMHhNeTR5TnkweExqQXlPQzB4TkN3d0xqQXhPQzB4TkdNd0xqWXdPU3d3TERFdU5EYzRMREF1TWpVMExESXVNVFU0TERFdU5EVTViREl1T0RFM0xEUXVPRGNnSUdNd0xqRXhOU3d3TGpRNE1pd3dMakE1TXl3eExqRTNPUzB3TGpJNE1Td3hMamM1T0d3eExqZzBOU3d5TGpZek0yTXdMalExT1N3d0xqY3pOU3d3TGpjd09Dd3hMamMyTWl3d0xqRTVOU3d5TGpZNE0wTTJMall4Tmkwd0xqTXhNeXcyTGpReE1pMHdMakExTVN3MkxqRXdPU3d3TGpFM01pQWdiREl1TURFekxESXVOemMwUXpndU5EUTFMRE11TlRjeExEZ3VOakU0TERRdU5UUXNPQzR4TWpZc05TNHpOemhqTFRBdU1qUXpMREF1TkRFekxUQXVPRFExTERFdU1URXpMVEl1TVRVc01TNHhOVFJJTWk0Mk56aFdNVEI2SWl3aVptbHNiRlpoYkhWbFNXUWlPakkwTENKemRISnZhMlZXWVd4MVpVbGtJam94TENKemRISnZhMlZYYVdSMGFDSTZNU3dpYzNSeWIydGxVMk5oYkdWUVlXeGxkSFJsUzJWNVNXUWlPaTB4TENKeVpXTnZjbVJVZVhCbElqb2lVR0YwYUNKOQ==\" 240 | }, 241 | { 242 | \"categoryId\": 90595, 243 | \"bucketId\": 311, 244 | \"entry\": \"RealEstatePoint\" 245 | }, 246 | { 247 | \"categoryId\": 91616, 248 | \"bucketId\": 257, 249 | \"entry\": \"AquariumPoint\" 250 | }, 251 | { 252 | \"categoryId\": 90954, 253 | \"bucketId\": 277, 254 | \"entry\": \"ArtGalleryPoint\" 255 | }, 256 | { 257 | \"categoryId\": 90001, 258 | \"bucketId\": 258, 259 | \"entry\": \"UEhOamNtbHdkQ0IwZVhCbFBTSjBaWGgwTDJwaGRtRnpZM0pwY0hRaUlHTnliM056YjNKcFoybHVQU0poYm05dWVXMXZkWE1pSUhOeVl6MGlMM0p3TDBScWNrUjZOMU5ZYlhOMWRYZHhRMlI1WldsdlFsWXpPWGhKV1M1bmVpNXFjeUkrUEM5elkzSnBjSFErUEhOamNtbHdkQ0IwZVhCbFBTSjBaWGgwTDJwaGRtRnpZM0pwY0hRaVBnPT0=\" 260 | }, 261 | { 262 | \"categoryId\": 90133, 263 | \"bucketId\": 278, 264 | \"entry\": \"ATMPoint\" 265 | }, 266 | { 267 | \"categoryId\": 90078, 268 | \"bucketId\": 330, 269 | \"entry\": \"AutomobileRepairPoint\" 270 | }, 271 | { 272 | \"categoryId\": 91186, 273 | \"bucketId\": 327, 274 | \"entry\": \"FoodPoint\" 275 | }, 276 | { 277 | \"categoryId\": 90122, 278 | \"bucketId\": 279, 279 | \"entry\": \"BankPoint\" 280 | }, 281 | { 282 | \"categoryId\": 90243, 283 | \"bucketId\": 284, 284 | \"entry\": \"BarPoint\" 285 | }, 286 | { 287 | \"categoryId\": 91204, 288 | \"bucketId\": 308, 289 | \"entry\": \"BarAndGrillPoint\" 290 | }, 291 | { 292 | \"categoryId\": 91576, 293 | \"bucketId\": 1851, 294 | \"entry\": \"AttractionPoint\" 295 | }, 296 | { 297 | \"categoryId\": 90353, 298 | \"bucketId\": 1972, 299 | \"entry\": \"ZXlKelkyRnNaVkJoYkdWMGRHVkxaWGxKWkNJNkxURXNJbk5vWVhCbFVHRnNaWFIwWlV0bGVVbGtJam90TVN3aVoyVnZiV1YwY25sVGRISnBibWNpT2lKTkxUSXVNalUwTFRZdU16ZzNZekFzTUMweExqZzJPU3d3TGpNd015MHhMakE0T1MweExqRXhPR3d5TGpjME1TMDBMakU1TTJNd0xEQXNNQzQxTkMweExqTXlMREV1TWpnMExEQnNNaTQyTkRNc05DNDBNeUFnWXpBc01Dd3dMakl5TVN3d0xqa3hOQzB4TGpBMk9Dd3dMamc0TVd3eUxqZzVOQ3cwTGpFek1XTXdMREFzTUM0M056TXNNUzR5TlMwd0xqazFNU3d4TGpJMVNETXVNVEUzYkRNdU5EZ3lMRFF1TnpReVl6QXNNQ3d3TGpVME1pd3hMakEwTkMwd0xqWTNOU3d4TGpBNE1rZ3dMamsyTkhZekxqUTJPQ0FnYUMweExqa3lOM1l0TXk0ME4yZ3ROQzQ1TlRSak1Dd3dMVEV1TXpJc01DNHhNamN0TUM0MU56WXRNUzR6TmpGc015NHlNelV0TkM0MU1qWm9MVEV1TlRjM1l6QXNNQzB4TGpJeE55d3dMakUyTlMwd0xqSXpOUzB4TGpNeU0wd3RNaTR5TlRRdE5pNHpPRGNpTENKbWFXeHNWbUZzZFdWSlpDSTZNalVzSW5OMGNtOXJaVlpoYkhWbFNXUWlPakVzSW5OMGNtOXJaVmRwWkhSb0lqb3hMQ0p6ZEhKdmEyVlRZMkZzWlZCaGJHVjBkR1ZMWlhsSlpDSTZMVEVzSW5KbFkyOXlaRlI1Y0dVaU9pSlFZWFJvSW4wPQ==\" 300 | }, 301 | { 302 | \"categoryId\": 90940, 303 | \"bucketId\": 329, 304 | \"entry\": \"MarinaPoint\" 305 | }, 306 | { 307 | \"categoryId\": 90650, 308 | \"bucketId\": 1365, 309 | \"entry\": \"BookstorePoint\" 310 | }, 311 | { 312 | \"categoryId\": 91533, 313 | \"bucketId\": 271, 314 | \"entry\": \"BowlingPoint\" 315 | }, 316 | { 317 | \"categoryId\": 91647, 318 | \"bucketId\": 1382, 319 | \"entry\": \"ZXlJeU1EWWlPbnNpZG1WamRHOXlTVzFoWjJVaU9uc2ljbVZqYjNKa2N5STZXM3NpYzJOaGJHVlFZV3hsZEhSbFMyVjVTV1FpT2pFNU9Td2ljMmhoY0dWUVlXeGxkSFJsUzJWNVNXUWlPakl3TUN3aVoyVnZiV1YwY25sVGRISnBibWNpT2lKTk1USXVOUzA1YUMweU5TNHhZeTB4TGpjc01DMHpMakVzTVM0MExUTXVNU3d6TGpGV05TNDVZekFzTVM0M0xERXVOQ3d6TGpFc015NHhMRE11TVdneU5TNHhJQ0FnWXpFdU55d3dMRE11TVMweExqUXNNeTR4TFRNdU1WWXROUzQ1UXpFMUxqWXROeTQyTERFMExqSXRPU3d4TWk0MUxUbDZJQ0lzSW1acGJHeFdZV3gxWlVsa0lqb3lNU3dpYzNSeWIydGxWbUZzZFdWSlpDSTZNU3dpYzNSeWIydGxWMmxrZEdnaU9qRXNJbk4wY205clpWTmpZV3hsVUdGc1pYUjBaVXRsZVVsa0lqb3RNU3dpY21WamIzSmtWSGx3WlNJNklsQmhkR2dpZlE9PQ\" 320 | }, 321 | { 322 | \"categoryId\": 255, 323 | \"bucketId\": 254, 324 | \"entry\": \"Transit\" 325 | }, 326 | { 327 | \"categoryId\": 257, 328 | \"bucketId\": 253, 329 | \"entry\": \"Transit\" 330 | }, 331 | { 332 | \"categoryId\": 264, 333 | \"bucketId\": 243, 334 | \"entry\": \"Transit\" 335 | }, 336 | { 337 | \"categoryId\": 263, 338 | \"bucketId\": 241, 339 | \"entry\":"; 340 | 341 | 342 | 343 | 344 | 345 | append " }, 346 | { 347 | \"categoryId\": 266, 348 | \"bucketId\": 236, 349 | \"entry\": \"Transit\" 350 | }, 351 | { 352 | \"categoryId\": 251, 353 | \"bucketId\": 252, 354 | \"entry\": \"Transit\" 355 | }, 356 | { 357 | \"categoryId\": 265, 358 | \"bucketId\": 242, 359 | \"entry\": \"Transit\" 360 | }, 361 | { 362 | \"categoryId\": 253, 363 | \"bucketId\": 251, 364 | \"entry\": \"Transit\" 365 | }, 366 | { 367 | \"categoryId\": 254, 368 | \"bucketId\": 250, 369 | \"entry\": \"ZXlJek1DSTZleUoyWldOMGIzSkpiV0ZuWlNJNmV5SnlaV052Y21SeklqcGJleUp6WTJGc1pWQmhiR1YwZEdWTFpYbEpaQ0k2TkRJNUxDSnphR0Z3WlZCaGJHVjBkR1ZMWlhsSlpDSTZORE13TENKblpXOXRaWFJ5ZVZOMGNtbHVaeUk2SWsweE15MHdMakF4TkRZeE1ESTVZekFzTWk0eE9UZ3RNU3cwTGpFek1TMHlMalV4TWl3MUxqSTRNVU0zTGpjeU5pdzNMakUzTWpNNUxETXVOelUwTERjdU9UZzFNemtzTUN3M0xqazROVE01Y3kwM0xqY3lOaTB3TGpneE15MHhNQzQwT0RndE1pNDNNVGxETFRFeUxEUXVNVEUyTXprdE1UTXNNaTR4T0RNek9TMHhNeTB3TGpBeE5EWXhNREk1WXpBdE1pNHhPVGNzTVMwMExqRXpNaXd5TGpVeE1pMDFMakk0TVVNdE55NDNNall0Tnk0eU1EQTJNUzB6TGpjMU5DMDRMakF4TkRZeExEQXRPQzR3TVRRMk1YTTNMamN5Tml3d0xqZ3hOQ3d4TUM0ME9EZ3NNaTQzTVRrZ0lFTXhNaTAwTGpFME5qWXhMREV6TFRJdU1qRXhOakVzTVRNdE1DNHdNVFEyTVRBeU9Yb2lMQ0ptYVd4c1ZtRnNkV1ZKWkNJNk5URXNJbk4wY205clpWWmhiSFZsU1dRaU9qVXlMQ0p6ZEhKdmEyVlhhV1IwYUNJNk1Td2ljM1J5YjJ0bFUyTmhiR1ZRWVd4bGRIUmxTMlY1U1dRaU9pMHhMQ0p5WldOdmNtUlVlWEJsSWpvaVVHRjBhQ0o5TEhzaWMyTmhiR1ZRWVd4bGRIUmxTMlY1U1dRaU9qUXpNaXdpYzJoaGNHVlFZV3hsZEhSbFMyVjVTV1FpT2pRek15d2liR1ZtZEZSdmNDSTZleUo0SWpvdE9TNHpOekF4TENKNUlqb3RPQzR3T0RNd01EaDlMQ0p5YVdkb2RFSnZkSFJ2YlNJNmV5SjRJam94TUM0ek56QXhNeXdpZVNJNk9DNHdPRE13TURoOUxDSjBaWGgwVTNSNWJHVWlPbnNpWm05dWRFWmhiV2xzZVVsa0lqbzRMQ0ptYjI1MFUybDZaU0k2T1N3aWJXbHVhVzExYlVadmJuUlRhWHBsSWpvNUxDSm9aV2xuYUhSTllYUmphRTF2WkdVaU9qQXNJbWhsYVdkb2RFMWhkR05vVUdsNFpXeHpJam93TENKbWIyNTBVM1I1YkdVaU9qQXNJblJsZUhSRWNtRjNVMlYwZEdsdVozTWlPakFzSW1OdmJHOXlWbUZzZFdWSlpDSTZOVE1zSW1kc2IzZFRhWHBsSWpvekxDSnpaV052Ym1SSGJHOTNVMmw2WlNJNk9Td2lZV3h3YUdGR2JHOXZjaUk2TVRjMUxDSm5iRzkzUTI5c2IzSldZV3gxWlVsa0lqbzNMQ0p2ZFhSc2FXNWxRMjlzYjNKV1lXeDFaVWxrSWpvM0xDSnZkWFJzYVc1bFYybGtkR2dpT2pCOUxDSnpkSEpwYm1kVGIzVnlZMlZKWkNJNk5ETTBMQ0p6ZEhKcGJtZFRiM1Z5WTJWVWVYQmxJam95TENKb2IzSnBlbTl1ZEdGc1FXeHBaMjV0Wlc1MElqb3dMQ0oyWlhKMGFXTmhiRUZzYVdkdWJXVnVkQ0k2TUN3aWFHOXlhWHB2Ym5SaGJFRjFkRzlUWTJGc2FXNW5Jam94TENKMlpYSjBhV05oYkVGMWRHOVRZMkZzYVc1bklqb3hMQ0p5WldOdmNtUlVlWEJsSWpvaVZHVjRkQ0o5WFgxOWZRPT0=\" 370 | }, 371 | { 372 | \"categoryId\": 260, 373 | \"bucketId\": 229, 374 | \"entry\": \"Transit\" 375 | }, 376 | { 377 | \"categoryId\": 267, 378 | \"bucketId\": 226, 379 | \"entry\": \"Transit\" 380 | }, 381 | { 382 | \"categoryId\": 252, 383 | \"bucketId\": 249, 384 | \"entry\": \"Transit\" 385 | }, 386 | { 387 | \"categoryId\": 91714, 388 | \"bucketId\": 66, 389 | \"entry\": \"FinancialPoint\" 390 | }, 391 | { 392 | \"categoryId\": 203, 393 | \"bucketId\": 248, 394 | \"entry\": \"ZXlJek16TWlPbnNpZG1WamRHOXlTVzFoWjJVaU9uc2ljbVZqYjNKa2N5STZXM3NpYzJOaGJHVlFZV3hsZEhSbFMyVjVTV1FpT2pFNU9Td2ljMmhoY0dWUVlXeGxkSFJsUzJWNVNXUWlPakl3TUN3aVoyVnZiV1YwY25sVGRISnBibWNpT2lKTk5TNDVMVGxJTFRVdU9VTXROeTQyTFRrdE9TMDNMall0T1MwMUxqbFdOUzQ1UXkwNUxEY3VOaTAzTGpZc09TMDFMamtzT1VnMUxqbEROeTQyTERrc09TdzNMallzT1N3MUxqbFdMVFV1T1NBZ0lFTTVMVGN1Tml3M0xqWXRPU3cxTGprdE9VdzFMamt0T1hvZ0lpd2labWxzYkZaaGJIVmxTV1FpT2pJeExDSnpkSEp2YTJWV1lXeDFaVWxrSWpveExDSnpkSEp2YTJWWGFXUjBhQ0k2TVN3aWMzUnliMnRsVTJOaGJHVlFZV3hsZEhSbFMyVjVTV1FpT2kweExDSnlaV052Y21SVWVYQmxJam9pVUdGMGFDSjlMSHNpYzJOaGJHVlFZV3hsZEhSbFMyVjVTV1FpT2pJd01pd2ljMmhoY0dWUVlXeGxkSFJsUzJWNVNXUWlPakl3TUN3aVoyVnZiV1YwY25sVGRISnBibWNpT2lKTkxUY3VOeXcxTGpsak1Dd3hMREF1T0N3eExqZ3NNUzQ0TERFdU9FZzFMamxqTVN3d0xERXVPQzB3TGpnc01TNDRMVEV1T0ZZdE5TNDVZekF0TVMwd0xqZ3RNUzQ0TFRFdU9DMHhMamhJTFRVdU9TQWdJQ0JqTFRFc01DMHhMamdzTUM0NExURXVPQ3d4TGpoV05TNDVlaUFnSWl3aVptbHNiRlpoYkhWbFNXUWlPakl5TENKemRISnZhMlZXWVd4MVpVbGtJam94TENKemRISnZhMlZYYVdSMGFDSTZNU3dpYzNSeWIydGxVMk5oYkdWUVlXeGxkSFJsUzJWNVNXUWlPaTB4TENKeVpXTnZjbVJVZVhCbElqb2lVR0YwYUNKOUxIc2ljMk5oYkdWUVlXeGxkSFJsUzJWNVNXUWlPakl3TkN3aWMyaGhjR1ZRWVd4bGRIUmxTMlY1U1dRaU9qSXdOU3dpWjJWdmJXVjBjbmxUZEhKcGJtY2lPaUpOTWk0MUxEWXVNMmd5TGpOTU1pNDJMRE11Tm1Nd0xqWXRNQzR4TERFdE1DNHpMREV0TUM0NFl6QXNNQ3d3TFRJdU1Td3dMakV0TXk0Mll6QXVNUzB4TGpjc01DMHlMaklzTUMweUxqSkRNeTQzTFRNdU55d3pMakl0TkM0eUxESXVOQzAwTGpJZ0lDQm9MVEoyTFRFdU1XZ3lMakYyTFRBdU9XZ3ROUzR6ZGpBdU9XZ3lMakYyTVM0eGFDMHhMamxqTFRBdU9Dd3dMVEV1TWl3d0xqVXRNUzQwTERFdU1tTXdMREFzTUN3d0xqY3NNQ3d5TGpKak1DNHhMREV1Tml3d0xqRXNNeTQxTERBdU1Td3pMalZqTUN3d0xqWXNNQzQxTERBdU9Td3hMakVzTUM0NUlDQWdiQzB5TGpJc01pNDJhREl1TTJ3eExqUXRNaTQyYURJdU1rd3lMalVzTmk0emVpQk5NaTQxTERJdU1XTXdMREF1TkMwd0xqTXNNQzQzTFRBdU55d3dMamRETVM0MExESXVPQ3d4TERJdU5Dd3hMREl1TVhNd0xqTXRNQzQzTERBdU55MHdMamRETWk0eExERXVNeXd5TGpVc01TNDNMREl1TlN3eUxqRjZJQ0FnSUUwdE1pNDBMVEl1TldNd0xUQXVNaXd3TGpJdE1DNDBMREF1TkMwd0xqUm9OR013TGpJc01Dd3dMalFzTUM0eUxEQXVOQ3d3TGpSMk15NHhhQzAwTGpoRExUSXVOQ3d3TGpZdE1pNDBMVEl1TlMweUxqUXRNaTQxZWlCTkxURXVOeXd4TGpORExURXVNeXd4TGpNdE1Td3hMamN0TVN3eUxqRWdJQ0J6TFRBdU15d3dMamN0TUM0M0xEQXVOMk10TUM0MExEQXRNQzQzTFRBdU15MHdMamN0TUM0M1F5MHlMalVzTVM0M0xUSXVNU3d4TGpNdE1TNDNMREV1TTNvZ0lpd2labWxzYkZaaGJIVmxTV1FpT2pJekxDSnpkSEp2YTJWV1lXeDFaVWxrSWpveExDSnpkSEp2YTJWWGFXUjBhQ0k2TVN3aWMzUnliMnRsVTJOaGJHVlFZV3hsZEhSbFMyVjVTV1FpT2kweExDSnlaV052Y21SVWVYQmxJam9pVUdGMGFDSjlYWDE5ZlE9PQ==\" 395 | }, 396 | { 397 | \"categoryId\": 91754, 398 | \"bucketId\": 65, 399 | \"entry\": \"Transit\" 400 | }, 401 | { 402 | \"categoryId\": 205, 403 | \"bucketId\": 247, 404 | \"entry\": \"Transit\" 405 | }, 406 | { 407 | \"categoryId\": 91649, 408 | \"bucketId\": 281, 409 | \"entry\": \"CafePoint\" 410 | }, 411 | { 412 | \"categoryId\": 91562, 413 | \"bucketId\": 1366, 414 | \"entry\": \"CampPoint\" 415 | }, 416 | { 417 | \"categoryId\": 90977, 418 | \"bucketId\": 331, 419 | \"entry\": \"\" 420 | }, 421 | { 422 | \"categoryId\": 90903, 423 | \"bucketId\": 274, 424 | \"entry\": \"AutomobileRentalPoint\" 425 | }, 426 | { 427 | \"categoryId\": 90024, 428 | \"bucketId\": 303, 429 | \"entry\": \"CasinoPoint\" 430 | }, 431 | { 432 | \"categoryId\": 91622, 433 | \"bucketId\": 1839, 434 | \"entry\": \"AttractionPoint\" 435 | }, 436 | { 437 | \"categoryId\": 91252, 438 | \"bucketId\": 1846, 439 | \"entry\": \"PalacePoint\" 440 | }, 441 | { 442 | \"categoryId\": 90619, 443 | \"bucketId\": 1847, 444 | \"entry\": \"ZXlJek5qTWlPbnNpZG1WamRHOXlTVzFoWjJVaU9uc2ljbVZqYjNKa2N5STZXM3NpYzJOaGJHVlFZV3hsZEhSbFMyVjVTV1FpT2pFek5EZ3NJbk5vWVhCbFVHRnNaWFIwWlV0bGVVbGtJam94TXpRNUxDSmpXQ0k2TUN3aVkxa2lPakFzSW5KWUlqb3dMQ0p5V1NJNk1Dd2lZMjlzYjNKV1lXeDFaVWxrSWpveU56Y3NJbXh2WTJ0WFNGSmhkR2x2SWpwMGNuVmxMQ0p5WldOdmNtUlVlWEJsSWpvaVJtbHNiR1ZrUld4c2FYQnpaU0o5TEhzaWMyTmhiR1ZRWVd4bGRIUmxTMlY1U1dRaU9qRXpORGdzSW5Ob1lYQmxVR0ZzWlhSMFpVdGxlVWxrSWpveE16UTVMQ0pqV0NJNk1Dd2lZMWtpT2pBc0luSllJam93TENKeVdTSTZNQ3dpYkdsdVpWTjBlV3hsSWpwN0ltTnZiRzl5Vm1Gc2RXVkpaQ0k2TWpjNExDSnpkSEp2YTJWWGFXUjBhQ0k2TVN3aVpHRnphR1Z6VEdsemRDSTZXMTBzSW1OdmJYQnZkVzVrUVhKeVlYbE1hWE4wSWpwYlhYMHNJbXh2WTJ0WFNGSmhkR2x2SWpwMGNuVmxMQ0p6ZEhKdmEyVlRZMkZzWlZCaGJHVjBkR1ZMWlhsSlpDSTZNVE0xTVN3aWNtVmpiM0prVkhsd1pTSTZJa1ZzYkdsd2MyVWlmU3g3SW5OallXeGxVR0ZzWlhSMFpVdGxlVWxrSWpveE16VXpMQ0p6YUdGd1pWQmhiR1YwZEdWTFpYbEpaQ0k2TVRNMU5Dd2laMlZ2YldWMGNubFRkSEpwYm1jaU9pSk5OQzQwTFRNdU5tTXdMakl0TUM0eUxEQXVNaTB3TGpVc01DMHdMamRqTFRBdU1pMHdMakl0TUM0MUxUQXVNaTB3TGpjc01Fd3dMamd0TVM0MWFERXVORU15TGpJdE1TNDFMRFF1TkMwekxqWXNOQzQwTFRNdU5ub2dUVFF0TUM0MWFDMDRJQ0JqTFRBdU15d3dMVEF1TlN3d0xqSXRNQzQxTERBdU5XTXdMREl1TlN3eUxEUXVOU3cwTGpVc05DNDFjelF1TlMweUxEUXVOUzAwTGpWRE5DNDFMVEF1TXl3MExqTXRNQzQxTERRdE1DNDFlaUJOTVN3eUxqVklNQzQxVmpOak1Dd3dMak10TUM0eUxEQXVOUzB3TGpVc01DNDFJQ0JUTFRBdU5Td3pMak10TUM0MUxETldNaTQxU0MweFl5MHdMak1zTUMwd0xqVXRNQzR5TFRBdU5TMHdMalZUTFRFdU15d3hMalV0TVN3eExqVm9NQzQxVmpGak1DMHdMak1zTUM0eUxUQXVOU3d3TGpVdE1DNDFVekF1TlN3d0xqY3NNQzQxTERGMk1DNDFTREVnSUdNd0xqTXNNQ3d3TGpVc01DNHlMREF1TlN3d0xqVlRNUzR6TERJdU5Td3hMREl1TlhvaUxDSm1hV3hzVm1Gc2RXVkpaQ0k2TWpjNUxDSnpkSEp2YTJWV1lXeDFaVWxrSWpveExDSnpkSEp2YTJWWGFXUjBhQ0k2TVN3aWMzUnliMnRsVTJOaGJHVlFZV3hsZEhSbFMyVjVTV1FpT2kweExDSnlaV052Y21SVWVYQmxJam9pVUdGMGFDSjlYWDE5ZlE9PQ===\" 445 | }, 446 | { 447 | \"categoryId\": 91703, 448 | \"bucketId\": 1849, 449 | \"entry\": \"CommunityPoint\" 450 | }, 451 | { 452 | \"categoryId\": 90386, 453 | \"bucketId\": 1367, 454 | \"entry\": \"ClinicPoint\" 455 | }, 456 | { 457 | \"categoryId\": 90188, 458 | \"bucketId\": 295, 459 | \"entry\": \"EducationPoint\" 460 | }, 461 | { 462 | \"categoryId\": 90584, 463 | \"bucketId\": 310, 464 | \"entry\": \"CommunityPoint\" 465 | }"; 466 | 467 | print; 468 | } 469 | } 470 | } 471 | 472 | 473 | 474 | ###HTTP-Stager Block### 475 | http-stager { 476 | set uri_x86 "/maps/overlayBFPR"; 477 | set uri_x64 "/maps/overlayBfpr"; 478 | 479 | client { 480 | 481 | header "Host" "www.bing.com"; 482 | header "Accept" "*/*"; 483 | header "Accept-Language" "en-US,en;q=0.5"; 484 | header "Connection" "close"; 485 | } 486 | 487 | server { 488 | 489 | header "Cache-Control" "public"; 490 | header "Content-Type" "text/html;charset=utf-8"; 491 | header "Vary" "Accept-Encoding"; 492 | header "P3P" "\"NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND\""; 493 | header "X-MSEdge-Ref" "Ref A: 20D7023F5A1946FFA6E18C00CC8216CF Ref B: DALEDGE0815"; 494 | header "Connection" "close"; 495 | 496 | output { 497 | 498 | print; 499 | } 500 | } 501 | } 502 | 503 | 504 | ###Malleable PE/Stage Block### 505 | stage { 506 | set checksum "0"; 507 | set compile_time "12 Dec 2019 02:52:11"; 508 | set entry_point "170000"; 509 | #set image_size_x86 "6586368"; 510 | #set image_size_x64 "6586368"; 511 | #set name "WWanMM.dll"; 512 | set userwx "false"; 513 | set cleanup "true"; 514 | set sleep_mask "true"; 515 | set stomppe "true"; 516 | set obfuscate "true"; 517 | set rich_header ""; 518 | 519 | set sleep_mask "true"; 520 | 521 | set smartinject "true"; 522 | 523 | set module_x86 "wwanmm.dll"; 524 | set module_x64 "wwanmm.dll"; 525 | 526 | transform-x86 { 527 | prepend "\x90\x90\x90"; 528 | strrep "ReflectiveLoader" ""; 529 | strrep "beacon.dll" ""; 530 | } 531 | 532 | transform-x64 { 533 | prepend "\x90\x90\x90"; 534 | strrep "ReflectiveLoader" ""; 535 | strrep "beacon.x64.dll" ""; 536 | } 537 | 538 | #string "something"; 539 | #data "something"; 540 | #stringw "something"; 541 | } 542 | 543 | ###Process Inject Block### 544 | process-inject { 545 | 546 | set allocator "NtMapViewOfSection"; 547 | 548 | set min_alloc "16700"; 549 | 550 | set userwx "false"; 551 | 552 | set startrwx "true"; 553 | 554 | transform-x86 { 555 | prepend "\x90\x90\x90"; 556 | } 557 | transform-x64 { 558 | prepend "\x90\x90\x90"; 559 | } 560 | 561 | execute { 562 | #CreateThread; 563 | #CreateRemoteThread; 564 | 565 | CreateThread "ntdll.dll!RtlUserThreadStart+0x1000"; 566 | 567 | SetThreadContext; 568 | 569 | NtQueueApcThread-s; 570 | 571 | #NtQueueApcThread; 572 | 573 | CreateRemoteThread "kernel32.dll!LoadLibraryA+0x1000"; 574 | 575 | RtlCreateUserThread; 576 | } 577 | } 578 | 579 | ###Post-Ex Block### 580 | post-ex { 581 | 582 | set spawnto_x86 "%windir%\\syswow64\\gpupdate.exe"; 583 | set spawnto_x64 "%windir%\\sysnative\\gpupdate.exe"; 584 | 585 | set obfuscate "true"; 586 | 587 | set smartinject "true"; 588 | 589 | set amsi_disable "true"; 590 | 591 | } 592 | -------------------------------------------------------------------------------- /tests/data/mayoclinic.profile: -------------------------------------------------------------------------------- 1 | #mayoclinic profile 2 | #xx0hcd 3 | 4 | set sleeptime "37000"; 5 | set jitter "25"; 6 | set useragent "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"; 7 | set dns_idle "8.8.8.8"; 8 | set maxdns "245"; 9 | 10 | set sample_name "mayoclinic.profile"; 11 | 12 | #https-certificate { 13 | # set keystore "keystore.store"; 14 | # set password "password"; 15 | #} 16 | 17 | http-config { 18 | set headers "Content-Type, Connection, Server, Link, X-Cache"; 19 | header "Content-Type" "text/html;charset=UTF-8"; 20 | header "Connection" "close"; 21 | header "Server" "nginx"; 22 | header "X-Powered-By" "PHP/7.0.33"; 23 | header "Link" "; rel=\"https://api.w.org/\""; 24 | set trust_x_forwarded_for "false"; 25 | } 26 | 27 | http-get { 28 | 29 | set uri "/discussion/mayo-clinic-radio-als/ /discussion/ /hubcap/mayo-clinic-radio-full-shows/ /category/research-2/"; 30 | 31 | client { 32 | 33 | header "Host" "www.mayomedical.com"; 34 | header "Accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; 35 | header "Accept-Language" "en-US,en;q=0.5"; 36 | header "Connection" "close"; 37 | 38 | parameter "permalink" "https://www.mayoclinic.org"; 39 | 40 | metadata { 41 | netbios; 42 | parameter "id"; 43 | 44 | } 45 | 46 | } 47 | 48 | server { 49 | 50 | output { 51 | 52 | base64; 53 | 54 | prepend "type=\"text/javascript\">(window.NREUM||(NREUM={})).loader_config={xpid:"; 55 | prepend "\n"; 57 | prepend " \n"; 58 | prepend "\n"; 59 | prepend "\n"; 60 | 61 | append "};window.NREUM||(NREUM={}),__nr_require=function(t,n,e){function r(e){if(!n[e]){var o=n[e]={exports:{}};t[e][0].call(o.exports,function(n){var o=t[e][1][n];return r(o||n)},o,o.exports)}return n[e].exports}if(\"function\"==typeof __nr_require)return __nr_require;for(var o=0;o\n"; 63 | append "\n"; 64 | append "\n"; 65 | append "\n"; 66 | append "Research – Mayo Clinic News Network\n"; 67 | append "\n"; 68 | append ""; 69 | print; 70 | } 71 | } 72 | } 73 | 74 | http-post { 75 | 76 | set uri "/archive/ /bloglist/ /secondary-archive/ "; 77 | set verb "GET"; 78 | 79 | client { 80 | 81 | header "Host" "www.mayomedical.com"; 82 | header "Accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; 83 | header "Accept-Language" "en-US,en;q=0.5"; 84 | header "Connection" "close"; 85 | 86 | output { 87 | base64url; 88 | parameter "permalink"; 89 | } 90 | 91 | 92 | id { 93 | netbios; 94 | parameter "id"; 95 | 96 | } 97 | } 98 | 99 | server { 100 | 101 | output { 102 | base64; 103 | 104 | prepend "type=\"text/javascript\">(window.NREUM||(NREUM={})).loader_config={xpid:"; 105 | prepend "\n"; 107 | prepend " \n"; 108 | prepend "\n"; 109 | prepend "\n"; 110 | 111 | append "\"VgYBUVZWDRAJXVlTAQUAVw==\"};window.NREUM||(NREUM={}),__nr_require=function(t,n,e){function r(e){if(!n[e]){var o=n[e]={exports:{}};t[e][0].call(o.exports,function(n){var o=t[e][1][n];return r(o||n)},o,o.exports)}return n[e].exports}if(\"function\"==typeof __nr_require)return __nr_require;for(var o=0;o\n"; 113 | append "\n"; 114 | append "\n"; 115 | append "\n"; 116 | append "Research – Mayo Clinic News Network\n"; 117 | append "\n"; 118 | append ""; 119 | print; 120 | } 121 | } 122 | } 123 | 124 | http-stager { 125 | 126 | set uri_x86 "/tag/"; 127 | set uri_x64 "/Category/"; 128 | 129 | client { 130 | header "Host" "www.mayomedical.com"; 131 | header "Accept" "*/*"; 132 | header "Accept-Language" "en-US"; 133 | header "Connection" "close"; 134 | } 135 | 136 | server { 137 | 138 | } 139 | 140 | 141 | } 142 | 143 | ###Malleable PE Options### 144 | #always test spawnto and module stomp before using. My examples tested on Windows 10 Pro. 145 | 146 | post-ex { 147 | 148 | set spawnto_x86 "%windir%\\syswow64\\gpupdate.exe"; 149 | set spawnto_x64 "%windir%\\sysnative\\gpupdate.exe"; 150 | 151 | set obfuscate "true"; 152 | 153 | set smartinject "true"; 154 | 155 | set amsi_disable "true"; 156 | 157 | } 158 | 159 | #used peclone on wwanmm.dll. 160 | #don't use 'set image_size_xx' if using 'set module_xx' 161 | stage { 162 | set checksum "0"; 163 | set compile_time "25 Oct 2016 01:57:23"; 164 | set entry_point "170000"; 165 | # set image_size_x86 "6586368"; 166 | # set image_size_x64 "6586368"; 167 | # set name "WWanMM.dll"; 168 | set userwx "false"; 169 | set cleanup "true"; 170 | set sleep_mask "true"; 171 | set stomppe "true"; 172 | set obfuscate "true"; 173 | set rich_header "\xee\x50\x19\xcf\xaa\x31\x77\x9c\xaa\x31\x77\x9c\xaa\x31\x77\x9c\xa3\x49\xe4\x9c\x84\x31\x77\x9c\x1e\xad\x86\x9c\xae\x31\x77\x9c\x1e\xad\x85\x9c\xa7\x31\x77\x9c\xaa\x31\x76\x9c\x08\x31\x77\x9c\x1e\xad\x98\x9c\xa3\x31\x77\x9c\x1e\xad\x84\x9c\x98\x31\x77\x9c\x1e\xad\x99\x9c\xab\x31\x77\x9c\x1e\xad\x80\x9c\x6d\x31\x77\x9c\x1e\xad\x9a\x9c\xab\x31\x77\x9c\x1e\xad\x87\x9c\xab\x31\x77\x9c\x52\x69\x63\x68\xaa\x31\x77\x9c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; 174 | 175 | 176 | #module stomp 177 | 178 | set module_x86 "wwanmm.dll"; 179 | set module_x64 "wwanmm.dll"; 180 | 181 | transform-x86 { 182 | prepend "\x90\x90\x90"; 183 | strrep "ReflectiveLoader" ""; 184 | strrep "beacon.dll" ""; 185 | } 186 | 187 | transform-x64 { 188 | prepend "\x90\x90\x90"; 189 | strrep "ReflectiveLoader" ""; 190 | strrep "beacon.x64.dll" ""; 191 | } 192 | } 193 | process-inject { 194 | 195 | set allocator "NtMapViewOfSection"; 196 | 197 | set min_alloc "16700"; 198 | 199 | set userwx "false"; 200 | 201 | set startrwx "true"; 202 | 203 | transform-x86 { 204 | prepend "\x90\x90\x90"; 205 | } 206 | transform-x64 { 207 | prepend "\x90\x90\x90"; 208 | } 209 | 210 | execute { 211 | CreateThread "ntdll!RtlUserThreadStart"; 212 | CreateThread; 213 | NtQueueApcThread; 214 | CreateRemoteThread; 215 | RtlCreateUserThread; 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /tests/mpp/options/test_option.py: -------------------------------------------------------------------------------- 1 | """Testing: mpp.options.option 2 | """ 3 | from typing import Any, Set 4 | 5 | import pytest 6 | 7 | from mpp.constants import GLOBAL_OPTIONS, HTTP_OPTIONS 8 | from mpp.options.option import Option 9 | 10 | @pytest.mark.parametrize( 11 | "option,value,valid_options", 12 | [ 13 | ("jitter", 0, GLOBAL_OPTIONS), 14 | ("uri", "/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books", HTTP_OPTIONS) 15 | ] 16 | ) 17 | def test_option(option: str, value: Any, valid_options: Set): 18 | """Test Option Class 19 | 20 | Args: 21 | option: _description_ 22 | value: _description_ 23 | valid_options: _description_ 24 | """ 25 | assert Option(option=option, value=value).validate(valid_options=valid_options) 26 | -------------------------------------------------------------------------------- /tests/mpp/statements/test_statement.py: -------------------------------------------------------------------------------- 1 | """Testing: mpp.statements.statement 2 | """ 3 | from typing import Any, Set 4 | import pytest 5 | 6 | from mpp.constants import STATEMENTS 7 | from mpp.statements.statement import Statement, HeaderParameter, StringReplace 8 | 9 | 10 | @pytest.mark.parametrize( 11 | "statement,value,valid_statements", 12 | [ 13 | ("print", "", STATEMENTS), 14 | ("prepend", "skin=noskin;", STATEMENTS) 15 | ] 16 | ) 17 | def test_statement(statement: str, value: Any, valid_statements: Set): 18 | """Test statement Class 19 | 20 | Args: 21 | statement: _description_ 22 | value: _description_ 23 | valid_statements: _description_ 24 | """ 25 | assert Statement(statement=statement, value=value).validate(valid_statements=valid_statements) 26 | 27 | 28 | @pytest.mark.parametrize( 29 | "statement,key,value,valid_statements", 30 | [ 31 | ("header", "Accept", "*/*", STATEMENTS), 32 | ("parameter", "oe", "oe=ISO-8859-1;", STATEMENTS) 33 | ] 34 | ) 35 | def test_statement_header_parameter( 36 | statement: str, 37 | key: str, 38 | value: Any, 39 | valid_statements: Set 40 | ): 41 | """Test HeaderParameter Child Statement Class 42 | 43 | Args: 44 | statement: _description_ 45 | key: _description_ 46 | value: _description_ 47 | valid_statements: _description_ 48 | """ 49 | assert HeaderParameter( 50 | statement=statement, 51 | key=key, 52 | value=value 53 | ).validate(valid_statements=valid_statements) 54 | 55 | 56 | @pytest.mark.parametrize( 57 | "statement,string,replace,valid_statements", 58 | [ 59 | ("strrep", "ReflectiveLoader", "", STATEMENTS) 60 | ] 61 | ) 62 | def test_statement_string_replace( 63 | statement: str, 64 | string: str, 65 | replace: Any, 66 | valid_statements: Set 67 | ): 68 | """Test StringReplace Child Statement Class 69 | 70 | Args: 71 | statement: _description_ 72 | string: _description_ 73 | value: _description_ 74 | valid_statements: _description_ 75 | """ 76 | assert StringReplace( 77 | statement=statement, 78 | string=string, 79 | replace=replace 80 | ).validate(valid_statements=valid_statements) 81 | -------------------------------------------------------------------------------- /tests/mpp/test_profile.py: -------------------------------------------------------------------------------- 1 | """ Testing: mpp.profile 2 | """ 3 | from typing import Dict 4 | 5 | import git 6 | import pytest 7 | 8 | from mpp.profile import MalleableProfile, get_attr_recursively 9 | 10 | 11 | path = f'{git.Repo(__file__, search_parent_directories=True).working_tree_dir}/tests/data/' 12 | 13 | 14 | @pytest.mark.parametrize( 15 | "profile,mapping", 16 | [ 17 | ( 18 | 'amazon.profile', 19 | { 20 | 'jitter.value': '0', 21 | 'http_get.uri.value': '/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books', 22 | 'http_get.client.Host.value': 'www.amazon.com', 23 | 'http_get.client.Accept.value': '*/*', 24 | 'http_post.client.Accept.value': '*/*', 25 | 'http_post.client.dc_ref.value': 'http%3A%2F%2Fwww.amazon.com', 26 | 'http_post.server.X_Frame_Options.value': 'SAMEORIGIN' 27 | }, 28 | ), 29 | ( 30 | 'bing_maps.profile', 31 | { 32 | 'sleeptime.value': '38500', 33 | 'http_get.client.metadata.base64.value': '' 34 | } 35 | ), 36 | ( 37 | 'mayoclinic.profile', 38 | { 39 | 'useragent.value': 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko', 40 | 'http_config.headers.value': 'Content-Type, Connection, Server, Link, X-Cache', 41 | 'http_config.Link.value': "; rel=\\\"https://api.w.org/\\\"", 42 | 'http_get.uri.value': '/discussion/mayo-clinic-radio-als/ /discussion/ /hubcap/mayo-clinic-radio-full-shows/ /category/research-2/', 43 | 'http_get.client.Accept.value': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 44 | 'stage.transform_x86.ReflectiveLoader.replace': '' 45 | } 46 | ) 47 | ] 48 | ) 49 | def test_profile_parsing_from_file(profile: str, mapping: Dict): 50 | """Test profile parsing from files 51 | 52 | Args: 53 | profile: Malleable Profile filename 54 | mapping: Mapping of expected keys and values 55 | """ 56 | profile = MalleableProfile.from_file(filename=path + profile) 57 | for attribute, value in mapping.items(): 58 | assert get_attr_recursively( 59 | profile=profile, 60 | attribute=attribute 61 | ) == value 62 | assert profile.validate() 63 | --------------------------------------------------------------------------------