├── SG
├── __init__.py
└── BFSG.py
├── img
└── BFSG.gif
├── .editorconfig
├── tests
├── __init__.py
└── test_brute_froce_string_generator.py
├── Pipfile
├── setup.py
├── .github
└── dependabot.yml
├── LICENSE
├── .gitignore
├── README.md
└── Pipfile.lock
/SG/__init__.py:
--------------------------------------------------------------------------------
1 | from SG.BFSG import BruteForceStringGenerator
2 |
--------------------------------------------------------------------------------
/img/BFSG.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yezz123-Archive/BFSG/HEAD/img/BFSG.gif
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 4
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = false
9 | insert_final_newline = false
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 |
4 | def run_test():
5 | test_loader = unittest.TestLoader()
6 | test_suite = test_loader.discover('tests/', pattern='test_*.py')
7 | return test_suite
8 |
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.python.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [packages]
7 | mypy = "*"
8 |
9 | [dev-packages]
10 | pytest = "*"
11 | mypy = "*"
12 |
13 | [requires]
14 | python_version = "3.8.5"
15 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 |
3 | with open("README.md", "r") as fh:
4 | long_description = fh.read()
5 |
6 | setuptools.setup(
7 | name="BFSG",
8 | version="1.0",
9 | author="Yezz123",
10 | author_email="yasserth19@protonmail.com",
11 | description="String bruteforce generator",
12 | long_description=long_description,
13 | packages=setuptools.find_packages(),
14 | install_requires=[
15 | ],
16 | )
17 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "pip" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "daily"
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Collector
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 |
--------------------------------------------------------------------------------
/.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 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
106 |
107 | .idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | ## BFSG 🌙
15 |
16 | BFSG is a web BruteForce String generator written in [Python](https://www.python.org/)
17 |
18 | ## How i can start using BFSG 😎
19 |
20 | - First check that you have a python version 3.8.5 or update it from [Python Update](https://www.python.org/downloads/)
21 |
22 | ### Installation 🤘
23 |
24 | ```
25 | git clone https://github.com/yezz123/BFSG.git
26 |
27 | Cd BFSG
28 | ```
29 | ### Usage 😁
30 |
31 | - Development prerequisites
32 |
33 | ```
34 | pipenv install
35 | ```
36 |
37 | - Production prerequisites
38 |
39 | ```
40 | pipenv install --dev
41 | ```
42 |
43 | - To activate project's virtualenv run:
44 | ```
45 | pipenv shell
46 | ```
47 | ### Running the tests 🥱
48 |
49 | ```
50 | cd BFSG
51 |
52 | mypy BFSG.py
53 |
54 | pytest
55 | ```
56 | ## Contributing ⭐
57 |
58 | Contributions are welcome! ❤ Please share any features, and add unit tests! Use the pull request and issue systems to contribute.
59 |
60 | ## Credits & Thanks 🏆
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/SG/BFSG.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 | import string
3 | from enum import IntEnum
4 |
5 |
6 | class Direction(IntEnum):
7 | LEFT = 0
8 | RIGHT = -1
9 |
10 |
11 | class BruteForceStringGenerator:
12 |
13 | def __init__(self, sequence: str = '', chars: str = string.ascii_lowercase, direction: Direction = Direction.RIGHT,
14 | min_length: int = 1, max_length: int = 0) -> None:
15 |
16 | self.sequence = sequence
17 | self._sequence_list = list(sequence)
18 | self.chars = chars
19 | self.dir = direction
20 | self.min_length = max(0, min_length)
21 | self.max_length = max(0, max_length)
22 | self.chars_num = len(self.chars)
23 |
24 | def __iter__(self) -> BruteForceStringGenerator:
25 | return self
26 |
27 | def __next__(self) -> str:
28 | self.next_string()
29 | return self.sequence
30 |
31 | def __len__(self) -> int:
32 | return len(self._sequence_list)
33 |
34 | def __repr__(self):
35 | return f"{self.sequence}"
36 |
37 | @property
38 | def sequence(self) -> str:
39 | return "".join(self._sequence_list)
40 |
41 | @sequence.setter
42 | def sequence(self, sequence: str) -> None:
43 | self._sequence_list = list(sequence)
44 |
45 | @property
46 | def dir(self):
47 | return self._dir
48 |
49 | @dir.setter
50 | def dir(self, direction):
51 | if type(direction) is not Direction:
52 | raise ValueError("Direction should be Direction Type")
53 | self._dir = direction
54 |
55 | @property
56 | def min_length(self):
57 | return self._min_length
58 |
59 | @min_length.setter
60 | def min_length(self, min_length):
61 | if type(min_length) is not int or min_length <= 0:
62 | raise ValueError("min_length should be integer greater than 0")
63 | self._min_length = min_length
64 |
65 | @property
66 | def max_length(self):
67 | return self._max_length
68 |
69 | @max_length.setter
70 | def max_length(self, max_length):
71 | if type(max_length) is not int or max_length < 0:
72 | raise ValueError("max_length should be integer")
73 | self._max_length = max_length
74 |
75 | def next_string(self) -> None:
76 | self._sequence_list = self._next(self._sequence_list)
77 |
78 | def check_length(self, length: int):
79 | if self.max_length and length > self.max_length:
80 | raise StopIteration
81 |
82 | def _next(self, current: list) -> list:
83 | if len(current) <= 0:
84 | if not self._sequence_list:
85 | return list(self.chars[0] * self.min_length)
86 | else:
87 | self.check_length(len(self) + 1)
88 | return list(self.chars[0])
89 | else:
90 | self.check_length(len(self))
91 | current[self.dir] = self.chars[((self.chars.index(current[self.dir]) + 1) % self.chars_num)]
92 | if self.chars.index(current[self.dir]) == 0:
93 | if self.dir == Direction.LEFT:
94 | return list(current[0]) + self._next(current[1:])
95 | else:
96 | return self._next(current[:-1]) + list(current[-1])
97 | return current
98 |
--------------------------------------------------------------------------------
/tests/test_brute_froce_string_generator.py:
--------------------------------------------------------------------------------
1 | import string
2 |
3 | from SG.BFSG import BruteForceStringGenerator, Direction
4 |
5 | import unittest
6 | import pytest
7 |
8 |
9 | class MyTest(unittest.TestCase):
10 | def test_brute_force_empty(self):
11 | default_init = BruteForceStringGenerator()
12 | assert (next(default_init) == 'a')
13 |
14 | def test_brute_force_direction(self):
15 | direction_test = BruteForceStringGenerator(sequence='aa', direction=Direction.LEFT)
16 | assert (next(direction_test) == 'ba')
17 | direction_test = BruteForceStringGenerator(sequence='aa', direction=Direction.RIGHT)
18 | assert (next(direction_test) == 'ab')
19 |
20 | def test_brute_force_edge(self):
21 | direction_test = BruteForceStringGenerator(sequence='za', direction=Direction.LEFT)
22 | assert (next(direction_test) == 'ab')
23 | direction_test = BruteForceStringGenerator(sequence='az', direction=Direction.RIGHT)
24 | assert (next(direction_test) == 'ba')
25 |
26 | def test_brute_force_long_string(self):
27 | long_string = BruteForceStringGenerator(sequence='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
28 | assert (next(long_string) == 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
29 |
30 | def test_brute_force_for_loop(self):
31 | loop_string = BruteForceStringGenerator(min_length=3)
32 | for _ in range(1, len(string.ascii_lowercase)):
33 | next(loop_string)
34 | assert (next(loop_string) == 'aaz')
35 |
36 | for _ in range(1, len(string.ascii_lowercase)):
37 | next(loop_string)
38 | assert (next(loop_string) == 'abz')
39 |
40 | for _ in range(1, len(string.ascii_lowercase * len(string.ascii_lowercase))):
41 | next(loop_string)
42 | assert (next(loop_string) == 'bbz')
43 |
44 | def test_brute_force_custom_chars(self):
45 | custom_string = BruteForceStringGenerator(chars='!@#', min_length=3)
46 | assert (next(custom_string) == '!!!')
47 | assert (next(custom_string) == '!!@')
48 | assert (next(custom_string) == '!!#')
49 |
50 | def test_brute_force_brute_left(self):
51 | brute_string = BruteForceStringGenerator(direction=Direction.LEFT)
52 | for _ in range(1, 2000000):
53 | next(brute_string)
54 | assert (next(brute_string) == 'botid')
55 |
56 | def test_brute_force_brute_right(self):
57 | brute_string = BruteForceStringGenerator()
58 | for _ in range(1, 2000000):
59 | next(brute_string)
60 | assert (next(brute_string) == 'ditob')
61 |
62 | def test_brute_force_max_length(self):
63 | with pytest.raises(StopIteration):
64 | brute_string = BruteForceStringGenerator('z', max_length=1)
65 | next(brute_string)
66 |
67 | def test_brute_force_generator(self):
68 | brute_string = BruteForceStringGenerator(max_length=3)
69 | for text in brute_string:
70 | pass
71 | assert (text == 'zzz')
72 |
73 | def test_not_direction_type(self):
74 | for i in range(-1, 2):
75 | with pytest.raises(ValueError):
76 | BruteForceStringGenerator('a', max_length=1, direction=i)
77 |
78 | def test_brute_force_with_space(self):
79 | custom_string = BruteForceStringGenerator(chars='a ', min_length=3)
80 | assert (next(custom_string) == 'aaa')
81 | assert (next(custom_string) == 'aa ')
82 | assert (next(custom_string) == 'a a')
83 |
84 | def test_brute_force_with_polish_letters(self):
85 | custom_string = BruteForceStringGenerator(chars='ąćęłńóśźż', min_length=3)
86 | for _ in range(1, 2003):
87 | next(custom_string)
88 | assert (next(custom_string) == 'ćśśń')
89 |
90 | def test_brute_force_with_polish_letters_backward(self):
91 | custom_string = BruteForceStringGenerator(chars='ąćęłńóśźż', min_length=3, direction=Direction.LEFT)
92 | for _ in range(1, 2003):
93 | next(custom_string)
94 | assert (next(custom_string) == 'ńśść')
95 |
96 | def test_brute_force_with_german_letters(self):
97 | custom_string = BruteForceStringGenerator(chars='äöüß', min_length=3)
98 | for _ in range(1, 2003):
99 | next(custom_string)
100 | assert (next(custom_string) == 'äüüöäü')
101 |
102 | def test_brute_force_with_german_letters_backward(self):
103 | custom_string = BruteForceStringGenerator(chars='äöüß', min_length=3, direction=Direction.LEFT)
104 | for _ in range(1, 2003):
105 | next(custom_string)
106 | assert (next(custom_string) == 'üäöüüä')
107 |
108 | def test_brute_force_with_czech_letters(self):
109 | custom_string = BruteForceStringGenerator(chars='ýžáčďéěíňóřšťúů', max_length=4)
110 | for _ in custom_string:
111 | pass
112 | assert (custom_string.sequence == 'ůůůý')
113 |
114 | def test_brute_force_with_czech_letters_backward(self):
115 | custom_string = BruteForceStringGenerator(chars='ýžáčďéěíňóřšťúů', max_length=4, direction=Direction.LEFT)
116 | for _ in custom_string:
117 | pass
118 | assert (custom_string.sequence == 'ýůůů')
119 |
120 | def test_brute_force_string_max_length(self):
121 | for i in range(1, 10):
122 | custom_string = BruteForceStringGenerator(chars='ab', max_length=i)
123 | for _ in custom_string:
124 | pass
125 | assert (len(custom_string) == i)
126 |
--------------------------------------------------------------------------------
/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "737970ea335caaae8657acf6f544e3bd6164bc8688dadedd815926a975b4c91c"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3.8.5"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.python.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {
19 | "mypy": {
20 | "hashes": [
21 | "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9",
22 | "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a",
23 | "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9",
24 | "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e",
25 | "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2",
26 | "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212",
27 | "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b",
28 | "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885",
29 | "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150",
30 | "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703",
31 | "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072",
32 | "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457",
33 | "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e",
34 | "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0",
35 | "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb",
36 | "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97",
37 | "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8",
38 | "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811",
39 | "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6",
40 | "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de",
41 | "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504",
42 | "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921",
43 | "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"
44 | ],
45 | "index": "pypi",
46 | "version": "==0.910"
47 | },
48 | "mypy-extensions": {
49 | "hashes": [
50 | "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
51 | "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
52 | ],
53 | "version": "==0.4.3"
54 | },
55 | "toml": {
56 | "hashes": [
57 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
58 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
59 | ],
60 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
61 | "version": "==0.10.2"
62 | },
63 | "typing-extensions": {
64 | "hashes": [
65 | "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e",
66 | "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7",
67 | "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"
68 | ],
69 | "version": "==3.10.0.2"
70 | }
71 | },
72 | "develop": {
73 | "attrs": {
74 | "hashes": [
75 | "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
76 | "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
77 | ],
78 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
79 | "version": "==21.2.0"
80 | },
81 | "iniconfig": {
82 | "hashes": [
83 | "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
84 | "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"
85 | ],
86 | "version": "==1.1.1"
87 | },
88 | "mypy": {
89 | "hashes": [
90 | "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9",
91 | "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a",
92 | "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9",
93 | "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e",
94 | "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2",
95 | "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212",
96 | "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b",
97 | "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885",
98 | "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150",
99 | "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703",
100 | "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072",
101 | "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457",
102 | "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e",
103 | "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0",
104 | "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb",
105 | "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97",
106 | "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8",
107 | "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811",
108 | "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6",
109 | "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de",
110 | "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504",
111 | "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921",
112 | "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"
113 | ],
114 | "index": "pypi",
115 | "version": "==0.910"
116 | },
117 | "mypy-extensions": {
118 | "hashes": [
119 | "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
120 | "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
121 | ],
122 | "version": "==0.4.3"
123 | },
124 | "packaging": {
125 | "hashes": [
126 | "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7",
127 | "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"
128 | ],
129 | "markers": "python_version >= '3.6'",
130 | "version": "==21.0"
131 | },
132 | "pluggy": {
133 | "hashes": [
134 | "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
135 | "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
136 | ],
137 | "markers": "python_version >= '3.6'",
138 | "version": "==1.0.0"
139 | },
140 | "py": {
141 | "hashes": [
142 | "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
143 | "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
144 | ],
145 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
146 | "version": "==1.10.0"
147 | },
148 | "pyparsing": {
149 | "hashes": [
150 | "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
151 | "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
152 | ],
153 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
154 | "version": "==2.4.7"
155 | },
156 | "pytest": {
157 | "hashes": [
158 | "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89",
159 | "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"
160 | ],
161 | "index": "pypi",
162 | "version": "==6.2.5"
163 | },
164 | "toml": {
165 | "hashes": [
166 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
167 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
168 | ],
169 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
170 | "version": "==0.10.2"
171 | },
172 | "typing-extensions": {
173 | "hashes": [
174 | "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e",
175 | "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7",
176 | "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"
177 | ],
178 | "version": "==3.10.0.2"
179 | }
180 | }
181 | }
182 |
--------------------------------------------------------------------------------