├── _config.yml
├── static
└── demo.gif
├── config.ini
├── Pipfile
├── index.html
├── templates
├── 401.html
└── newspie.html
├── requirements.txt
├── LICENSE
├── data
└── countries.json
├── README.md
├── .gitignore
├── news.py
└── Pipfile.lock
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
2 |
--------------------------------------------------------------------------------
/static/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skamieniarz/newspie/HEAD/static/demo.gif
--------------------------------------------------------------------------------
/config.ini:
--------------------------------------------------------------------------------
1 | [ENDPOINTS]
2 | TOP_HEADLINES = https://newsapi.org/v2/top-headlines
3 | EVERYTHING = https://newsapi.org/v2/everything
4 |
5 | [VARIOUS]
6 | TEMPLATE = newspie.html
7 | 401_TEMPLATE = 401.html
8 | PAGE_SIZE = 6
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | name = "pypi"
3 | url = "https://pypi.org/simple"
4 | verify_ssl = true
5 |
6 | [dev-packages]
7 | pylint = "*"
8 | yapf = "*"
9 | flake8 = "*"
10 |
11 | [packages]
12 | requests = "*"
13 | flask = "*"
14 | requests-cache = "*"
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Redirecting to https://newspie.eu.pythonanywhere.com/
4 |
5 |
6 |
--------------------------------------------------------------------------------
/templates/401.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | NewsPie
9 |
10 |
11 |
12 | API key is invalid or its configuration is incorrect (not saved as an environment variable or as a string in the code).
13 |
14 |
15 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | -i https://pypi.org/simple
2 | attrs==23.1.0; python_version >= '3.7'
3 | blinker==1.6.2; python_version >= '3.7'
4 | cattrs==23.1.2; python_version >= '3.7'
5 | certifi==2023.7.22; python_version >= '3.6'
6 | charset-normalizer==3.2.0; python_full_version >= '3.7.0'
7 | click==8.1.7; python_version >= '3.7'
8 | flask==2.3.3
9 | idna==3.4; python_version >= '3.5'
10 | itsdangerous==2.1.2; python_version >= '3.7'
11 | jinja2==3.1.2; python_version >= '3.7'
12 | markupsafe==2.1.3; python_version >= '3.7'
13 | platformdirs==3.10.0; python_version >= '3.7'
14 | requests==2.31.0
15 | requests-cache==1.1.0
16 | six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'
17 | url-normalize==1.4.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'
18 | urllib3==2.0.4; python_version >= '3.7'
19 | werkzeug==2.3.7; python_version >= '3.8'
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 skamieniarz
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 |
--------------------------------------------------------------------------------
/data/countries.json:
--------------------------------------------------------------------------------
1 | {
2 | "ar": "Argentina",
3 | "au": "Australia",
4 | "at": "Austria",
5 | "be": "Belgium",
6 | "br": "Brazil",
7 | "bg": "Bulgaria",
8 | "ca": "Canada",
9 | "cn": "China",
10 | "co": "Colombia",
11 | "cu": "Cuba",
12 | "cz": "Czechia",
13 | "eg": "Egypt",
14 | "fr": "France",
15 | "de": "Germany",
16 | "gr": "Greece",
17 | "hk": "Hong Kong",
18 | "hu": "Hungary",
19 | "in": "India",
20 | "id": "Indonesia",
21 | "ie": "Ireland",
22 | "il": "Israel",
23 | "it": "Italy",
24 | "jp": "Japan",
25 | "lv": "Latvia",
26 | "lt": "Lithuania",
27 | "my": "Malaysia",
28 | "mx": "Mexico",
29 | "ma": "Morocco",
30 | "nl": "Netherlands",
31 | "nz": "New Zealand",
32 | "ng": "Nigeria",
33 | "no": "Norway",
34 | "ph": "Philippines",
35 | "pl": "Poland",
36 | "pt": "Portugal",
37 | "kr": "South Korea",
38 | "ro": "Romania",
39 | "ru": "Russia",
40 | "sa": "Saudi Arabia",
41 | "rs": "Serbia",
42 | "sg": "Singapore",
43 | "sk": "Slovakia",
44 | "si": "Slovenia",
45 | "za": "South Africa",
46 | "se": "Sweden",
47 | "ch": "Switzerland",
48 | "tw": "Taiwan",
49 | "th": "Thailand",
50 | "tr": "Turkey",
51 | "ua": "Ukraine",
52 | "ae": "UAE",
53 | "gb": "UK",
54 | "us": "USA",
55 | "ve": "Venezuela"
56 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NewsPie #
2 | A minimalistic news aggregator built with [Flask](https://www.palletsprojects.com/p/flask/) and powered by [News API](https://newsapi.org/).
3 |
4 | 
5 |
6 | ## Prerequisites: ##
7 |
8 | 1. [Python3](https://www.python.org).
9 | 2. Dependencies from `requirements.txt` or `Pipfile.lock` (preferably in a virtual env).
10 | 3. API key for [News API](https://newsapi.org/register). It's free for non-commercial projects (including open-source) and allows 500 requests per day. Once acquired, save it as `NEWS_API_KEY` environment variable or directly as string to `API_KEY` in `news.py`. Just don't share it or upload the code with it.
11 |
12 | ## Starting: ##
13 |
14 | 1. Run `python news.py` or `python3 news.py` (depending on the environment) in the terminal while in the root of the repository.
15 | 2. Go to [http://127.0.0.1:5000/](http://127.0.0.1:5000/) address in the web browser.
16 |
17 | ## Features: ##
18 |
19 | 1. Get top articles headlines and their URLs by country and/or category.
20 | 2. Search articles up to a month old. Looks for a given query in the titles. Language/country independent results. Relevancy decides.
21 | 3. Results received from News API are cached for 5 minutes.
22 | 4. Country saved as a cookie.
23 | 5. Responsive UI.
24 | 6. Dark mode/theme.
25 |
26 | ## Open-source used: ##
27 |
28 | - [Flask](https://github.com/pallets/flask)
29 | - [jinja](https://github.com/pallets/jinja)
30 | - [Pico.css](https://github.com/picocss/pico)
31 | - [requests](https://github.com/psf/requests)
32 | - [requests-cache](https://github.com/reclosedev/requests-cache)
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | .DS_store
3 | .vscode/
4 | news_cache.sqlite
5 |
6 | # Byte-compiled / optimized / DLL files
7 | __pycache__/
8 | *.py[cod]
9 | *$py.class
10 |
11 | # C extensions
12 | *.so
13 |
14 | # Distribution / packaging
15 | .Python
16 | build/
17 | develop-eggs/
18 | dist/
19 | downloads/
20 | eggs/
21 | .eggs/
22 | lib/
23 | lib64/
24 | parts/
25 | sdist/
26 | var/
27 | wheels/
28 | pip-wheel-metadata/
29 | share/python-wheels/
30 | *.egg-info/
31 | .installed.cfg
32 | *.egg
33 | MANIFEST
34 |
35 | # PyInstaller
36 | # Usually these files are written by a python script from a template
37 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
38 | *.manifest
39 | *.spec
40 |
41 | # Installer logs
42 | pip-log.txt
43 | pip-delete-this-directory.txt
44 |
45 | # Unit test / coverage reports
46 | htmlcov/
47 | .tox/
48 | .nox/
49 | .coverage
50 | .coverage.*
51 | .cache
52 | nosetests.xml
53 | coverage.xml
54 | *.cover
55 | *.py,cover
56 | .hypothesis/
57 | .pytest_cache/
58 |
59 | # Translations
60 | *.mo
61 | *.pot
62 |
63 | # Django stuff:
64 | *.log
65 | local_settings.py
66 | db.sqlite3
67 | db.sqlite3-journal
68 |
69 | # Flask stuff:
70 | instance/
71 | .webassets-cache
72 |
73 | # Scrapy stuff:
74 | .scrapy
75 |
76 | # Sphinx documentation
77 | docs/_build/
78 |
79 | # PyBuilder
80 | target/
81 |
82 | # Jupyter Notebook
83 | .ipynb_checkpoints
84 |
85 | # IPython
86 | profile_default/
87 | ipython_config.py
88 |
89 | # pyenv
90 | .python-version
91 |
92 | # pipenv
93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
96 | # install all needed dependencies.
97 | #Pipfile.lock
98 |
99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
100 | __pypackages__/
101 |
102 | # Celery stuff
103 | celerybeat-schedule
104 | celerybeat.pid
105 |
106 | # SageMath parsed files
107 | *.sage.py
108 |
109 | # Environments
110 | .env
111 | .venv
112 | env/
113 | venv/
114 | ENV/
115 | env.bak/
116 | venv.bak/
117 |
118 | # Spyder project settings
119 | .spyderproject
120 | .spyproject
121 |
122 | # Rope project settings
123 | .ropeproject
124 |
125 | # mkdocs documentation
126 | /site
127 |
128 | # mypy
129 | .mypy_cache/
130 | .dmypy.json
131 | dmypy.json
132 |
133 | # Pyre type checker
134 | .pyre/
135 |
--------------------------------------------------------------------------------
/templates/newspie.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | NewsPie
9 |
10 |
11 |
12 |
13 | NewsPie{% for item in categories %}{% if item == category %} • {{ item }}
14 | {% else %} • {{ item }}
15 | {% endif %}{% endfor %}
16 |
17 |
18 |
19 |
20 | {% for article in articles %}
21 |
22 | | {{ article['title'] }}
24 | |
25 |
26 | {% endfor %}
27 |
28 |
29 |
38 |
39 |
44 |
45 |
55 |
60 |
61 |
62 |
68 |
69 |
--------------------------------------------------------------------------------
/news.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | '''
3 | NewsPie - a minimalistic news aggregator built with Flask and powered by
4 | News API (https://newsapi.org/).
5 |
6 | Created by @skamieniarz (https://github.com/skamieniarz) in 2019.
7 | '''
8 | import configparser
9 | import json
10 | import logging
11 | import os
12 | from typing import Union
13 |
14 | import requests
15 | import requests_cache
16 | from flask import (Flask, make_response, redirect, render_template, request,
17 | url_for)
18 |
19 | CONFIG = configparser.ConfigParser()
20 | CONFIG.read('config.ini')
21 | API_KEY = os.environ.get('NEWS_API_KEY')
22 | TOP_HEADLINES = CONFIG['ENDPOINTS']['TOP_HEADLINES']
23 | EVERYTHING = CONFIG['ENDPOINTS']['EVERYTHING']
24 | PAGE_SIZE = int(CONFIG['VARIOUS']['PAGE_SIZE'])
25 |
26 | CATEGORIES = ('general', 'sports', 'business', 'entertainment', 'health',
27 | 'science', 'technology')
28 | with open('data/countries.json') as json_file:
29 | COUNTRIES = json.load(json_file)
30 |
31 | logging.basicConfig(level=logging.DEBUG)
32 | requests_cache.install_cache(cache_name='news_cache',
33 | backend='sqlite',
34 | expire_after=300)
35 |
36 | APP = Flask(__name__)
37 | SESSION = requests.Session()
38 | SESSION.headers.update({'Authorization': API_KEY})
39 |
40 |
41 | @APP.route('/', methods=['GET', 'POST'])
42 | def root():
43 | ''' Base URL redirect to the first page of general category. '''
44 | return redirect(url_for('category', category='general', page=1))
45 |
46 |
47 | @APP.errorhandler(404)
48 | def page_not_found(error):
49 | ''' Not existing pages redirect to the first page of general category. '''
50 | return redirect(url_for('category', category='general', page=1))
51 |
52 |
53 | @APP.route('/category/', methods=['GET', 'POST'])
54 | def category(category):
55 | ''' Handles category route.
56 |
57 | Parameters:
58 | - name: category
59 | in: path
60 | description: Name of the news category
61 | - name: page
62 | in: query
63 | description: Number of the page
64 | '''
65 | page = request.args.get('page', default=1, type=int)
66 | if page < 1:
67 | return redirect(url_for('category', category=category, page=1))
68 | if request.method == 'POST' and category in CATEGORIES:
69 | return do_post(page, category)
70 | if category in CATEGORIES:
71 | params = {'page': page, 'category': category, 'pageSize': PAGE_SIZE}
72 | country = get_cookie('country')
73 | if country is not None:
74 | params.update({'country': country})
75 | response = SESSION.get(TOP_HEADLINES, params=params)
76 | if response.status_code == 200:
77 | pages = count_pages(response.json())
78 | if page > pages:
79 | page = pages
80 | return redirect(
81 | url_for('category', category=category, page=page))
82 | articles = parse_articles(response.json())
83 | theme = get_cookie('theme') if get_cookie(
84 | 'theme') is not None else 'light'
85 | return render(articles, page, pages, country, category, theme)
86 | elif response.status_code == 401:
87 | return render_template(CONFIG['VARIOUS']['401_TEMPLATE'])
88 | return redirect(url_for('category', category='general', page=page))
89 |
90 |
91 | @APP.route('/search/', methods=['GET', 'POST'])
92 | def search(query: str):
93 | ''' Handles category route.
94 |
95 | Parameters:
96 | - name: query
97 | in: path
98 | description: Query string to be searched
99 | - name: page
100 | in: query
101 | description: Number of the page
102 | '''
103 | page = request.args.get('page', default=1, type=int)
104 | if page < 1:
105 | return redirect(url_for('search', query=query, page=1))
106 | params = {
107 | 'qInTitle': query,
108 | 'sortBy': 'relevancy',
109 | 'page': page,
110 | 'pageSize': PAGE_SIZE
111 | }
112 | if request.method == 'POST':
113 | return do_post(page, category='search', current_query=query)
114 | response = SESSION.get(EVERYTHING, params=params)
115 | pages = count_pages(response.json())
116 | if page > pages:
117 | page = pages
118 | return redirect(url_for('search', query=query, page=page))
119 | articles = parse_articles(response.json())
120 | return render(articles,
121 | page,
122 | pages,
123 | country=get_cookie('country'),
124 | category='search',
125 | theme=get_cookie('theme'))
126 |
127 |
128 | def do_post(page=1, category='general', current_query=None):
129 | ''' Helper method that handles POST request basing on the input. '''
130 | new_query = request.form.get('search_query')
131 | country = request.form.get('country')
132 | theme = request.form.get('theme')
133 | next_page = request.form.get('next_page')
134 | previous_page = request.form.get('previous_page')
135 | if new_query is not None and new_query != '':
136 | return redirect(url_for('search', query=new_query, page=1))
137 | if country is not None and country != get_cookie('country'):
138 | response = make_response(
139 | redirect(url_for('category', category=category, page=1)))
140 | response.set_cookie('country', country)
141 | return response
142 | if theme is not None:
143 | response = make_response(
144 | redirect(url_for('category', category=category, page=page)))
145 | response.set_cookie('theme', theme)
146 | return response
147 | if next_page is not None:
148 | page = int(next_page) + 1
149 | elif previous_page is not None:
150 | page = int(previous_page) - 1
151 | if category == 'search':
152 | return redirect(url_for('search', query=current_query, page=page))
153 | return redirect(url_for('category', category=category, page=page))
154 |
155 |
156 | def parse_articles(response: dict) -> list:
157 | ''' Parses articles fetched from News API.
158 |
159 | Returns:
160 | A list of dicts containing publishing title and URL.
161 | '''
162 | parsed_articles = []
163 | if response.get('status') == 'ok':
164 | for article in response.get('articles'):
165 | parsed_articles.append({
166 | 'title': article['title'],
167 | 'url': article['url']
168 | })
169 | return parsed_articles
170 |
171 |
172 | def count_pages(response: dict) -> int:
173 | ''' Helper method that counts number of total pages basing on total
174 | results from News API response and PAGE_SIZE.
175 |
176 | Returns:
177 | An int with a number of total pages. '''
178 | if response.get('status') == 'ok':
179 | return (-(-response.get('totalResults', 0) // PAGE_SIZE))
180 | return 0
181 |
182 |
183 | def render(articles: list, page: int, pages: int, country: str, category: str,
184 | theme: str):
185 | ''' Renders the template with appropriate variables. Up to 12 pages
186 | allowed. '''
187 | pages = pages if pages <= 12 else 12
188 | return render_template(CONFIG['VARIOUS']['TEMPLATE'],
189 | articles=articles,
190 | categories=CATEGORIES,
191 | category=category,
192 | countries=COUNTRIES,
193 | country=country,
194 | page=page,
195 | pages=pages,
196 | theme=theme)
197 |
198 |
199 | def get_cookie(key: str) -> Union[str, None]:
200 | ''' Helper method that gets cookie's value.
201 |
202 | Returns:
203 | A string with a value of a cookie with provided key. If a key is
204 | missing, None is returned.
205 | '''
206 | return request.cookies.get(key)
207 |
208 |
209 | if __name__ == '__main__':
210 | APP.run()
211 |
--------------------------------------------------------------------------------
/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "0e27b578cbaccfd58327d1bff71a9aea8519c51e35fc267c023355e93bb3fda9"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {},
8 | "sources": [
9 | {
10 | "name": "pypi",
11 | "url": "https://pypi.org/simple",
12 | "verify_ssl": true
13 | }
14 | ]
15 | },
16 | "default": {
17 | "attrs": {
18 | "hashes": [
19 | "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04",
20 | "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"
21 | ],
22 | "markers": "python_version >= '3.7'",
23 | "version": "==23.1.0"
24 | },
25 | "blinker": {
26 | "hashes": [
27 | "sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213",
28 | "sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0"
29 | ],
30 | "markers": "python_version >= '3.7'",
31 | "version": "==1.6.2"
32 | },
33 | "cattrs": {
34 | "hashes": [
35 | "sha256:b2bb14311ac17bed0d58785e5a60f022e5431aca3932e3fc5cc8ed8639de50a4",
36 | "sha256:db1c821b8c537382b2c7c66678c3790091ca0275ac486c76f3c8f3920e83c657"
37 | ],
38 | "markers": "python_version >= '3.7'",
39 | "version": "==23.1.2"
40 | },
41 | "certifi": {
42 | "hashes": [
43 | "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
44 | "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
45 | ],
46 | "markers": "python_version >= '3.6'",
47 | "version": "==2023.7.22"
48 | },
49 | "charset-normalizer": {
50 | "hashes": [
51 | "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96",
52 | "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c",
53 | "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710",
54 | "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706",
55 | "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020",
56 | "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252",
57 | "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad",
58 | "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329",
59 | "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a",
60 | "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f",
61 | "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6",
62 | "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4",
63 | "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a",
64 | "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46",
65 | "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2",
66 | "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23",
67 | "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace",
68 | "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd",
69 | "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982",
70 | "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10",
71 | "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2",
72 | "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea",
73 | "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09",
74 | "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5",
75 | "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149",
76 | "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489",
77 | "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9",
78 | "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80",
79 | "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592",
80 | "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3",
81 | "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6",
82 | "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed",
83 | "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c",
84 | "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200",
85 | "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a",
86 | "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e",
87 | "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d",
88 | "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6",
89 | "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623",
90 | "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669",
91 | "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3",
92 | "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa",
93 | "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9",
94 | "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2",
95 | "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f",
96 | "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1",
97 | "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4",
98 | "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a",
99 | "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8",
100 | "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3",
101 | "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029",
102 | "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f",
103 | "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959",
104 | "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22",
105 | "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7",
106 | "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952",
107 | "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346",
108 | "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e",
109 | "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d",
110 | "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299",
111 | "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd",
112 | "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a",
113 | "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3",
114 | "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037",
115 | "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94",
116 | "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c",
117 | "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858",
118 | "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a",
119 | "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449",
120 | "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c",
121 | "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918",
122 | "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1",
123 | "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c",
124 | "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac",
125 | "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"
126 | ],
127 | "markers": "python_full_version >= '3.7.0'",
128 | "version": "==3.2.0"
129 | },
130 | "click": {
131 | "hashes": [
132 | "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
133 | "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
134 | ],
135 | "markers": "python_version >= '3.7'",
136 | "version": "==8.1.7"
137 | },
138 | "flask": {
139 | "hashes": [
140 | "sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc",
141 | "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b"
142 | ],
143 | "index": "pypi",
144 | "version": "==2.3.3"
145 | },
146 | "idna": {
147 | "hashes": [
148 | "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
149 | "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
150 | ],
151 | "markers": "python_version >= '3.5'",
152 | "version": "==3.4"
153 | },
154 | "itsdangerous": {
155 | "hashes": [
156 | "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
157 | "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"
158 | ],
159 | "markers": "python_version >= '3.7'",
160 | "version": "==2.1.2"
161 | },
162 | "jinja2": {
163 | "hashes": [
164 | "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
165 | "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
166 | ],
167 | "markers": "python_version >= '3.7'",
168 | "version": "==3.1.2"
169 | },
170 | "markupsafe": {
171 | "hashes": [
172 | "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e",
173 | "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e",
174 | "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431",
175 | "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686",
176 | "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559",
177 | "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc",
178 | "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c",
179 | "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0",
180 | "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4",
181 | "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9",
182 | "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575",
183 | "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba",
184 | "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d",
185 | "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3",
186 | "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00",
187 | "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155",
188 | "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac",
189 | "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52",
190 | "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f",
191 | "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8",
192 | "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b",
193 | "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24",
194 | "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea",
195 | "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198",
196 | "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0",
197 | "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee",
198 | "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be",
199 | "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2",
200 | "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707",
201 | "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6",
202 | "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58",
203 | "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779",
204 | "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636",
205 | "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c",
206 | "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad",
207 | "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee",
208 | "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc",
209 | "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2",
210 | "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48",
211 | "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7",
212 | "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e",
213 | "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b",
214 | "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa",
215 | "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5",
216 | "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e",
217 | "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb",
218 | "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9",
219 | "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57",
220 | "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc",
221 | "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"
222 | ],
223 | "markers": "python_version >= '3.7'",
224 | "version": "==2.1.3"
225 | },
226 | "platformdirs": {
227 | "hashes": [
228 | "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d",
229 | "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"
230 | ],
231 | "markers": "python_version >= '3.7'",
232 | "version": "==3.10.0"
233 | },
234 | "requests": {
235 | "hashes": [
236 | "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
237 | "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
238 | ],
239 | "index": "pypi",
240 | "version": "==2.31.0"
241 | },
242 | "requests-cache": {
243 | "hashes": [
244 | "sha256:178282bce704b912c59e7f88f367c42bddd6cde6bf511b2a3e3cfb7e5332a92a",
245 | "sha256:41b79166aa8e300cc4de982f7ab7c52af914a785160be1eda25c6e9265969a67"
246 | ],
247 | "index": "pypi",
248 | "version": "==1.1.0"
249 | },
250 | "six": {
251 | "hashes": [
252 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
253 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
254 | ],
255 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
256 | "version": "==1.16.0"
257 | },
258 | "url-normalize": {
259 | "hashes": [
260 | "sha256:d23d3a070ac52a67b83a1c59a0e68f8608d1cd538783b401bc9de2c0fac999b2",
261 | "sha256:ec3c301f04e5bb676d333a7fa162fa977ad2ca04b7e652bfc9fac4e405728eed"
262 | ],
263 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
264 | "version": "==1.4.3"
265 | },
266 | "urllib3": {
267 | "hashes": [
268 | "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11",
269 | "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"
270 | ],
271 | "markers": "python_version >= '3.7'",
272 | "version": "==2.0.4"
273 | },
274 | "werkzeug": {
275 | "hashes": [
276 | "sha256:2b8c0e447b4b9dbcc85dd97b6eeb4dcbaf6c8b6c3be0bd654e25553e0a2157d8",
277 | "sha256:effc12dba7f3bd72e605ce49807bbe692bd729c3bb122a3b91747a6ae77df528"
278 | ],
279 | "markers": "python_version >= '3.8'",
280 | "version": "==2.3.7"
281 | }
282 | },
283 | "develop": {
284 | "astroid": {
285 | "hashes": [
286 | "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c",
287 | "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"
288 | ],
289 | "markers": "python_full_version >= '3.7.2'",
290 | "version": "==2.15.6"
291 | },
292 | "dill": {
293 | "hashes": [
294 | "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e",
295 | "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"
296 | ],
297 | "markers": "python_version >= '3.11'",
298 | "version": "==0.3.7"
299 | },
300 | "flake8": {
301 | "hashes": [
302 | "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23",
303 | "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"
304 | ],
305 | "index": "pypi",
306 | "version": "==6.1.0"
307 | },
308 | "importlib-metadata": {
309 | "hashes": [
310 | "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb",
311 | "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"
312 | ],
313 | "markers": "python_version >= '3.8'",
314 | "version": "==6.8.0"
315 | },
316 | "isort": {
317 | "hashes": [
318 | "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504",
319 | "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"
320 | ],
321 | "markers": "python_full_version >= '3.8.0'",
322 | "version": "==5.12.0"
323 | },
324 | "lazy-object-proxy": {
325 | "hashes": [
326 | "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382",
327 | "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82",
328 | "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9",
329 | "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494",
330 | "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46",
331 | "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30",
332 | "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63",
333 | "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4",
334 | "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae",
335 | "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be",
336 | "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701",
337 | "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd",
338 | "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006",
339 | "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a",
340 | "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586",
341 | "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8",
342 | "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821",
343 | "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07",
344 | "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b",
345 | "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171",
346 | "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b",
347 | "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2",
348 | "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7",
349 | "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4",
350 | "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8",
351 | "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e",
352 | "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f",
353 | "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda",
354 | "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4",
355 | "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e",
356 | "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671",
357 | "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11",
358 | "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455",
359 | "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734",
360 | "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb",
361 | "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"
362 | ],
363 | "markers": "python_version >= '3.7'",
364 | "version": "==1.9.0"
365 | },
366 | "mccabe": {
367 | "hashes": [
368 | "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
369 | "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
370 | ],
371 | "markers": "python_version >= '3.6'",
372 | "version": "==0.7.0"
373 | },
374 | "platformdirs": {
375 | "hashes": [
376 | "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d",
377 | "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"
378 | ],
379 | "markers": "python_version >= '3.7'",
380 | "version": "==3.10.0"
381 | },
382 | "pycodestyle": {
383 | "hashes": [
384 | "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0",
385 | "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"
386 | ],
387 | "markers": "python_version >= '3.8'",
388 | "version": "==2.11.0"
389 | },
390 | "pyflakes": {
391 | "hashes": [
392 | "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774",
393 | "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"
394 | ],
395 | "markers": "python_version >= '3.8'",
396 | "version": "==3.1.0"
397 | },
398 | "pylint": {
399 | "hashes": [
400 | "sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413",
401 | "sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252"
402 | ],
403 | "index": "pypi",
404 | "version": "==2.17.5"
405 | },
406 | "tomli": {
407 | "hashes": [
408 | "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
409 | "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
410 | ],
411 | "markers": "python_version >= '3.7'",
412 | "version": "==2.0.1"
413 | },
414 | "tomlkit": {
415 | "hashes": [
416 | "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86",
417 | "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"
418 | ],
419 | "markers": "python_version >= '3.7'",
420 | "version": "==0.12.1"
421 | },
422 | "wrapt": {
423 | "hashes": [
424 | "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0",
425 | "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420",
426 | "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a",
427 | "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c",
428 | "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079",
429 | "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923",
430 | "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f",
431 | "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1",
432 | "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8",
433 | "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86",
434 | "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0",
435 | "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364",
436 | "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e",
437 | "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c",
438 | "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e",
439 | "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c",
440 | "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727",
441 | "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff",
442 | "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e",
443 | "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29",
444 | "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7",
445 | "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72",
446 | "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475",
447 | "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a",
448 | "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317",
449 | "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2",
450 | "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd",
451 | "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640",
452 | "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98",
453 | "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248",
454 | "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e",
455 | "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d",
456 | "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec",
457 | "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1",
458 | "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e",
459 | "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9",
460 | "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92",
461 | "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb",
462 | "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094",
463 | "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46",
464 | "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29",
465 | "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd",
466 | "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705",
467 | "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8",
468 | "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975",
469 | "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb",
470 | "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e",
471 | "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b",
472 | "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418",
473 | "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019",
474 | "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1",
475 | "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba",
476 | "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6",
477 | "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2",
478 | "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3",
479 | "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7",
480 | "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752",
481 | "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416",
482 | "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f",
483 | "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1",
484 | "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc",
485 | "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145",
486 | "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee",
487 | "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a",
488 | "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7",
489 | "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b",
490 | "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653",
491 | "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0",
492 | "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90",
493 | "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29",
494 | "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6",
495 | "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034",
496 | "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09",
497 | "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559",
498 | "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"
499 | ],
500 | "markers": "python_version >= '3.11'",
501 | "version": "==1.15.0"
502 | },
503 | "yapf": {
504 | "hashes": [
505 | "sha256:958587eb5c8ec6c860119a9c25d02addf30a44f75aa152a4220d30e56a98037c",
506 | "sha256:b8bfc1f280949153e795181768ca14ef43d7312629a06c43e7abd279323af313"
507 | ],
508 | "index": "pypi",
509 | "version": "==0.40.1"
510 | },
511 | "zipp": {
512 | "hashes": [
513 | "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0",
514 | "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"
515 | ],
516 | "markers": "python_version >= '3.8'",
517 | "version": "==3.16.2"
518 | }
519 | }
520 | }
521 |
--------------------------------------------------------------------------------