├── .gitignore ├── streamlit ├── config.py ├── .streamlit │ ├── .credentials.IGNORE.toml │ └── config.IGNORE.toml ├── Pipfile ├── src │ └── pages │ │ ├── test.py │ │ ├── read.py │ │ ├── create.py │ │ ├── delete.py │ │ └── update.py ├── Dockerfile ├── app.py └── Pipfile.lock ├── api ├── alembic │ ├── README │ ├── script.py.mako │ ├── versions │ │ ├── fd769291ee31_db_back_to_main_py.py │ │ ├── 00141d366319_import_db_in_models_py.py │ │ ├── 03c1a4d01b21_added_items_table.py │ │ ├── f7ce49c9785a_first_migration.py │ │ └── 17c60318b9a7_added_items_table.py │ └── env.py ├── .env ├── .env.template ├── Dockerfile ├── schema.py ├── Pipfile ├── models.py ├── alembic.ini ├── main.py └── Pipfile.lock ├── pgadmin4 ├── .env └── .env.template ├── postgres ├── .env └── .env.template ├── nginx ├── index.html ├── Dockerfile ├── auth │ └── README.md └── conf │ └── project.conf ├── docker-compose.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .htpasswd -------------------------------------------------------------------------------- /streamlit/config.py: -------------------------------------------------------------------------------- 1 | API_URL = 'http://api:8000' -------------------------------------------------------------------------------- /api/alembic/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /streamlit/.streamlit/.credentials.IGNORE.toml: -------------------------------------------------------------------------------- 1 | [general] 2 | 3 | email="" -------------------------------------------------------------------------------- /pgadmin4/.env: -------------------------------------------------------------------------------- 1 | PGADMIN_DEFAULT_EMAIL=pgadmin4@pgadmin.org 2 | PGADMIN_DEFAULT_PASSWORD=admin -------------------------------------------------------------------------------- /postgres/.env: -------------------------------------------------------------------------------- 1 | POSTGRES_USER=postgres 2 | POSTGRES_PASSWORD=postgres 3 | POSTGRES_DB=postgres -------------------------------------------------------------------------------- /pgadmin4/.env.template: -------------------------------------------------------------------------------- 1 | PGADMIN_DEFAULT_EMAIL=pgadmin4@pgadmin.org 2 | PGADMIN_DEFAULT_PASSWORD=admin -------------------------------------------------------------------------------- /postgres/.env.template: -------------------------------------------------------------------------------- 1 | POSTGRES_USER=postgres 2 | POSTGRES_PASSWORD=postgres 3 | POSTGRES_DB=postgres -------------------------------------------------------------------------------- /nginx/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

My First Heading

6 |

My first paragraph.

7 | 8 | 9 | -------------------------------------------------------------------------------- /api/.env: -------------------------------------------------------------------------------- 1 | POSTGRES_USER=postgres 2 | POSTGRES_PASSWORD=postgres 3 | POSTGRES_DB=postgres 4 | 5 | DATABASE_URL = postgresql+psycopg2://postgres:postgres@postgres:5432 -------------------------------------------------------------------------------- /api/.env.template: -------------------------------------------------------------------------------- 1 | POSTGRES_USER=postgres 2 | POSTGRES_PASSWORD=postgres 3 | POSTGRES_DB=postgres 4 | 5 | DATABASE_URL = postgresql+psycopg2://{user}:{password}@{host}:{port} -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.18.0 2 | 3 | WORKDIR /nginx 4 | COPY . /nginx 5 | 6 | COPY /conf/project.conf /etc/nginx/conf.d/ 7 | RUN rm /etc/nginx/conf.d/default.conf -------------------------------------------------------------------------------- /api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ENV PYTHONDONTWRITEBYTECODE 1 4 | ENV PYTHONUNBUFFERED 1 5 | 6 | WORKDIR /api/ 7 | 8 | RUN pip install pipenv 9 | COPY Pipfile Pipfile.lock /api/ 10 | RUN pipenv install --system --dev 11 | 12 | COPY . /api/ -------------------------------------------------------------------------------- /streamlit/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | streamlit = "*" 8 | pandas = "*" 9 | awesome-streamlit = "*" 10 | 11 | [dev-packages] 12 | 13 | [requires] 14 | python_version = "3.8" 15 | -------------------------------------------------------------------------------- /api/schema.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | class User(BaseModel): 4 | first_name: str 5 | last_name: str = None 6 | age: int 7 | 8 | class Config: 9 | orm_mode = True 10 | 11 | class Item(BaseModel): 12 | name: str 13 | price: float 14 | 15 | class Config: 16 | orm_mode = True -------------------------------------------------------------------------------- /streamlit/src/pages/test.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | import streamlit as st 5 | import pandas as pd 6 | 7 | from config import API_URL 8 | 9 | PAGE_TITLE = 'Test Page' 10 | 11 | def write(): 12 | st.markdown(f'# {PAGE_TITLE}') 13 | 14 | st.write('Test Page Loads') 15 | 16 | if __name__=='__main__': 17 | write() -------------------------------------------------------------------------------- /api/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.python.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | uvicorn = "*" 8 | fastapi = "*" 9 | fastapi-sqlalchemy = "*" 10 | pydantic = "*" 11 | alembic = "*" 12 | python-dotenv = "*" 13 | psycopg2-binary = "*" 14 | 15 | [dev-packages] 16 | 17 | [requires] 18 | python_version = "3.8" 19 | -------------------------------------------------------------------------------- /streamlit/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | WORKDIR /streamlit 4 | ENV PYTHONDONTWRITEBYTECODE 1 5 | ENV PYTHONBUFFERED 1 6 | 7 | COPY . /streamlit 8 | 9 | # Intentionally do not expose port 8501 or else people can circumvent login 10 | 11 | RUN pip install pipenv 12 | COPY Pipfile Pipfile.lock /streamlit/ 13 | RUN pipenv install --system --dev 14 | 15 | CMD streamlit run app.py -------------------------------------------------------------------------------- /nginx/auth/README.md: -------------------------------------------------------------------------------- 1 | put your .htpasswd file here & run: 2 | 3 | htpasswd -c .htpasswd 4 | 5 | to add another to an existing file (-c overwrites existing), I run: 6 | 7 | htpasswd -n 8 | 9 | then copy-paste the command-line result into the existing .htpasswd file 10 | 11 | [more here](https://httpd.apache.org/docs/2.4/programs/htpasswd.html) 12 | 13 | 14 | FYI, you may need to install apache2-utils if you don't have it already 15 | $ sudo apt update 16 | $ sudo apt install apache2-utils\ -------------------------------------------------------------------------------- /api/models.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.ext.declarative import declarative_base 2 | from sqlalchemy import Column, Integer, String, Float 3 | 4 | Base = declarative_base() 5 | 6 | class User(Base): 7 | __tablename__ = 'users' 8 | 9 | id = Column(Integer, primary_key=True, index=True) 10 | first_name = Column(String) 11 | last_name = Column(String) 12 | age = Column(Integer) 13 | 14 | class Item(Base): 15 | __tablename__ = 'items' 16 | 17 | id = Column(Integer, primary_key=True, index=True) 18 | name = Column(String) 19 | price = Column(Float) -------------------------------------------------------------------------------- /api/alembic/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /streamlit/src/pages/read.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | import streamlit as st 5 | import pandas as pd 6 | 7 | from config import API_URL 8 | 9 | PAGE_TITLE = 'Read Items' 10 | 11 | def write(): 12 | st.markdown(f'# {PAGE_TITLE}') 13 | 14 | df = read_items() 15 | st.write(df) 16 | 17 | def read_items(): 18 | url = f'{API_URL}/items/' 19 | res = requests.get(url) 20 | df = pd.read_json(res.text) 21 | return df.set_index('id') 22 | 23 | # if you just want to see the JSON, uncomment this: 24 | # res_json = json.loads(res.text) 25 | # st.write(res_json) 26 | 27 | if __name__=='__main__': 28 | write() -------------------------------------------------------------------------------- /api/alembic/versions/fd769291ee31_db_back_to_main_py.py: -------------------------------------------------------------------------------- 1 | """db back to main.py 2 | 3 | Revision ID: fd769291ee31 4 | Revises: 00141d366319 5 | Create Date: 2020-12-27 04:11:07.598009 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = 'fd769291ee31' 14 | down_revision = '00141d366319' 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | pass 22 | # ### end Alembic commands ### 23 | 24 | 25 | def downgrade(): 26 | # ### commands auto generated by Alembic - please adjust! ### 27 | pass 28 | # ### end Alembic commands ### 29 | -------------------------------------------------------------------------------- /api/alembic/versions/00141d366319_import_db_in_models_py.py: -------------------------------------------------------------------------------- 1 | """import db in models.py 2 | 3 | Revision ID: 00141d366319 4 | Revises: 17c60318b9a7 5 | Create Date: 2020-12-27 04:06:22.681896 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '00141d366319' 14 | down_revision = '17c60318b9a7' 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | pass 22 | # ### end Alembic commands ### 23 | 24 | 25 | def downgrade(): 26 | # ### commands auto generated by Alembic - please adjust! ### 27 | pass 28 | # ### end Alembic commands ### 29 | -------------------------------------------------------------------------------- /streamlit/app.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | import pandas as pd 3 | 4 | # ast credit to https://github.com/MarcSkovMadsen/awesome-streamlit 5 | import awesome_streamlit as ast 6 | import src.pages.create 7 | import src.pages.read 8 | import src.pages.update 9 | import src.pages.delete 10 | 11 | # ast.core.services.other.set_logging_format() 12 | 13 | PAGES = { 14 | 'Create': src.pages.create, 15 | 'Read': src.pages.read, 16 | 'Update': src.pages.update, 17 | 'Delete': src.pages.delete 18 | } 19 | 20 | def main(): 21 | st.sidebar.title("Navigation") 22 | selection = st.sidebar.radio("Go to", list(PAGES.keys())) 23 | 24 | page = PAGES[selection] 25 | 26 | with st.spinner(f"Loading {selection} ..."): 27 | ast.shared.components.write_page(page) 28 | 29 | if __name__=='__main__': 30 | main() -------------------------------------------------------------------------------- /streamlit/src/pages/create.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | import streamlit as st 5 | import pandas as pd 6 | 7 | from config import API_URL 8 | 9 | PAGE_TITLE = 'Create Item' 10 | 11 | def write(): 12 | st.markdown(f'# {PAGE_TITLE}') 13 | 14 | st.markdown('## Enter item details') 15 | 16 | item = {} 17 | 18 | item['name'] = st.text_input( 19 | label='Item Name', 20 | value='') 21 | 22 | item['price'] = st.number_input( 23 | label='Item Price ($USD)', 24 | ) 25 | 26 | create = st.button(label='Create') 27 | 28 | if create: 29 | item = submit_item(item) 30 | if item: 31 | st.write(item) 32 | create = False 33 | 34 | def submit_item(item): 35 | url = f'{API_URL}/item/' 36 | res = requests.post(url, json=item) 37 | return json.loads(res.text) 38 | 39 | if __name__=='__main__': 40 | write() -------------------------------------------------------------------------------- /api/alembic/versions/03c1a4d01b21_added_items_table.py: -------------------------------------------------------------------------------- 1 | """Added items table 2 | 3 | Revision ID: 03c1a4d01b21 4 | Revises: f7ce49c9785a 5 | Create Date: 2020-12-27 02:02:16.100795 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '03c1a4d01b21' 14 | down_revision = 'f7ce49c9785a' 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.create_table('iems', 22 | sa.Column('id', sa.Integer(), nullable=False), 23 | sa.Column('name', sa.String(), nullable=True), 24 | sa.Column('price', sa.Float(), nullable=True), 25 | sa.PrimaryKeyConstraint('id') 26 | ) 27 | op.create_index(op.f('ix_iems_id'), 'iems', ['id'], unique=False) 28 | # ### end Alembic commands ### 29 | 30 | 31 | def downgrade(): 32 | # ### commands auto generated by Alembic - please adjust! ### 33 | op.drop_index(op.f('ix_iems_id'), table_name='iems') 34 | op.drop_table('iems') 35 | # ### end Alembic commands ### 36 | -------------------------------------------------------------------------------- /api/alembic/versions/f7ce49c9785a_first_migration.py: -------------------------------------------------------------------------------- 1 | """First migration 2 | 3 | Revision ID: f7ce49c9785a 4 | Revises: 5 | Create Date: 2020-12-26 21:28:35.842453 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = 'f7ce49c9785a' 14 | down_revision = None 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.create_table('users', 22 | sa.Column('id', sa.Integer(), nullable=False), 23 | sa.Column('first_name', sa.String(), nullable=True), 24 | sa.Column('last_name', sa.String(), nullable=True), 25 | sa.Column('age', sa.Integer(), nullable=True), 26 | sa.PrimaryKeyConstraint('id') 27 | ) 28 | op.create_index(op.f('ix_users_id'), 'users', ['id'], unique=False) 29 | # ### end Alembic commands ### 30 | 31 | 32 | def downgrade(): 33 | # ### commands auto generated by Alembic - please adjust! ### 34 | op.drop_index(op.f('ix_users_id'), table_name='users') 35 | op.drop_table('users') 36 | # ### end Alembic commands ### 37 | -------------------------------------------------------------------------------- /streamlit/src/pages/delete.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | import streamlit as st 5 | import pandas as pd 6 | 7 | from config import API_URL 8 | 9 | PAGE_TITLE = 'Delete Item' 10 | 11 | def write(): 12 | st.markdown(f'# {PAGE_TITLE}') 13 | 14 | items = read_items() 15 | items.set_index('id', inplace=True) 16 | st.write(items) 17 | 18 | namecol='name' 19 | pricecol='price' 20 | 21 | selected_id = st.selectbox( 22 | label='Choose Item to Update', 23 | options=list(items.index), 24 | format_func=lambda x: f'{x}: {items.loc[x,namecol]} (${items.loc[x,pricecol]})') 25 | 26 | delete = st.button(label='Delete') 27 | 28 | if delete: 29 | deleted_item = delete_item(id=selected_id) 30 | if deleted_item: 31 | st.write(deleted_item) 32 | delete = False 33 | 34 | def delete_item(id): 35 | url = f'{API_URL}/item/delete/{id}' 36 | res = requests.post(url) 37 | return json.loads(res.text) 38 | 39 | def read_items(): 40 | url = f'{API_URL}/items/' 41 | res = requests.get(url) 42 | return pd.read_json(res.text) 43 | 44 | if __name__=='__main__': 45 | write() -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | streamlit: 5 | volumes: 6 | - ./streamlit/:/streamlit/ 7 | build: 8 | context: ./streamlit 9 | dockerfile: Dockerfile 10 | container_name: streamlit 11 | restart: always 12 | # do not publicly expose port 8501 13 | # ports: 14 | # - "8501:8501" 15 | depends_on: 16 | - api 17 | 18 | reverse: 19 | container_name: reverse 20 | hostname: reverse 21 | restart: always 22 | build: ./nginx 23 | ports: 24 | - "80:80" 25 | - "443:443" 26 | depends_on: 27 | - streamlit 28 | - postgres 29 | - api 30 | 31 | postgres: 32 | image: postgres:12 33 | volumes: 34 | - postgres_data:/var/lib/postgresql/data/ 35 | # ports: 36 | # - "5432:5432" 37 | env_file: 38 | - ./postgres/.env 39 | 40 | api: 41 | build: 42 | context: ./api 43 | dockerfile: Dockerfile 44 | volumes: 45 | - ./api/:/api/ 46 | command: bash -c "alembic upgrade head && uvicorn main:app --host 0.0.0.0 --port 8000 --reload" 47 | # ports: 48 | # - "8000:8000" 49 | depends_on: 50 | - postgres 51 | 52 | pgadmin4: 53 | container_name: pgadmin4 54 | image: dpage/pgadmin4 55 | env_file: 56 | - ./pgadmin4/.env 57 | # ports: 58 | # - "5050:80" 59 | depends_on: 60 | - postgres 61 | 62 | volumes: 63 | postgres_data: -------------------------------------------------------------------------------- /api/alembic/versions/17c60318b9a7_added_items_table.py: -------------------------------------------------------------------------------- 1 | """Added items table 2 | 3 | Revision ID: 17c60318b9a7 4 | Revises: 03c1a4d01b21 5 | Create Date: 2020-12-27 02:07:01.214070 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | from sqlalchemy.dialects import postgresql 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '17c60318b9a7' 14 | down_revision = '03c1a4d01b21' 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.create_table('items', 22 | sa.Column('id', sa.Integer(), nullable=False), 23 | sa.Column('name', sa.String(), nullable=True), 24 | sa.Column('price', sa.Float(), nullable=True), 25 | sa.PrimaryKeyConstraint('id') 26 | ) 27 | op.create_index(op.f('ix_items_id'), 'items', ['id'], unique=False) 28 | op.drop_index('ix_iems_id', table_name='iems') 29 | op.drop_table('iems') 30 | # ### end Alembic commands ### 31 | 32 | 33 | def downgrade(): 34 | # ### commands auto generated by Alembic - please adjust! ### 35 | op.create_table('iems', 36 | sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), 37 | sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=True), 38 | sa.Column('price', postgresql.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True), 39 | sa.PrimaryKeyConstraint('id', name='iems_pkey') 40 | ) 41 | op.create_index('ix_iems_id', 'iems', ['id'], unique=False) 42 | op.drop_index(op.f('ix_items_id'), table_name='items') 43 | op.drop_table('items') 44 | # ### end Alembic commands ### 45 | -------------------------------------------------------------------------------- /streamlit/src/pages/update.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | import streamlit as st 5 | import pandas as pd 6 | 7 | from config import API_URL 8 | 9 | PAGE_TITLE = 'Update Item' 10 | 11 | def write(): 12 | st.markdown(f'# {PAGE_TITLE}') 13 | 14 | items = read_items() 15 | items.set_index('id', inplace=True) 16 | st.write(items) 17 | 18 | namecol='name' 19 | pricecol='price' 20 | 21 | selected_id = st.selectbox( 22 | label='Choose Item to Update', 23 | options=list(items.index), 24 | format_func=lambda x: f'{x}: {items.loc[x,namecol]} (${items.loc[x,pricecol]})') 25 | 26 | item_original = { 27 | 'name': items.loc[selected_id,namecol], 28 | 'price': items.loc[selected_id,pricecol], 29 | } 30 | 31 | item_update = {} 32 | 33 | item_update['name'] = st.text_input( 34 | label='Update Item Name', 35 | value=item_original['name']) 36 | 37 | item_update['price'] = st.number_input( 38 | label='Update Item Price ($USD)', 39 | value=item_original['price'] 40 | ) 41 | 42 | update = st.button(label='Update') 43 | 44 | if update: 45 | updated_item = update_item(item=item_update, id=selected_id) 46 | if updated_item: 47 | st.write(updated_item) 48 | update = False 49 | 50 | def update_item(item, id): 51 | url = f'{API_URL}/item/update/{id}' 52 | res = requests.post(url, json=item) 53 | return json.loads(res.text) 54 | 55 | def read_items(): 56 | url = f'{API_URL}/items/' 57 | res = requests.get(url) 58 | return pd.read_json(res.text) 59 | 60 | if __name__=='__main__': 61 | write() -------------------------------------------------------------------------------- /api/alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # path to migration scripts 5 | script_location = alembic 6 | 7 | # template used to generate migration files 8 | # file_template = %%(rev)s_%%(slug)s 9 | 10 | # timezone to use when rendering the date 11 | # within the migration file as well as the filename. 12 | # string value is passed to dateutil.tz.gettz() 13 | # leave blank for localtime 14 | # timezone = 15 | 16 | # max length of characters to apply to the 17 | # "slug" field 18 | # truncate_slug_length = 40 19 | 20 | # set to 'true' to run the environment during 21 | # the 'revision' command, regardless of autogenerate 22 | # revision_environment = false 23 | 24 | # set to 'true' to allow .pyc and .pyo files without 25 | # a source .py file to be detected as revisions in the 26 | # versions/ directory 27 | # sourceless = false 28 | 29 | # version location specification; this defaults 30 | # to alembic/versions. When using multiple version 31 | # directories, initial revisions must be specified with --version-path 32 | # version_locations = %(here)s/bar %(here)s/bat alembic/versions 33 | 34 | # the output encoding used when revision files 35 | # are written from script.py.mako 36 | # output_encoding = utf-8 37 | 38 | sqlalchemy.url = 39 | 40 | 41 | [post_write_hooks] 42 | # post_write_hooks defines scripts or Python functions that are run 43 | # on newly generated revision scripts. See the documentation for further 44 | # detail and examples 45 | 46 | # format using "black" - use the console_scripts runner, against the "black" entrypoint 47 | # hooks=black 48 | # black.type=console_scripts 49 | # black.entrypoint=black 50 | # black.options=-l 79 51 | 52 | # Logging configuration 53 | [loggers] 54 | keys = root,sqlalchemy,alembic 55 | 56 | [handlers] 57 | keys = console 58 | 59 | [formatters] 60 | keys = generic 61 | 62 | [logger_root] 63 | level = WARN 64 | handlers = console 65 | qualname = 66 | 67 | [logger_sqlalchemy] 68 | level = WARN 69 | handlers = 70 | qualname = sqlalchemy.engine 71 | 72 | [logger_alembic] 73 | level = INFO 74 | handlers = 75 | qualname = alembic 76 | 77 | [handler_console] 78 | class = StreamHandler 79 | args = (sys.stderr,) 80 | level = NOTSET 81 | formatter = generic 82 | 83 | [formatter_generic] 84 | format = %(levelname)-5.5s [%(name)s] %(message)s 85 | datefmt = %H:%M:%S 86 | -------------------------------------------------------------------------------- /api/main.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | from fastapi import FastAPI 3 | from fastapi.openapi.utils import get_openapi 4 | 5 | import os 6 | from fastapi_sqlalchemy import DBSessionMiddleware 7 | from fastapi_sqlalchemy import db 8 | from dotenv import load_dotenv 9 | 10 | # Model Imports 11 | from models import User as ModelUser 12 | from models import Item as ModelItem 13 | 14 | # Schema Imports 15 | from schema import User as SchemaUser 16 | from schema import Item as SchemaItem 17 | 18 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 19 | load_dotenv(os.path.join(BASE_DIR,'.env')) 20 | 21 | app = FastAPI( 22 | openapi_url="/api/v1/openapi.json", 23 | root_path='/api/v1' 24 | ) 25 | 26 | app.add_middleware( 27 | DBSessionMiddleware, 28 | db_url=os.environ['DATABASE_URL']) 29 | 30 | # arbitrary user resource I built when following a tutorial - not used in streamlit CRUD example 31 | @app.post("/user/", response_model=SchemaUser) 32 | def create_user(user: SchemaUser): 33 | db_user = ModelUser( 34 | first_name=user.first_name, 35 | last_name=user.last_name, 36 | age=user.age) 37 | db.session.add(db_user) 38 | db.session.commit() 39 | return db_user 40 | 41 | # create an item 42 | @app.post("/item/", response_model=SchemaItem) 43 | def create_item(item: SchemaItem): 44 | db_item = ModelItem( 45 | name=item.name, 46 | price=item.price) 47 | db.session.add(db_item) 48 | db.session.commit() 49 | return db_item 50 | 51 | # update an existing item 52 | @app.post("/item/update/{id}", response_model=SchemaItem) 53 | def update_item(id: int, item: SchemaItem): 54 | db_item = db.session.query(ModelItem).filter(ModelItem.id == id).first() 55 | db_item.name = item.name 56 | db_item.price = item.price 57 | db.session.commit() 58 | return db_item 59 | 60 | # delete an existing item 61 | @app.post("/item/delete/{id}", response_model=SchemaItem) 62 | def delete_item(id: int): 63 | db_item = db.session.query(ModelItem).filter(ModelItem.id == id).first() 64 | db.session.delete(db_item) 65 | db.session.commit() 66 | return db_item 67 | 68 | # get all items 69 | @app.get('/items/') 70 | def get_items(): 71 | db_items = db.session.query(ModelItem).all() 72 | return db_items 73 | 74 | if __name__ == "__main__": 75 | uvicorn.run(app, host="127.0.0.1", port=8000) -------------------------------------------------------------------------------- /nginx/conf/project.conf: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen 80; 4 | server_name reverse; 5 | 6 | # ---------------- PGADMIN CONFIGURAITONS ---------------- # 7 | location ^~ /pgadmin4/ { 8 | proxy_pass http://pgadmin4:80/; 9 | proxy_redirect off; 10 | proxy_set_header X-Script-Name /pgadmin4; 11 | proxy_set_header Host $host; 12 | proxy_set_header X-Real-IP $remote_addr; 13 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 14 | } 15 | # ------------------------------------------- END ---------------- # 16 | 17 | 18 | # ---------------- API CONFIGURAITONS ---------------- # 19 | location ^~ /api/v1/ { 20 | # https://github.com/tiangolo/fastapi/issues/102#issuecomment-739520277 21 | auth_basic "closed site"; 22 | auth_basic_user_file /nginx/auth/.htpasswd; 23 | proxy_set_header Host $http_host; 24 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 25 | proxy_set_header X-Forwarded-Proto $scheme; 26 | proxy_redirect off; 27 | proxy_buffering off; 28 | proxy_pass http://api:8000/; 29 | } 30 | # ------------------------------------------- END ---------------- # 31 | 32 | 33 | # ---------------- STREAMLIT CONFIGURAITONS ---------------- # 34 | location / { 35 | auth_basic "closed site"; 36 | auth_basic_user_file /nginx/auth/.htpasswd; 37 | proxy_pass http://streamlit:8501/; 38 | } 39 | 40 | location ^~ /static { 41 | proxy_pass http://streamlit:8501/static/; 42 | } 43 | location ^~ /healthz { 44 | proxy_pass http://streamlit:8501/healthz; 45 | } 46 | location ^~ /vendor { 47 | proxy_pass http://streamlit:8501/vendor; 48 | } 49 | location /stream { 50 | proxy_pass http://streamlit:8501/stream; 51 | proxy_http_version 1.1; 52 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 53 | proxy_set_header Host $host; 54 | proxy_set_header Upgrade $http_upgrade; 55 | proxy_set_header Connection "upgrade"; 56 | proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions; 57 | proxy_read_timeout 86400; 58 | # testing these 59 | proxy_set_header X-Real-IP $remote_addr; 60 | proxy_set_header X-Forwarded-Proto $scheme; 61 | } 62 | # ------------------------------------------- END ---------------- # 63 | 64 | } -------------------------------------------------------------------------------- /api/alembic/env.py: -------------------------------------------------------------------------------- 1 | from logging.config import fileConfig 2 | 3 | from sqlalchemy import engine_from_config 4 | from sqlalchemy import pool 5 | 6 | from alembic import context 7 | 8 | # ---------------- added code here -------------------------# 9 | import os, sys 10 | from dotenv import load_dotenv 11 | 12 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 13 | load_dotenv(os.path.join(BASE_DIR, ".env")) 14 | sys.path.append(BASE_DIR) 15 | 16 | #------------------------------------------------------------# 17 | 18 | # this is the Alembic Config object, which provides 19 | # access to the values within the .ini file in use. 20 | config = context.config 21 | 22 | # ---------------- added code here -------------------------# 23 | # this will overwrite the ini-file sqlalchemy.url path 24 | # with the path given in the config of the main code 25 | config.set_main_option('sqlalchemy.url', os.environ['DATABASE_URL']) 26 | 27 | #------------------------------------------------------------# 28 | 29 | # Interpret the config file for Python logging. 30 | # This line sets up loggers basically. 31 | fileConfig(config.config_file_name) 32 | 33 | # add your model's MetaData object here 34 | # for 'autogenerate' support 35 | # from myapp import mymodel 36 | # target_metadata = mymodel.Base.metadata 37 | 38 | # ---------------- added code here -------------------------# 39 | import models 40 | #------------------------------------------------------------# 41 | 42 | 43 | # ---------------- added code here -------------------------# 44 | # was target_metadata = None 45 | target_metadata = models.Base.metadata 46 | #------------------------------------------------------------# 47 | 48 | # other values from the config, defined by the needs of env.py, 49 | # can be acquired: 50 | # my_important_option = config.get_main_option("my_important_option") 51 | # ... etc. 52 | 53 | 54 | def run_migrations_offline(): 55 | """Run migrations in 'offline' mode. 56 | 57 | This configures the context with just a URL 58 | and not an Engine, though an Engine is acceptable 59 | here as well. By skipping the Engine creation 60 | we don't even need a DBAPI to be available. 61 | 62 | Calls to context.execute() here emit the given string to the 63 | script output. 64 | 65 | """ 66 | url = config.get_main_option("sqlalchemy.url") 67 | context.configure( 68 | url=url, 69 | target_metadata=target_metadata, 70 | literal_binds=True, 71 | dialect_opts={"paramstyle": "named"}, 72 | ) 73 | 74 | with context.begin_transaction(): 75 | context.run_migrations() 76 | 77 | 78 | def run_migrations_online(): 79 | """Run migrations in 'online' mode. 80 | 81 | In this scenario we need to create an Engine 82 | and associate a connection with the context. 83 | 84 | """ 85 | connectable = engine_from_config( 86 | config.get_section(config.config_ini_section), 87 | prefix="sqlalchemy.", 88 | poolclass=pool.NullPool, 89 | ) 90 | 91 | with connectable.connect() as connection: 92 | context.configure( 93 | connection=connection, target_metadata=target_metadata 94 | ) 95 | 96 | with context.begin_transaction(): 97 | context.run_migrations() 98 | 99 | 100 | if context.is_offline_mode(): 101 | run_migrations_offline() 102 | else: 103 | run_migrations_online() 104 | -------------------------------------------------------------------------------- /streamlit/.streamlit/config.IGNORE.toml: -------------------------------------------------------------------------------- 1 | # Below are all the sections and options you can have in ~/.streamlit/config.toml. 2 | 3 | [global] 4 | 5 | # By default, Streamlit checks if the Python watchdog module is available and, if not, prints a warning asking for you to install it. The watchdog module is not required, but highly recommended. It improves Streamlit's ability to detect changes to files in your filesystem. 6 | # If you'd like to turn off this warning, set this to True. 7 | # Default: false 8 | disableWatchdogWarning = false 9 | 10 | # Configure the ability to share apps to the cloud. 11 | # Should be set to one of these values: - "off" : turn off sharing. - "s3" : share to S3, based on the settings under the [s3] section of this config file. 12 | # Default: "off" 13 | sharingMode = "off" 14 | 15 | # If True, will show a warning when you run a Streamlit-enabled script via "python my_script.py". 16 | # Default: true 17 | showWarningOnDirectExecution = true 18 | 19 | 20 | [client] 21 | 22 | # Whether to enable st.cache. 23 | # Default: true 24 | caching = true 25 | 26 | # If false, makes your Streamlit script not draw to a Streamlit app. 27 | # Default: true 28 | displayEnabled = true 29 | 30 | 31 | [runner] 32 | 33 | # Allows you to type a variable or string by itself in a single line of Python code to write it to the app. 34 | # Default: true 35 | magicEnabled = true 36 | 37 | # Install a Python tracer to allow you to stop or pause your script at any point and introspect it. As a side-effect, this slows down your script's execution. 38 | # Default: false 39 | installTracer = false 40 | 41 | # Sets the MPLBACKEND environment variable to Agg inside Streamlit to prevent Python crashing. 42 | # Default: true 43 | fixMatplotlib = true 44 | 45 | 46 | [server] 47 | 48 | # List of folders that should not be watched for changes. Relative paths will be taken as relative to the current working directory. 49 | # Example: ['/home/user1/env', 'relative/path/to/folder'] 50 | # Default: [] 51 | folderWatchBlacklist = [''] 52 | 53 | enableWebsocketCompression = false 54 | 55 | 56 | 57 | # If false, will attempt to open a browser window on start. 58 | # Default: false unless (1) we are on a Linux box where DISPLAY is unset, or (2) server.liveSave is set. 59 | headless = true 60 | 61 | # Immediately share the app in such a way that enables live monitoring, and post-run analysis. 62 | # Default: false 63 | liveSave = false 64 | 65 | # Automatically rerun script when the file is modified on disk. 66 | # Default: false 67 | runOnSave = false 68 | 69 | # The port where the server will listen for client and browser connections. 70 | # Default: 8501 71 | port = 8501 72 | 73 | # Enables support for Cross-Origin Request Sharing, for added security. 74 | # Default: true 75 | enableCORS = false 76 | 77 | 78 | [browser] 79 | 80 | # Internet address of the server server that the browser should connect to. Can be IP address or DNS name. 81 | # Default: 'localhost' 82 | serverAddress = 'streamlit' 83 | 84 | # Whether to send usage statistics to Streamlit. 85 | # Default: true 86 | gatherUsageStats = true 87 | 88 | # Port that the browser should use to connect to the server when in liveSave mode. 89 | # Default: whatever value is set in server.port. 90 | serverPort = 80 91 | 92 | [s3] 93 | 94 | # Name of the AWS S3 bucket to save apps. 95 | # Default: (unset) 96 | #bucket = 97 | 98 | # URL root for external view of Streamlit apps. 99 | # Default: (unset) 100 | #url = 101 | 102 | # Access key to write to the S3 bucket. 103 | # Leave unset if you want to use an AWS profile. 104 | # Default: (unset) 105 | #accessKeyId = 106 | 107 | # Secret access key to write to the S3 bucket. 108 | # Leave unset if you want to use an AWS profile. 109 | # Default: (unset) 110 | #secretAccessKey = 111 | 112 | # The "subdirectory" within the S3 bucket where to save apps. 113 | # S3 calls paths "keys" which is why the keyPrefix is like a subdirectory. Use "" to mean the root directory. 114 | # Default: "" 115 | keyPrefix = "" 116 | 117 | # AWS region where the bucket is located, e.g. "us-west-2". 118 | # Default: (unset) 119 | #region = 120 | 121 | # AWS credentials profile to use. 122 | # Leave unset to use your default profile. 123 | # Default: (unset) 124 | #profile = -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Authenticated Full-Stack Streamlit 2 | 3 | ## Notes for Users 4 | 5 | ### Rationale & Features 6 | [Streamlit](https://www.streamlit.io/a) is great, but it doesn't natively support user authentication. This repo leverages Nginx as a reverse proxy layer with enterprise-grade authentication. Nginx itself includes the ability to authenticate with most protocols like OAuth2, SAML, etc. which you should be able to implement in project.conf. However, this particular repo authenticates with Nginx's auth_basic, which is just a hashed username & password in a file (more below under first-time setup). If that's all you want, you can delete the folders that aren't "nginx" or "streamlit" and also remove any reference to them in the docker-compose.yml file. 7 | 8 | But I also want a bit more than that. I also want a DB and an API to interact with the DB for a full-stack feel even for my smallest Streamlit applications. That's what the "api", "pgadmin4", and "postgres" folders / docker-compose services do. Ultimately, the goal is to separate presentation (streamlit) from logic, piping & persistence (FastAPI / Postgres). When presenting information in Streamlit, you process as little as possible. Ideally, your database and API calls should get most of the work done, be it with SQL queries to the DB or POST payload parameters to the API. This way, you'll be setup for an easy transition to a more robust Flask/Django app once you're finished prototyping in Streamlit. Or, you can just keep using Streamlit! 9 | 10 | - Built on back of docker & docker-compose, so it's hopefully easy to deploy (see first-time setup instructions below) 11 | - Streamlit application that interacts with an internal API powered by [FastAPI](https://fastapi.tiangolo.com/) 12 | - Database is postgresql 13 | - pgadmin at /pgadmin4/ 14 | - This works on a server like a Digitalocean droplet, but doesn't work on localhost. This is because I can't seem to make the :80 redirect work with local nginx. 15 | - Nginx serves everything. See project.conf for the routes. Should be easy to read & follow-along the logic to add other services. Should even be easy to serve multiple streamlit applications with this 16 | 17 | ### First-time setup 18 | 1. The subfolders for the API, PGAdmin4, and Postgres each have ".env.template" files that you'll use to create your own ".env" files in each corresponding subdirectory. The ".env" files themselves are .gitignore'd. So, copy the .env.template files into new .env files. You should change out these default values with the real environment variables you're looking to use 19 | 2. you should gitignore your .env files so you aren't sharing any important credentials with the universe 20 | 3. create htpasswd .htpasswd -c in the nginx > auth folder. More details in the READAME at nginx/auth. Also make sure that .htpasswd is in your gitignore, you probably don't want to share your hashed password with the world. 21 | 4. for subsequent users, you can print to command line by switching -c to -n and then copy-pasting the hashed password result 22 | 5. when you have made all the .env files and the .htpasswd file, build your docker. This can take some time! 23 | 24 | docker-compose up --build 25 | 6. Once you've built the app, you can run it again and exclude the slow build process with 26 | 27 | docker-compose up 28 | 29 | 7. If you need more help with docker, see below resources 30 | 8. See pgadmin4 referenced guide below for instructions on connecting DB to pgadmin4 if you need help with that 31 | 32 | ### Default Implementaion 33 | This repo shows a default use-case where you can create, read, update, delete a basic "item" example. You can see how a RESTFUL configuration might flow between Streamlit, FastAPI, and Postgresql. With the added benefit of /pgadmin4/ to confirm your database is properly updated (see below reference resources on how to connect pgadmin4). 34 | 35 | ### Authentication 36 | The nginx project.conf file puts everything behind basic htpasswd authentication by including this in the top "server" block. Again, see the README in the repo folder nginx/auth for details on how to create the (super easy to make) .htpasswd file that drives this basic authentication 37 | 38 | auth_basic "closed site"; 39 | auth_basic_user_file /nginx/auth/.htpasswd; 40 | 41 | ## Guides Referenced when Building This 42 | Here's some further detail if I'm not clear enough on anything. Thanks to everybody who wrote the guides below, they taught me a lot. 43 | 44 | ### Alembic 45 | When you run your first alembic migration, type this: 46 | docker-compose run [service name] alembic revision --autogenerate -m "First migration" 47 | 48 | And when you make other revisions you can just type in: 49 | docker-compose run [service name] alembic revision --autogenerate 50 | 51 | replace [service name] with the docker-compose service name. In this case, it's called "api" per docker-compose.yaml in the top directory 52 | 53 | [Reference I used to learn alembic in this context](https://ahmed-nafies.medium.com/fastapi-with-sqlalchemy-postgresql-and-alembic-and-of-course-docker-f2b7411ee396) 54 | 55 | ### FastAPI Quirks 56 | 1. [How to get openapi.json to load, required for the /docs/ endpoint](https://github.com/tiangolo/fastapi/issues/102#issuecomment-739520277) 57 | 2. [But also need to define root-path="/api/v1" for /docs to work](https://fastapi.tiangolo.com/advanced/behind-a-proxy/) 58 | 59 | ### PGAdmin4 References when Setting This Up: 60 | Connect to postgres server in pgadmin(ctrl+f for "connect to a database server,": https://ahmed-nafies.medium.com/fastapi-with-sqlalchemy-postgresql-and-alembic-and-of-course-docker-f2b7411ee396 61 | 62 | - [Fully comprehensive, did this one first. But also see below. Nginx should port_forward to 80, not 5050, for the GUI](https://www.enterprisedb.com/postgres-tutorials/reverse-proxying-pgadmin) 63 | - [But needs to do the port 80 in nginx config, not the 5050 for me to use it](https://stackoverflow.com/questions/61802782/reverse-proxy-in-docker-using-nginx-for-pgadmin4) 64 | 65 | ### Docker Basics 66 | In case you are unfamiliar with docker, [Jeff Astor has a really nice series](https://www.jeffastor.com/blog/pairing-a-postgresql-db-with-your-dockerized-fastapi-app) on "enough Docker to get by." This is a link to part two, which has some helpful commands. But you might want to rewind to Part 1, which is linked at the top of his blog post. 67 | 68 | ### Awesome-streamilt 69 | Shoutout to Marc, providing a great workaround for pagination via [awesome-streamlit (pypi)](https://pypi.org/project/awesome-streamlit/) which I gladly repurposed here. And of course, here is the [awesome-streamlit github repo](https://github.com/MarcSkovMadsen/awesome-streamlit). 70 | 71 | ## Next Steps 72 | - In production, I'll look to replace the 'auth_basic' login using an htpasswd with an 'auth_requeset' SP-initiated SAML 2.0 SSO login flow. Then I'll host the streamlit apps at different endpoints, restricting access to a user whitelist. -------------------------------------------------------------------------------- /api/Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "c3a26ffeebdf6d8984c7119813650280a831778aa990294f4d377321e4f2abad" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.8" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.python.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "alembic": { 20 | "hashes": [ 21 | "sha256:4e02ed2aa796bd179965041afa092c55b51fb077de19d61835673cc80672c01c", 22 | "sha256:5334f32314fb2a56d86b4c4dd1ae34b08c03cae4cb888bc699942104d66bc245" 23 | ], 24 | "index": "pypi", 25 | "version": "==1.4.3" 26 | }, 27 | "click": { 28 | "hashes": [ 29 | "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", 30 | "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" 31 | ], 32 | "version": "==7.1.2" 33 | }, 34 | "fastapi": { 35 | "hashes": [ 36 | "sha256:63c4592f5ef3edf30afa9a44fa7c6b7ccb20e0d3f68cd9eba07b44d552058dcb", 37 | "sha256:98d8ea9591d8512fdadf255d2a8fa56515cdd8624dca4af369da73727409508e" 38 | ], 39 | "index": "pypi", 40 | "version": "==0.63.0" 41 | }, 42 | "fastapi-sqlalchemy": { 43 | "hashes": [ 44 | "sha256:7a9d44e46cbc73c3f5ee8c444f7e0bcd3d01370a878740abd4cd4d2e900ce9af", 45 | "sha256:d3bfc6d9388a73a2c3726bc6bd7764cd82debfa71c16e3991c544b9701f48d96" 46 | ], 47 | "index": "pypi", 48 | "version": "==0.2.1" 49 | }, 50 | "h11": { 51 | "hashes": [ 52 | "sha256:3c6c61d69c6f13d41f1b80ab0322f1872702a3ba26e12aa864c928f6a43fbaab", 53 | "sha256:ab6c335e1b6ef34b205d5ca3e228c9299cc7218b049819ec84a388c2525e5d87" 54 | ], 55 | "version": "==0.11.0" 56 | }, 57 | "mako": { 58 | "hashes": [ 59 | "sha256:8195c8c1400ceb53496064314c6736719c6f25e7479cd24c77be3d9361cddc27", 60 | "sha256:93729a258e4ff0747c876bd9e20df1b9758028946e976324ccd2d68245c7b6a9" 61 | ], 62 | "version": "==1.1.3" 63 | }, 64 | "markupsafe": { 65 | "hashes": [ 66 | "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", 67 | "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", 68 | "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", 69 | "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", 70 | "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", 71 | "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", 72 | "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", 73 | "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", 74 | "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", 75 | "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", 76 | "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", 77 | "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", 78 | "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", 79 | "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", 80 | "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", 81 | "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", 82 | "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", 83 | "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", 84 | "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", 85 | "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", 86 | "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", 87 | "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", 88 | "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", 89 | "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", 90 | "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", 91 | "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", 92 | "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", 93 | "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", 94 | "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", 95 | "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", 96 | "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", 97 | "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", 98 | "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" 99 | ], 100 | "version": "==1.1.1" 101 | }, 102 | "psycopg2-binary": { 103 | "hashes": [ 104 | "sha256:0deac2af1a587ae12836aa07970f5cb91964f05a7c6cdb69d8425ff4c15d4e2c", 105 | "sha256:0e4dc3d5996760104746e6cfcdb519d9d2cd27c738296525d5867ea695774e67", 106 | "sha256:11b9c0ebce097180129e422379b824ae21c8f2a6596b159c7659e2e5a00e1aa0", 107 | "sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6", 108 | "sha256:1fabed9ea2acc4efe4671b92c669a213db744d2af8a9fc5d69a8e9bc14b7a9db", 109 | "sha256:2dac98e85565d5688e8ab7bdea5446674a83a3945a8f416ad0110018d1501b94", 110 | "sha256:42ec1035841b389e8cc3692277a0bd81cdfe0b65d575a2c8862cec7a80e62e52", 111 | "sha256:6422f2ff0919fd720195f64ffd8f924c1395d30f9a495f31e2392c2efafb5056", 112 | "sha256:6a32f3a4cb2f6e1a0b15215f448e8ce2da192fd4ff35084d80d5e39da683e79b", 113 | "sha256:7312e931b90fe14f925729cde58022f5d034241918a5c4f9797cac62f6b3a9dd", 114 | "sha256:7d92a09b788cbb1aec325af5fcba9fed7203897bbd9269d5691bb1e3bce29550", 115 | "sha256:833709a5c66ca52f1d21d41865a637223b368c0ee76ea54ca5bad6f2526c7679", 116 | "sha256:89705f45ce07b2dfa806ee84439ec67c5d9a0ef20154e0e475e2b2ed392a5b83", 117 | "sha256:8cd0fb36c7412996859cb4606a35969dd01f4ea34d9812a141cd920c3b18be77", 118 | "sha256:950bc22bb56ee6ff142a2cb9ee980b571dd0912b0334aa3fe0fe3788d860bea2", 119 | "sha256:a0c50db33c32594305b0ef9abc0cb7db13de7621d2cadf8392a1d9b3c437ef77", 120 | "sha256:a0eb43a07386c3f1f1ebb4dc7aafb13f67188eab896e7397aa1ee95a9c884eb2", 121 | "sha256:aaa4213c862f0ef00022751161df35804127b78adf4a2755b9f991a507e425fd", 122 | "sha256:ac0c682111fbf404525dfc0f18a8b5f11be52657d4f96e9fcb75daf4f3984859", 123 | "sha256:ad20d2eb875aaa1ea6d0f2916949f5c08a19c74d05b16ce6ebf6d24f2c9f75d1", 124 | "sha256:b4afc542c0ac0db720cf516dd20c0846f71c248d2b3d21013aa0d4ef9c71ca25", 125 | "sha256:b8a3715b3c4e604bcc94c90a825cd7f5635417453b253499664f784fc4da0152", 126 | "sha256:ba28584e6bca48c59eecbf7efb1576ca214b47f05194646b081717fa628dfddf", 127 | "sha256:ba381aec3a5dc29634f20692349d73f2d21f17653bda1decf0b52b11d694541f", 128 | "sha256:bd1be66dde2b82f80afb9459fc618216753f67109b859a361cf7def5c7968729", 129 | "sha256:c2507d796fca339c8fb03216364cca68d87e037c1f774977c8fc377627d01c71", 130 | "sha256:cec7e622ebc545dbb4564e483dd20e4e404da17ae07e06f3e780b2dacd5cee66", 131 | "sha256:d14b140a4439d816e3b1229a4a525df917d6ea22a0771a2a78332273fd9528a4", 132 | "sha256:d1b4ab59e02d9008efe10ceabd0b31e79519da6fb67f7d8e8977118832d0f449", 133 | "sha256:d5227b229005a696cc67676e24c214740efd90b148de5733419ac9aaba3773da", 134 | "sha256:e1f57aa70d3f7cc6947fd88636a481638263ba04a742b4a37dd25c373e41491a", 135 | "sha256:e74a55f6bad0e7d3968399deb50f61f4db1926acf4a6d83beaaa7df986f48b1c", 136 | "sha256:e82aba2188b9ba309fd8e271702bd0d0fc9148ae3150532bbb474f4590039ffb", 137 | "sha256:ee69dad2c7155756ad114c02db06002f4cded41132cc51378e57aad79cc8e4f4", 138 | "sha256:f5ab93a2cb2d8338b1674be43b442a7f544a0971da062a5da774ed40587f18f5" 139 | ], 140 | "index": "pypi", 141 | "version": "==2.8.6" 142 | }, 143 | "pydantic": { 144 | "hashes": [ 145 | "sha256:025bf13ce27990acc059d0c5be46f416fc9b293f45363b3d19855165fee1874f", 146 | "sha256:185e18134bec5ef43351149fe34fda4758e53d05bb8ea4d5928f0720997b79ef", 147 | "sha256:213125b7e9e64713d16d988d10997dabc6a1f73f3991e1ff8e35ebb1409c7dc9", 148 | "sha256:24ca47365be2a5a3cc3f4a26dcc755bcdc9f0036f55dcedbd55663662ba145ec", 149 | "sha256:38be427ea01a78206bcaf9a56f835784afcba9e5b88fbdce33bbbfbcd7841229", 150 | "sha256:475f2fa134cf272d6631072554f845d0630907fce053926ff634cc6bc45bf1af", 151 | "sha256:514b473d264671a5c672dfb28bdfe1bf1afd390f6b206aa2ec9fed7fc592c48e", 152 | "sha256:59e45f3b694b05a69032a0d603c32d453a23f0de80844fb14d55ab0c6c78ff2f", 153 | "sha256:5b24e8a572e4b4c18f614004dda8c9f2c07328cb5b6e314d6e1bbd536cb1a6c1", 154 | "sha256:6e3874aa7e8babd37b40c4504e3a94cc2023696ced5a0500949f3347664ff8e2", 155 | "sha256:8d72e814c7821125b16f1553124d12faba88e85405b0864328899aceaad7282b", 156 | "sha256:a4143c8d0c456a093387b96e0f5ee941a950992904d88bc816b4f0e72c9a0009", 157 | "sha256:b2b054d095b6431cdda2f852a6d2f0fdec77686b305c57961b4c5dd6d863bf3c", 158 | "sha256:c59ea046aea25be14dc22d69c97bee629e6d48d2b2ecb724d7fe8806bf5f61cd", 159 | "sha256:d1fe3f0df8ac0f3a9792666c69a7cd70530f329036426d06b4f899c025aca74e", 160 | "sha256:d8df4b9090b595511906fa48deda47af04e7d092318bfb291f4d45dfb6bb2127", 161 | "sha256:dba5c1f0a3aeea5083e75db9660935da90216f8a81b6d68e67f54e135ed5eb23", 162 | "sha256:e682f6442ebe4e50cb5e1cfde7dda6766fb586631c3e5569f6aa1951fd1a76ef", 163 | "sha256:ecb54491f98544c12c66ff3d15e701612fc388161fd455242447083350904730", 164 | "sha256:f5b06f5099e163295b8ff5b1b71132ecf5866cc6e7f586d78d7d3fd6e8084608", 165 | "sha256:f6864844b039805add62ebe8a8c676286340ba0c6d043ae5dea24114b82a319e", 166 | "sha256:ffd180ebd5dd2a9ac0da4e8b995c9c99e7c74c31f985ba090ee01d681b1c4b95" 167 | ], 168 | "index": "pypi", 169 | "version": "==1.7.3" 170 | }, 171 | "python-dateutil": { 172 | "hashes": [ 173 | "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", 174 | "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" 175 | ], 176 | "version": "==2.8.1" 177 | }, 178 | "python-dotenv": { 179 | "hashes": [ 180 | "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e", 181 | "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0" 182 | ], 183 | "index": "pypi", 184 | "version": "==0.15.0" 185 | }, 186 | "python-editor": { 187 | "hashes": [ 188 | "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d", 189 | "sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b", 190 | "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8", 191 | "sha256:c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77", 192 | "sha256:ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522" 193 | ], 194 | "version": "==1.0.4" 195 | }, 196 | "six": { 197 | "hashes": [ 198 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", 199 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" 200 | ], 201 | "version": "==1.15.0" 202 | }, 203 | "sqlalchemy": { 204 | "hashes": [ 205 | "sha256:04f995fcbf54e46cddeb4f75ce9dfc17075d6ae04ac23b2bacb44b3bc6f6bf11", 206 | "sha256:0c6406a78a714a540d980a680b86654feadb81c8d0eecb59f3d6c554a4c69f19", 207 | "sha256:0c72b90988be749e04eff0342dcc98c18a14461eb4b2ad59d611b57b31120f90", 208 | "sha256:108580808803c7732f34798eb4a329d45b04c562ed83ee90f09f6a184a42b766", 209 | "sha256:1418f5e71d6081aa1095a1d6b567a562d2761996710bdce9b6e6ba20a03d0864", 210 | "sha256:17610d573e698bf395afbbff946544fbce7c5f4ee77b5bcb1f821b36345fae7a", 211 | "sha256:216ba5b4299c95ed179b58f298bda885a476b16288ab7243e89f29f6aeced7e0", 212 | "sha256:2ff132a379838b1abf83c065be54cef32b47c987aedd06b82fc76476c85225eb", 213 | "sha256:314f5042c0b047438e19401d5f29757a511cfc2f0c40d28047ca0e4c95eabb5b", 214 | "sha256:318b5b727e00662e5fc4b4cd2bf58a5116d7c1b4dd56ffaa7d68f43458a8d1ed", 215 | "sha256:3ab5b44a07b8c562c6dcb7433c6a6c6e03266d19d64f87b3333eda34e3b9936b", 216 | "sha256:426ece890153ccc52cc5151a1a0ed540a5a7825414139bb4c95a868d8da54a52", 217 | "sha256:491fe48adc07d13e020a8b07ef82eefc227003a046809c121bea81d3dbf1832d", 218 | "sha256:4a84c7c7658dd22a33dab2e2aa2d17c18cb004a42388246f2e87cb4085ef2811", 219 | "sha256:54da615e5b92c339e339fe8536cce99fe823b6ed505d4ea344852aefa1c205fb", 220 | "sha256:5a7f224cdb7233182cec2a45d4c633951268d6a9bcedac37abbf79dd07012aea", 221 | "sha256:61628715931f4962e0cdb2a7c87ff39eea320d2aa96bd471a3c293d146f90394", 222 | "sha256:62285607a5264d1f91590abd874d6a498e229d5840669bd7d9f654cfaa599bd0", 223 | "sha256:62fb881ba51dbacba9af9b779211cf9acff3442d4f2993142015b22b3cd1f92a", 224 | "sha256:68428818cf80c60dc04aa0f38da20ad39b28aba4d4d199f949e7d6e04444ea86", 225 | "sha256:6aaa13ee40c4552d5f3a59f543f0db6e31712cc4009ec7385407be4627259d41", 226 | "sha256:70121f0ae48b25ef3e56e477b88cd0b0af0e1f3a53b5554071aa6a93ef378a03", 227 | "sha256:715b34578cc740b743361f7c3e5f584b04b0f1344f45afc4e87fbac4802eb0a0", 228 | "sha256:758fc8c4d6c0336e617f9f6919f9daea3ab6bb9b07005eda9a1a682e24a6cacc", 229 | "sha256:7d4b8de6bb0bc736161cb0bbd95366b11b3eb24dd6b814a143d8375e75af9990", 230 | "sha256:81d8d099a49f83111cce55ec03cc87eef45eec0d90f9842b4fc674f860b857b0", 231 | "sha256:888d5b4b5aeed0d3449de93ea80173653e939e916cc95fe8527079e50235c1d2", 232 | "sha256:95bde07d19c146d608bccb9b16e144ec8f139bcfe7fd72331858698a71c9b4f5", 233 | "sha256:9bf572e4f5aa23f88dd902f10bb103cb5979022a38eec684bfa6d61851173fec", 234 | "sha256:bab5a1e15b9466a25c96cda19139f3beb3e669794373b9ce28c4cf158c6e841d", 235 | "sha256:bd4b1af45fd322dcd1fb2a9195b4f93f570d1a5902a842e3e6051385fac88f9c", 236 | "sha256:bde677047305fe76c7ee3e4492b545e0018918e44141cc154fe39e124e433991", 237 | "sha256:c389d7cc2b821853fb018c85457da3e7941db64f4387720a329bc7ff06a27963", 238 | "sha256:d055ff750fcab69ca4e57b656d9c6ad33682e9b8d564f2fbe667ab95c63591b0", 239 | "sha256:d53f59744b01f1440a1b0973ed2c3a7de204135c593299ee997828aad5191693", 240 | "sha256:f115150cc4361dd46153302a640c7fa1804ac207f9cc356228248e351a8b4676", 241 | "sha256:f1e88b30da8163215eab643962ae9d9252e47b4ea53404f2c4f10f24e70ddc62", 242 | "sha256:f8191fef303025879e6c3548ecd8a95aafc0728c764ab72ec51a0bdf0c91a341" 243 | ], 244 | "version": "==1.3.22" 245 | }, 246 | "starlette": { 247 | "hashes": [ 248 | "sha256:bd2ffe5e37fb75d014728511f8e68ebf2c80b0fa3d04ca1479f4dc752ae31ac9", 249 | "sha256:ebe8ee08d9be96a3c9f31b2cb2a24dbdf845247b745664bd8a3f9bd0c977fdbc" 250 | ], 251 | "version": "==0.13.6" 252 | }, 253 | "uvicorn": { 254 | "hashes": [ 255 | "sha256:6707fa7f4dbd86fd6982a2d4ecdaad2704e4514d23a1e4278104311288b04691", 256 | "sha256:d19ca083bebd212843e01f689900e5c637a292c63bb336c7f0735a99300a5f38" 257 | ], 258 | "index": "pypi", 259 | "version": "==0.13.2" 260 | } 261 | }, 262 | "develop": {} 263 | } 264 | -------------------------------------------------------------------------------- /streamlit/Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "274a61235233b47c384a6aa1b3ff91fbcc7cb8bd8c2e581c177a7f3cf278f39a" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.8" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "altair": { 20 | "hashes": [ 21 | "sha256:3edd30d4f4bb0a37278b72578e7e60bc72045a8e6704179e2f4738e35bc12931", 22 | "sha256:7748841a1bea8354173d1140bef6d3b58bea21d201f562528e9599ea384feb7f" 23 | ], 24 | "version": "==4.1.0" 25 | }, 26 | "argon2-cffi": { 27 | "hashes": [ 28 | "sha256:05a8ac07c7026542377e38389638a8a1e9b78f1cd8439cd7493b39f08dd75fbf", 29 | "sha256:0bf066bc049332489bb2d75f69216416329d9dc65deee127152caeb16e5ce7d5", 30 | "sha256:18dee20e25e4be86680b178b35ccfc5d495ebd5792cd00781548d50880fee5c5", 31 | "sha256:392c3c2ef91d12da510cfb6f9bae52512a4552573a9e27600bdb800e05905d2b", 32 | "sha256:57358570592c46c420300ec94f2ff3b32cbccd10d38bdc12dc6979c4a8484fbc", 33 | "sha256:6678bb047373f52bcff02db8afab0d2a77d83bde61cfecea7c5c62e2335cb203", 34 | "sha256:6ea92c980586931a816d61e4faf6c192b4abce89aa767ff6581e6ddc985ed003", 35 | "sha256:77e909cc756ef81d6abb60524d259d959bab384832f0c651ed7dcb6e5ccdbb78", 36 | "sha256:7d455c802727710e9dfa69b74ccaab04568386ca17b0ad36350b622cd34606fe", 37 | "sha256:8a84934bd818e14a17943de8099d41160da4a336bcc699bb4c394bbb9b94bd32", 38 | "sha256:9bee3212ba4f560af397b6d7146848c32a800652301843df06b9e8f68f0f7361", 39 | "sha256:9dfd5197852530294ecb5795c97a823839258dfd5eb9420233c7cfedec2058f2", 40 | "sha256:b160416adc0f012fb1f12588a5e6954889510f82f698e23ed4f4fa57f12a0647", 41 | "sha256:ba7209b608945b889457f949cc04c8e762bed4fe3fec88ae9a6b7765ae82e496", 42 | "sha256:cc0e028b209a5483b6846053d5fd7165f460a1f14774d79e632e75e7ae64b82b", 43 | "sha256:d8029b2d3e4b4cea770e9e5a0104dd8fa185c1724a0f01528ae4826a6d25f97d", 44 | "sha256:da7f0445b71db6d3a72462e04f36544b0de871289b0bc8a7cc87c0f5ec7079fa", 45 | "sha256:e2db6e85c057c16d0bd3b4d2b04f270a7467c147381e8fd73cbbe5bc719832be" 46 | ], 47 | "version": "==20.1.0" 48 | }, 49 | "astor": { 50 | "hashes": [ 51 | "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5", 52 | "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e" 53 | ], 54 | "version": "==0.8.1" 55 | }, 56 | "async-generator": { 57 | "hashes": [ 58 | "sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b", 59 | "sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144" 60 | ], 61 | "version": "==1.10" 62 | }, 63 | "attrs": { 64 | "hashes": [ 65 | "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6", 66 | "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700" 67 | ], 68 | "version": "==20.3.0" 69 | }, 70 | "awesome-streamlit": { 71 | "hashes": [ 72 | "sha256:425ec1734c403ed966b024cd4ff076b460bbc64be14f56063f7c637e6c6eb0b9", 73 | "sha256:5649f43857eca883f2c5d8aae5cc0ba961c1de0c041680017fd7565f3b30559b" 74 | ], 75 | "index": "pypi", 76 | "version": "==20200728.1" 77 | }, 78 | "backcall": { 79 | "hashes": [ 80 | "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e", 81 | "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255" 82 | ], 83 | "version": "==0.2.0" 84 | }, 85 | "base58": { 86 | "hashes": [ 87 | "sha256:365c9561d9babac1b5f18ee797508cd54937a724b6e419a130abad69cec5ca79", 88 | "sha256:447adc750d6b642987ffc6d397ecd15a799852d5f6a1d308d384500243825058" 89 | ], 90 | "version": "==2.0.1" 91 | }, 92 | "bleach": { 93 | "hashes": [ 94 | "sha256:52b5919b81842b1854196eaae5ca29679a2f2e378905c346d3ca8227c2c66080", 95 | "sha256:9f8ccbeb6183c6e6cddea37592dfb0167485c1e3b13b3363bc325aa8bda3adbd" 96 | ], 97 | "version": "==3.2.1" 98 | }, 99 | "blinker": { 100 | "hashes": [ 101 | "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6" 102 | ], 103 | "version": "==1.4" 104 | }, 105 | "cachetools": { 106 | "hashes": [ 107 | "sha256:3796e1de094f0eaca982441c92ce96c68c89cced4cd97721ab297ea4b16db90e", 108 | "sha256:c6b07a6ded8c78bf36730b3dc452dfff7d95f2a12a2fed856b1a0cb13ca78c61" 109 | ], 110 | "version": "==4.2.0" 111 | }, 112 | "certifi": { 113 | "hashes": [ 114 | "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", 115 | "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" 116 | ], 117 | "version": "==2020.12.5" 118 | }, 119 | "cffi": { 120 | "hashes": [ 121 | "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e", 122 | "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d", 123 | "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a", 124 | "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec", 125 | "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362", 126 | "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668", 127 | "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c", 128 | "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b", 129 | "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06", 130 | "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698", 131 | "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2", 132 | "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c", 133 | "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7", 134 | "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009", 135 | "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03", 136 | "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b", 137 | "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909", 138 | "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53", 139 | "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35", 140 | "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26", 141 | "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b", 142 | "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01", 143 | "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb", 144 | "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293", 145 | "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd", 146 | "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d", 147 | "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3", 148 | "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d", 149 | "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e", 150 | "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca", 151 | "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d", 152 | "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775", 153 | "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375", 154 | "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b", 155 | "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b", 156 | "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f" 157 | ], 158 | "version": "==1.14.4" 159 | }, 160 | "chardet": { 161 | "hashes": [ 162 | "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", 163 | "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" 164 | ], 165 | "version": "==4.0.0" 166 | }, 167 | "click": { 168 | "hashes": [ 169 | "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", 170 | "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" 171 | ], 172 | "version": "==7.1.2" 173 | }, 174 | "decorator": { 175 | "hashes": [ 176 | "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760", 177 | "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7" 178 | ], 179 | "version": "==4.4.2" 180 | }, 181 | "defusedxml": { 182 | "hashes": [ 183 | "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93", 184 | "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5" 185 | ], 186 | "version": "==0.6.0" 187 | }, 188 | "entrypoints": { 189 | "hashes": [ 190 | "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", 191 | "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451" 192 | ], 193 | "version": "==0.3" 194 | }, 195 | "gitdb": { 196 | "hashes": [ 197 | "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac", 198 | "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9" 199 | ], 200 | "version": "==4.0.5" 201 | }, 202 | "gitpython": { 203 | "hashes": [ 204 | "sha256:6eea89b655917b500437e9668e4a12eabdcf00229a0df1762aabd692ef9b746b", 205 | "sha256:befa4d101f91bad1b632df4308ec64555db684c360bd7d2130b4807d49ce86b8" 206 | ], 207 | "version": "==3.1.11" 208 | }, 209 | "idna": { 210 | "hashes": [ 211 | "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", 212 | "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" 213 | ], 214 | "version": "==2.10" 215 | }, 216 | "ipykernel": { 217 | "hashes": [ 218 | "sha256:63b4b96c513e1138874934e3e783a8e5e13c02b9036e37107bfe042ac8955005", 219 | "sha256:e20ceb7e52cb4d250452e1230be76e0b2323f33bd46c6b2bc7abb6601740e182" 220 | ], 221 | "markers": "python_version >= '3.4'", 222 | "version": "==5.4.2" 223 | }, 224 | "ipython": { 225 | "hashes": [ 226 | "sha256:c987e8178ced651532b3b1ff9965925bfd445c279239697052561a9ab806d28f", 227 | "sha256:cbb2ef3d5961d44e6a963b9817d4ea4e1fa2eb589c371a470fed14d8d40cbd6a" 228 | ], 229 | "version": "==7.19.0" 230 | }, 231 | "ipython-genutils": { 232 | "hashes": [ 233 | "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", 234 | "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8" 235 | ], 236 | "version": "==0.2.0" 237 | }, 238 | "ipywidgets": { 239 | "hashes": [ 240 | "sha256:bbb881ce18fb0cff4ac718f40c04709c7ac86a77abee149f1b447965ede86e36", 241 | "sha256:eab960f737f380075cabca41f92e5e81dfb6eba3ce6392094469ef2418ca4d35" 242 | ], 243 | "version": "==7.6.2" 244 | }, 245 | "jedi": { 246 | "hashes": [ 247 | "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93", 248 | "sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707" 249 | ], 250 | "version": "==0.18.0" 251 | }, 252 | "jinja2": { 253 | "hashes": [ 254 | "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", 255 | "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" 256 | ], 257 | "version": "==2.11.2" 258 | }, 259 | "jsonschema": { 260 | "hashes": [ 261 | "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163", 262 | "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a" 263 | ], 264 | "version": "==3.2.0" 265 | }, 266 | "jupyter-client": { 267 | "hashes": [ 268 | "sha256:49e390b36fe4b4226724704ea28d9fb903f1a3601b6882ce3105221cd09377a1", 269 | "sha256:c958d24d6eacb975c1acebb68ac9077da61b5f5c040f22f6849928ad7393b950" 270 | ], 271 | "version": "==6.1.7" 272 | }, 273 | "jupyter-core": { 274 | "hashes": [ 275 | "sha256:0a451c9b295e4db772bdd8d06f2f1eb31caeec0e81fbb77ba37d4a3024e3b315", 276 | "sha256:aa1f9496ab3abe72da4efe0daab0cb2233997914581f9a071e07498c6add8ed3" 277 | ], 278 | "version": "==4.7.0" 279 | }, 280 | "jupyterlab-pygments": { 281 | "hashes": [ 282 | "sha256:abfb880fd1561987efaefcb2d2ac75145d2a5d0139b1876d5be806e32f630008", 283 | "sha256:cfcda0873626150932f438eccf0f8bf22bfa92345b814890ab360d666b254146" 284 | ], 285 | "version": "==0.1.2" 286 | }, 287 | "jupyterlab-widgets": { 288 | "hashes": [ 289 | "sha256:5c1a29a84d3069208cb506b10609175b249b6486d6b1cbae8fcde2a11584fb78", 290 | "sha256:caeaf3e6103180e654e7d8d2b81b7d645e59e432487c1d35a41d6d3ee56b3fef" 291 | ], 292 | "markers": "python_version >= '3.5'", 293 | "version": "==1.0.0" 294 | }, 295 | "markupsafe": { 296 | "hashes": [ 297 | "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", 298 | "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", 299 | "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", 300 | "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", 301 | "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", 302 | "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", 303 | "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", 304 | "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", 305 | "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", 306 | "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", 307 | "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", 308 | "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", 309 | "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", 310 | "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", 311 | "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", 312 | "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", 313 | "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", 314 | "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", 315 | "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", 316 | "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", 317 | "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", 318 | "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", 319 | "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", 320 | "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", 321 | "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", 322 | "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", 323 | "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", 324 | "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", 325 | "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", 326 | "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", 327 | "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", 328 | "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", 329 | "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" 330 | ], 331 | "version": "==1.1.1" 332 | }, 333 | "mistune": { 334 | "hashes": [ 335 | "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e", 336 | "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4" 337 | ], 338 | "version": "==0.8.4" 339 | }, 340 | "nbclient": { 341 | "hashes": [ 342 | "sha256:01e2d726d16eaf2cde6db74a87e2451453547e8832d142f73f72fddcd4fe0250", 343 | "sha256:4d6b116187c795c99b9dba13d46e764d596574b14c296d60670c8dfe454db364" 344 | ], 345 | "version": "==0.5.1" 346 | }, 347 | "nbconvert": { 348 | "hashes": [ 349 | "sha256:39e9f977920b203baea0be67eea59f7b37a761caa542abe80f5897ce3cf6311d", 350 | "sha256:cbbc13a86dfbd4d1b5dee106539de0795b4db156c894c2c5dc382062bbc29002" 351 | ], 352 | "version": "==6.0.7" 353 | }, 354 | "nbformat": { 355 | "hashes": [ 356 | "sha256:aa9450c16d29286dc69b92ea4913c1bffe86488f90184445996ccc03a2f60382", 357 | "sha256:f545b22138865bfbcc6b1ffe89ed5a2b8e2dc5d4fe876f2ca60d8e6f702a30f8" 358 | ], 359 | "version": "==5.0.8" 360 | }, 361 | "nest-asyncio": { 362 | "hashes": [ 363 | "sha256:dbe032f3e9ff7f120e76be22bf6e7958e867aed1743e6894b8a9585fe8495cc9", 364 | "sha256:eaa09ef1353ebefae19162ad423eef7a12166bcc63866f8bff8f3635353cd9fa" 365 | ], 366 | "version": "==1.4.3" 367 | }, 368 | "notebook": { 369 | "hashes": [ 370 | "sha256:cf40d4f81541401db5a2fda1707ca7877157abd41f04ef7b88f02b67f3c61791", 371 | "sha256:e6a62188e319a5d45dd2ed24719f646adf88bef8be1f654ebd0ab360ece6d7a6" 372 | ], 373 | "version": "==6.1.6" 374 | }, 375 | "numpy": { 376 | "hashes": [ 377 | "sha256:08308c38e44cc926bdfce99498b21eec1f848d24c302519e64203a8da99a97db", 378 | "sha256:09c12096d843b90eafd01ea1b3307e78ddd47a55855ad402b157b6c4862197ce", 379 | "sha256:13d166f77d6dc02c0a73c1101dd87fdf01339febec1030bd810dcd53fff3b0f1", 380 | "sha256:141ec3a3300ab89c7f2b0775289954d193cc8edb621ea05f99db9cb181530512", 381 | "sha256:16c1b388cc31a9baa06d91a19366fb99ddbe1c7b205293ed072211ee5bac1ed2", 382 | "sha256:18bed2bcb39e3f758296584337966e68d2d5ba6aab7e038688ad53c8f889f757", 383 | "sha256:1aeef46a13e51931c0b1cf8ae1168b4a55ecd282e6688fdb0a948cc5a1d5afb9", 384 | "sha256:27d3f3b9e3406579a8af3a9f262f5339005dd25e0ecf3cf1559ff8a49ed5cbf2", 385 | "sha256:2a2740aa9733d2e5b2dfb33639d98a64c3b0f24765fed86b0fd2aec07f6a0a08", 386 | "sha256:4377e10b874e653fe96985c05feed2225c912e328c8a26541f7fc600fb9c637b", 387 | "sha256:448ebb1b3bf64c0267d6b09a7cba26b5ae61b6d2dbabff7c91b660c7eccf2bdb", 388 | "sha256:50e86c076611212ca62e5a59f518edafe0c0730f7d9195fec718da1a5c2bb1fc", 389 | "sha256:5734bdc0342aba9dfc6f04920988140fb41234db42381cf7ccba64169f9fe7ac", 390 | "sha256:64324f64f90a9e4ef732be0928be853eee378fd6a01be21a0a8469c4f2682c83", 391 | "sha256:6ae6c680f3ebf1cf7ad1d7748868b39d9f900836df774c453c11c5440bc15b36", 392 | "sha256:6d7593a705d662be5bfe24111af14763016765f43cb6923ed86223f965f52387", 393 | "sha256:8cac8790a6b1ddf88640a9267ee67b1aee7a57dfa2d2dd33999d080bc8ee3a0f", 394 | "sha256:8ece138c3a16db8c1ad38f52eb32be6086cc72f403150a79336eb2045723a1ad", 395 | "sha256:9eeb7d1d04b117ac0d38719915ae169aa6b61fca227b0b7d198d43728f0c879c", 396 | "sha256:a09f98011236a419ee3f49cedc9ef27d7a1651df07810ae430a6b06576e0b414", 397 | "sha256:a5d897c14513590a85774180be713f692df6fa8ecf6483e561a6d47309566f37", 398 | "sha256:ad6f2ff5b1989a4899bf89800a671d71b1612e5ff40866d1f4d8bcf48d4e5764", 399 | "sha256:c42c4b73121caf0ed6cd795512c9c09c52a7287b04d105d112068c1736d7c753", 400 | "sha256:cb1017eec5257e9ac6209ac172058c430e834d5d2bc21961dceeb79d111e5909", 401 | "sha256:d6c7bb82883680e168b55b49c70af29b84b84abb161cbac2800e8fcb6f2109b6", 402 | "sha256:e452dc66e08a4ce642a961f134814258a082832c78c90351b75c41ad16f79f63", 403 | "sha256:e5b6ed0f0b42317050c88022349d994fe72bfe35f5908617512cd8c8ef9da2a9", 404 | "sha256:e9b30d4bd69498fc0c3fe9db5f62fffbb06b8eb9321f92cc970f2969be5e3949", 405 | "sha256:ec149b90019852266fec2341ce1db513b843e496d5a8e8cdb5ced1923a92faab", 406 | "sha256:edb01671b3caae1ca00881686003d16c2209e07b7ef8b7639f1867852b948f7c", 407 | "sha256:f0d3929fe88ee1c155129ecd82f981b8856c5d97bcb0d5f23e9b4242e79d1de3", 408 | "sha256:f29454410db6ef8126c83bd3c968d143304633d45dc57b51252afbd79d700893", 409 | "sha256:fe45becb4c2f72a0907c1d0246ea6449fe7a9e2293bb0e11c4e9a32bb0930a15", 410 | "sha256:fedbd128668ead37f33917820b704784aff695e0019309ad446a6d0b065b57e4" 411 | ], 412 | "version": "==1.19.4" 413 | }, 414 | "packaging": { 415 | "hashes": [ 416 | "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858", 417 | "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093" 418 | ], 419 | "version": "==20.8" 420 | }, 421 | "pandas": { 422 | "hashes": [ 423 | "sha256:0be6102dd99910513e75ed6536284743ead810349c51bdeadd2a5b6649f30abb", 424 | "sha256:272675a98fa4954b9fc0933df775596fc942e50015d7e75d8f19548808a2bfdf", 425 | "sha256:2d8b4f532db37418121831a461fd107d826c240b098f52e7a1b4ab3d5aaa4fb2", 426 | "sha256:33318fa24b192b1a4684347ff76679a7267fd4e547da9f71556a5914f0dc10e7", 427 | "sha256:3bc6d2be03cb75981d8cbeda09503cd9d6d699fc0dc28a65e197165ad527b7b8", 428 | "sha256:43482789c55cbabeed9482263cfc98a11e8fcae900cb63ef038948acb4a72570", 429 | "sha256:616478c1bd8fe1e600f521ae2da434e021c11e7a4e5da3451d02906143d3629a", 430 | "sha256:6c1a57e4d0d6f9633a07817c44e6b36d81c265fe4c52d0c0505513a2d0f7953c", 431 | "sha256:7904ee438549b5223ce8dc008772458dd7c5cf0ccc64cf903e81202400702235", 432 | "sha256:7b54c14130a3448d81eed1348f52429c23e27188d9db6e6d4afeae792bc49c11", 433 | "sha256:8f92b07cdbfa3704d85b4264e52c216cafe6c0059b0d07cdad8cb29e0b90f2b8", 434 | "sha256:91fd0b94e7b98528177a05e6f65efea79d7ef9dec15ee48c7c69fc39fdd87235", 435 | "sha256:9c6692cea6d56da8650847172bdb148622f545e7782d17995822434c79d7a211", 436 | "sha256:9e18631d996fe131de6cb31a8bdae18965cc8f39eb23fdfbbf42808ecc63dabf", 437 | "sha256:cba93d4fd3b0a42858b2b599495aff793fb5d94587979f45a14177d1217ba446", 438 | "sha256:e03386615b970b8b41da6a68afe717626741bb2431cec993640685614c0680e4", 439 | "sha256:f8b87d2f541cd9bc4ecfe85a561abac85c33fe4de4ce70cca36b2768af2611f5" 440 | ], 441 | "index": "pypi", 442 | "version": "==1.2.0" 443 | }, 444 | "pandocfilters": { 445 | "hashes": [ 446 | "sha256:bc63fbb50534b4b1f8ebe1860889289e8af94a23bff7445259592df25a3906eb" 447 | ], 448 | "version": "==1.4.3" 449 | }, 450 | "parso": { 451 | "hashes": [ 452 | "sha256:15b00182f472319383252c18d5913b69269590616c947747bc50bf4ac768f410", 453 | "sha256:8519430ad07087d4c997fda3a7918f7cfa27cb58972a8c89c2a0295a1c940e9e" 454 | ], 455 | "version": "==0.8.1" 456 | }, 457 | "pexpect": { 458 | "hashes": [ 459 | "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937", 460 | "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c" 461 | ], 462 | "markers": "sys_platform != 'win32'", 463 | "version": "==4.8.0" 464 | }, 465 | "pickleshare": { 466 | "hashes": [ 467 | "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", 468 | "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56" 469 | ], 470 | "version": "==0.7.5" 471 | }, 472 | "pillow": { 473 | "hashes": [ 474 | "sha256:006de60d7580d81f4a1a7e9f0173dc90a932e3905cc4d47ea909bc946302311a", 475 | "sha256:0a2e8d03787ec7ad71dc18aec9367c946ef8ef50e1e78c71f743bc3a770f9fae", 476 | "sha256:0eeeae397e5a79dc088d8297a4c2c6f901f8fb30db47795113a4a605d0f1e5ce", 477 | "sha256:11c5c6e9b02c9dac08af04f093eb5a2f84857df70a7d4a6a6ad461aca803fb9e", 478 | "sha256:2fb113757a369a6cdb189f8df3226e995acfed0a8919a72416626af1a0a71140", 479 | "sha256:4b0ef2470c4979e345e4e0cc1bbac65fda11d0d7b789dbac035e4c6ce3f98adb", 480 | "sha256:59e903ca800c8cfd1ebe482349ec7c35687b95e98cefae213e271c8c7fffa021", 481 | "sha256:5abd653a23c35d980b332bc0431d39663b1709d64142e3652890df4c9b6970f6", 482 | "sha256:5f9403af9c790cc18411ea398a6950ee2def2a830ad0cfe6dc9122e6d528b302", 483 | "sha256:6b4a8fd632b4ebee28282a9fef4c341835a1aa8671e2770b6f89adc8e8c2703c", 484 | "sha256:6c1aca8231625115104a06e4389fcd9ec88f0c9befbabd80dc206c35561be271", 485 | "sha256:795e91a60f291e75de2e20e6bdd67770f793c8605b553cb6e4387ce0cb302e09", 486 | "sha256:7ba0ba61252ab23052e642abdb17fd08fdcfdbbf3b74c969a30c58ac1ade7cd3", 487 | "sha256:7c9401e68730d6c4245b8e361d3d13e1035cbc94db86b49dc7da8bec235d0015", 488 | "sha256:81f812d8f5e8a09b246515fac141e9d10113229bc33ea073fec11403b016bcf3", 489 | "sha256:895d54c0ddc78a478c80f9c438579ac15f3e27bf442c2a9aa74d41d0e4d12544", 490 | "sha256:8de332053707c80963b589b22f8e0229f1be1f3ca862a932c1bcd48dafb18dd8", 491 | "sha256:92c882b70a40c79de9f5294dc99390671e07fc0b0113d472cbea3fde15db1792", 492 | "sha256:95edb1ed513e68bddc2aee3de66ceaf743590bf16c023fb9977adc4be15bd3f0", 493 | "sha256:b63d4ff734263ae4ce6593798bcfee6dbfb00523c82753a3a03cbc05555a9cc3", 494 | "sha256:bd7bf289e05470b1bc74889d1466d9ad4a56d201f24397557b6f65c24a6844b8", 495 | "sha256:cc3ea6b23954da84dbee8025c616040d9aa5eaf34ea6895a0a762ee9d3e12e11", 496 | "sha256:cc9ec588c6ef3a1325fa032ec14d97b7309db493782ea8c304666fb10c3bd9a7", 497 | "sha256:d3d07c86d4efa1facdf32aa878bd508c0dc4f87c48125cc16b937baa4e5b5e11", 498 | "sha256:d8a96747df78cda35980905bf26e72960cba6d355ace4780d4bdde3b217cdf1e", 499 | "sha256:e38d58d9138ef972fceb7aeec4be02e3f01d383723965bfcef14d174c8ccd039", 500 | "sha256:eb472586374dc66b31e36e14720747595c2b265ae962987261f044e5cce644b5", 501 | "sha256:fbd922f702582cb0d71ef94442bfca57624352622d75e3be7a1e7e9360b07e72" 502 | ], 503 | "version": "==8.0.1" 504 | }, 505 | "prometheus-client": { 506 | "hashes": [ 507 | "sha256:9da7b32f02439d8c04f7777021c304ed51d9ec180604700c1ba72a4d44dceb03", 508 | "sha256:b08c34c328e1bf5961f0b4352668e6c8f145b4a087e09b7296ef62cbe4693d35" 509 | ], 510 | "version": "==0.9.0" 511 | }, 512 | "prompt-toolkit": { 513 | "hashes": [ 514 | "sha256:25c95d2ac813909f813c93fde734b6e44406d1477a9faef7c915ff37d39c0a8c", 515 | "sha256:7debb9a521e0b1ee7d2fe96ee4bd60ef03c6492784de0547337ca4433e46aa63" 516 | ], 517 | "version": "==3.0.8" 518 | }, 519 | "protobuf": { 520 | "hashes": [ 521 | "sha256:0e247612fadda953047f53301a7b0407cb0c3cb4ae25a6fde661597a04039b3c", 522 | "sha256:0fc96785262042e4863b3f3b5c429d4636f10d90061e1840fce1baaf59b1a836", 523 | "sha256:1c51fda1bbc9634246e7be6016d860be01747354ed7015ebe38acf4452f470d2", 524 | "sha256:1d63eb389347293d8915fb47bee0951c7b5dab522a4a60118b9a18f33e21f8ce", 525 | "sha256:22bcd2e284b3b1d969c12e84dc9b9a71701ec82d8ce975fdda19712e1cfd4e00", 526 | "sha256:2a7e2fe101a7ace75e9327b9c946d247749e564a267b0515cf41dfe450b69bac", 527 | "sha256:43b554b9e73a07ba84ed6cf25db0ff88b1e06be610b37656e292e3cbb5437472", 528 | "sha256:4b74301b30513b1a7494d3055d95c714b560fbb630d8fb9956b6f27992c9f980", 529 | "sha256:4e75105c9dfe13719b7293f75bd53033108f4ba03d44e71db0ec2a0e8401eafd", 530 | "sha256:5b7a637212cc9b2bcf85dd828b1178d19efdf74dbfe1ddf8cd1b8e01fdaaa7f5", 531 | "sha256:5e9806a43232a1fa0c9cf5da8dc06f6910d53e4390be1fa06f06454d888a9142", 532 | "sha256:629b03fd3caae7f815b0c66b41273f6b1900a579e2ccb41ef4493a4f5fb84f3a", 533 | "sha256:72230ed56f026dd664c21d73c5db73ebba50d924d7ba6b7c0d81a121e390406e", 534 | "sha256:86a75477addde4918e9a1904e5c6af8d7b691f2a3f65587d73b16100fbe4c3b2", 535 | "sha256:8971c421dbd7aad930c9bd2694122f332350b6ccb5202a8b7b06f3f1a5c41ed5", 536 | "sha256:9616f0b65a30851e62f1713336c931fcd32c057202b7ff2cfbfca0fc7d5e3043", 537 | "sha256:b0d5d35faeb07e22a1ddf8dce620860c8fe145426c02d1a0ae2688c6e8ede36d", 538 | "sha256:ecc33531a213eee22ad60e0e2aaea6c8ba0021f0cce35dbf0ab03dee6e2a23a1" 539 | ], 540 | "version": "==3.14.0" 541 | }, 542 | "ptyprocess": { 543 | "hashes": [ 544 | "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", 545 | "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f" 546 | ], 547 | "version": "==0.6.0" 548 | }, 549 | "pyarrow": { 550 | "hashes": [ 551 | "sha256:00d8fb8a9b2d9bb2f0ced2765b62c5d72689eed06c47315bca004584b0ccda60", 552 | "sha256:0b358773eb9fb1b31c8217c6c8c0b4681c3dff80562dc23ad5b379f0279dad69", 553 | "sha256:0bf43e520c33ceb1dd47263a5326830fca65f18d827f7f7b8fe7e64fc4364d88", 554 | "sha256:0db5156a66615591a4a8c66a9a30890a364a259de8d2a6ccb873c7d1740e6c75", 555 | "sha256:1000e491e9a539588ec33a2c2603cf05f1d4629aef375345bfd64f2ab7bc8529", 556 | "sha256:14b02a629986c25e045f81771799e07a8bb3f339898c111314066436769a3dd4", 557 | "sha256:16ec87163a2fb4abd48bf79cbdf70a7455faa83740e067c2280cfa45a63ed1f3", 558 | "sha256:3e33e9003794c9062f4c963a10f2a0d787b83d4d1a517a375294f2293180b778", 559 | "sha256:652c5dff97624375ed0f97cc8ad6f88ee01953f15c17083917735de171f03fe0", 560 | "sha256:6afc71cc9c234f3cdbe971297468755ec3392966cb19d3a6caf42fd7dbc6aaa9", 561 | "sha256:916b593a24f2812b9a75adef1143b1dd89d799e1803282fea2829c5dc0b828ea", 562 | "sha256:9a8d3c6baa6e159017d97e8a028ae9eaa2811d8f1ab3d22710c04dcddc0dd7a1", 563 | "sha256:9f4ba9ab479c0172e532f5d73c68e30a31c16b01e09bb21eba9201561231f722", 564 | "sha256:acdd18fd83c0be0b53a8e734c0a650fb27bbf4e7d96a8f7eb0a7506ea58bd594", 565 | "sha256:b5e6cd217457e8febcc98a6c279b96f72d5c31a24cd2bffd8d3b2da701d2025c", 566 | "sha256:bc8c3713086e4a137b3fda4b149440458b1b0bd72f67b1afa2c7068df1edc060", 567 | "sha256:c801e59ec4e8d9d871e299726a528c3ba3139f2ce2d9cdab101f8483c52eec7c", 568 | "sha256:ccff3a72f70ebfcc002bf75f5ad1248065e5c9c14e0dcfa599a438ea221c5658", 569 | "sha256:ce0462cec7f81c4ff87ce1a95c82a8d467606dce6c72e92906ac251c6115f32b", 570 | "sha256:cf9bf10daadbbf1a360ac1c7dab0b4f8381d81a3f452737bd6ed310d57a88be8", 571 | "sha256:dc0d04c42632e65c4fcbe2f82c70109c5f347652844ead285bc1285dc3a67660", 572 | "sha256:dd661b6598ce566c6f41d31cc1fc4482308613c2c0c808bd8db33b0643192f84", 573 | "sha256:eb05038b750a6e16a9680f9d2c40d050796284ea1f94690da8f4f28805af0495", 574 | "sha256:fb69672e69e1b752744ee1e236fdf03aad78ffec905fc5c19adbaf88bac4d0fd", 575 | "sha256:ffb306951b5925a0638dc2ef1ab7ce8033f39e5b4e0fef5787b91ef4fa7da19d" 576 | ], 577 | "markers": "python_version < '3.9'", 578 | "version": "==2.0.0" 579 | }, 580 | "pycparser": { 581 | "hashes": [ 582 | "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", 583 | "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" 584 | ], 585 | "version": "==2.20" 586 | }, 587 | "pydeck": { 588 | "hashes": [ 589 | "sha256:5759842addfef5a76c6033f90f34901dfa377a740b3dbedb55e7c46d07be3c65", 590 | "sha256:cf505af5c75924b669d8acdd00c6ef48da617c3f5051f5a146f2fb669d587385" 591 | ], 592 | "version": "==0.5.0" 593 | }, 594 | "pygments": { 595 | "hashes": [ 596 | "sha256:ccf3acacf3782cbed4a989426012f1c535c9a90d3a7fc3f16d231b9372d2b716", 597 | "sha256:f275b6c0909e5dafd2d6269a656aa90fa58ebf4a74f8fcf9053195d226b24a08" 598 | ], 599 | "version": "==2.7.3" 600 | }, 601 | "pyparsing": { 602 | "hashes": [ 603 | "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", 604 | "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" 605 | ], 606 | "version": "==2.4.7" 607 | }, 608 | "pyrsistent": { 609 | "hashes": [ 610 | "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e" 611 | ], 612 | "version": "==0.17.3" 613 | }, 614 | "python-dateutil": { 615 | "hashes": [ 616 | "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", 617 | "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" 618 | ], 619 | "version": "==2.8.1" 620 | }, 621 | "pytz": { 622 | "hashes": [ 623 | "sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4", 624 | "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5" 625 | ], 626 | "version": "==2020.5" 627 | }, 628 | "pyzmq": { 629 | "hashes": [ 630 | "sha256:03638e46d486dd1c118e03c8bf9c634bdcae679600eac6573ae1e54906de7c2f", 631 | "sha256:0af84f34f27b5c6a0e906c648bdf46d4caebf9c8e6e16db0728f30a58141cad6", 632 | "sha256:0e554fd390021edbe0330b67226325a820b0319c5b45e1b0a59bf22ccc36e793", 633 | "sha256:1e9b75a119606732023a305d1c214146c09a91f8116f6aff3e8b7d0a60b6f0ff", 634 | "sha256:225774a48ed7414c0395335e7123ef8c418dbcbe172caabdc2496133b03254c2", 635 | "sha256:2742e380d186673eee6a570ef83d4568741945434ba36d92b98d36cdbfedbd44", 636 | "sha256:309d763d89ec1845c0e0fa14e1fb6558fd8c9ef05ed32baec27d7a8499cc7bb0", 637 | "sha256:46250789730489009fe139cbf576679557c070a6a3628077d09a4153d52fd381", 638 | "sha256:4d9259a5eb3f71abbaf61f165cacf42240bfeea3783bebd8255341abdfe206f1", 639 | "sha256:523d542823cabb94065178090e05347bd204365f6e7cb260f0071c995d392fc2", 640 | "sha256:53706f4a792cdae422121fb6a5e65119bad02373153364fc9d004cf6a90394de", 641 | "sha256:5efe02bdcc5eafcac0aab531292294298f0ab8d28ed43be9e507d0e09173d1a4", 642 | "sha256:63ee08e35be72fdd7568065a249a5b5cf51a2e8ab6ee63cf9f73786fcb9e710b", 643 | "sha256:6e24907857c80dc67692e31f5bf3ad5bf483ee0142cec95b3d47e2db8c43bdda", 644 | "sha256:7113eb93dcd0a5750c65d123ed0099e036a3a3f2dcb48afedd025ffa125c983b", 645 | "sha256:824ad5888331aadeac772bce27e1c2fbcab82fade92edbd234542c4e12f0dca9", 646 | "sha256:895695be380f0f85d2e3ec5ccf68a93c92d45bd298567525ad5633071589872c", 647 | "sha256:b62113eeb9a0649cebed9b21fd578f3a0175ef214a2a91dcb7b31bbf55805295", 648 | "sha256:bc7dd697356b31389d5118b9bcdef3e8d8079e8181800c4e8d72dccd56e1ff68", 649 | "sha256:bf755905a7d30d2749079611b9a89924c1f2da2695dc09ce221f42122c9808e3", 650 | "sha256:c63fafd2556d218368c51d18588f8e6f8d86d09d493032415057faf6de869b34", 651 | "sha256:c95dda497a7c1b1e734b5e8353173ca5dd7b67784d8821d13413a97856588057", 652 | "sha256:cc09c5cd1a4332611c8564d65e6a432dc6db3e10793d0254da9fa1e31d9ffd6d", 653 | "sha256:cfa54a162a7b32641665e99b2c12084555afe9fc8fe80ec8b2f71a57320d10e1", 654 | "sha256:d81184489369ec325bd50ba1c935361e63f31f578430b9ad95471899361a8253", 655 | "sha256:d92c7f41a53ece82b91703ea433c7d34143248cf0cead33aa11c5fc621c764bf", 656 | "sha256:dc2f48b575dff6edefd572f1ac84cf0c3f18ad5fcf13384de32df740a010594a", 657 | "sha256:f0beef935efe78a63c785bb21ed56c1c24448511383e3994927c8bb2caf5e714", 658 | "sha256:f110a4d3f8f01209eec304ed542f6c8054cce9b0f16dfe3d571e57c290e4e133" 659 | ], 660 | "version": "==20.0.0" 661 | }, 662 | "requests": { 663 | "hashes": [ 664 | "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", 665 | "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" 666 | ], 667 | "version": "==2.25.1" 668 | }, 669 | "send2trash": { 670 | "hashes": [ 671 | "sha256:60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2", 672 | "sha256:f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b" 673 | ], 674 | "version": "==1.5.0" 675 | }, 676 | "six": { 677 | "hashes": [ 678 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", 679 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" 680 | ], 681 | "version": "==1.15.0" 682 | }, 683 | "smmap": { 684 | "hashes": [ 685 | "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4", 686 | "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24" 687 | ], 688 | "version": "==3.0.4" 689 | }, 690 | "streamlit": { 691 | "hashes": [ 692 | "sha256:6db734ca36c2c7beb3148c9894b1116837cd9f6d587446c56a3f4cde0453b726", 693 | "sha256:dc9ad12ff6b14263eaad7ea784375024d9f8a56ee19a8cfcfbf78382e1322f05" 694 | ], 695 | "index": "pypi", 696 | "version": "==0.73.1" 697 | }, 698 | "terminado": { 699 | "hashes": [ 700 | "sha256:3da72a155b807b01c9e8a5babd214e052a0a45a975751da3521a1c3381ce6d76", 701 | "sha256:c55f025beb06c2e2669f7ba5a04f47bb3304c30c05842d4981d8f0fc9ab3b4e3" 702 | ], 703 | "version": "==0.9.1" 704 | }, 705 | "testpath": { 706 | "hashes": [ 707 | "sha256:60e0a3261c149755f4399a1fff7d37523179a70fdc3abdf78de9fc2604aeec7e", 708 | "sha256:bfcf9411ef4bf3db7579063e0546938b1edda3d69f4e1fb8756991f5951f85d4" 709 | ], 710 | "version": "==0.4.4" 711 | }, 712 | "toml": { 713 | "hashes": [ 714 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", 715 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" 716 | ], 717 | "version": "==0.10.2" 718 | }, 719 | "toolz": { 720 | "hashes": [ 721 | "sha256:1bc473acbf1a1db4e72a1ce587be347450e8f08324908b8a266b486f408f04d5", 722 | "sha256:c7a47921f07822fe534fb1c01c9931ab335a4390c782bd28c6bcc7c2f71f3fbf" 723 | ], 724 | "version": "==0.11.1" 725 | }, 726 | "tornado": { 727 | "hashes": [ 728 | "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb", 729 | "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c", 730 | "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288", 731 | "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95", 732 | "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558", 733 | "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe", 734 | "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791", 735 | "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d", 736 | "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326", 737 | "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b", 738 | "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4", 739 | "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c", 740 | "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910", 741 | "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5", 742 | "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c", 743 | "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0", 744 | "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675", 745 | "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd", 746 | "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f", 747 | "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c", 748 | "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea", 749 | "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6", 750 | "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05", 751 | "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd", 752 | "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575", 753 | "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a", 754 | "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37", 755 | "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795", 756 | "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f", 757 | "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32", 758 | "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c", 759 | "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01", 760 | "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4", 761 | "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2", 762 | "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921", 763 | "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085", 764 | "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df", 765 | "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102", 766 | "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5", 767 | "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68", 768 | "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5" 769 | ], 770 | "version": "==6.1" 771 | }, 772 | "traitlets": { 773 | "hashes": [ 774 | "sha256:178f4ce988f69189f7e523337a3e11d91c786ded9360174a3d9ca83e79bc5396", 775 | "sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426" 776 | ], 777 | "version": "==5.0.5" 778 | }, 779 | "tzlocal": { 780 | "hashes": [ 781 | "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44", 782 | "sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4" 783 | ], 784 | "version": "==2.1" 785 | }, 786 | "urllib3": { 787 | "hashes": [ 788 | "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", 789 | "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" 790 | ], 791 | "version": "==1.26.2" 792 | }, 793 | "validators": { 794 | "hashes": [ 795 | "sha256:0143dcca8a386498edaf5780cbd5960da1a4c85e0719f3ee5c9b41249c4fefbd", 796 | "sha256:37cd9a9213278538ad09b5b9f9134266e7c226ab1fede1d500e29e0a8fbb9ea6" 797 | ], 798 | "version": "==0.18.2" 799 | }, 800 | "watchdog": { 801 | "hashes": [ 802 | "sha256:016b01495b9c55b5d4126ed8ae75d93ea0d99377084107c33162df52887cee18", 803 | "sha256:101532b8db506559e52a9b5d75a308729b3f68264d930670e6155c976d0e52a0", 804 | "sha256:27d9b4666938d5d40afdcdf2c751781e9ce36320788b70208d0f87f7401caf93", 805 | "sha256:2f1ade0d0802503fda4340374d333408831cff23da66d7e711e279ba50fe6c4a", 806 | "sha256:376cbc2a35c0392b0fe7ff16fbc1b303fd99d4dd9911ab5581ee9d69adc88982", 807 | "sha256:57f05e55aa603c3b053eed7e679f0a83873c540255b88d58c6223c7493833bac", 808 | "sha256:5f1f3b65142175366ba94c64d8d4c8f4015825e0beaacee1c301823266b47b9b", 809 | "sha256:602dbd9498592eacc42e0632c19781c3df1728ef9cbab555fab6778effc29eeb", 810 | "sha256:68744de2003a5ea2dfbb104f9a74192cf381334a9e2c0ed2bbe1581828d50b61", 811 | "sha256:85e6574395aa6c1e14e0f030d9d7f35c2340a6cf95d5671354ce876ac3ffdd4d", 812 | "sha256:b1d723852ce90a14abf0ec0ca9e80689d9509ee4c9ee27163118d87b564a12ac", 813 | "sha256:d948ad9ab9aba705f9836625b32e965b9ae607284811cd98334423f659ea537a", 814 | "sha256:e2a531e71be7b5cc3499ae2d1494d51b6a26684bcc7c3146f63c810c00e8a3cc", 815 | "sha256:e7c73edef48f4ceeebb987317a67e0080e5c9228601ff67b3c4062fa020403c7", 816 | "sha256:ee21aeebe6b3e51e4ba64564c94cee8dbe7438b9cb60f0bb350c4fa70d1b52c2", 817 | "sha256:f1d0e878fd69129d0d68b87cee5d9543f20d8018e82998efb79f7e412d42154a", 818 | "sha256:f84146f7864339c8addf2c2b9903271df21d18d2c721e9a77f779493234a82b5" 819 | ], 820 | "version": "==1.0.2" 821 | }, 822 | "wcwidth": { 823 | "hashes": [ 824 | "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784", 825 | "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83" 826 | ], 827 | "version": "==0.2.5" 828 | }, 829 | "webencodings": { 830 | "hashes": [ 831 | "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", 832 | "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" 833 | ], 834 | "version": "==0.5.1" 835 | }, 836 | "widgetsnbextension": { 837 | "hashes": [ 838 | "sha256:079f87d87270bce047512400efd70238820751a11d2d8cb137a5a5bdbaf255c7", 839 | "sha256:bd314f8ceb488571a5ffea6cc5b9fc6cba0adaf88a9d2386b93a489751938bcd" 840 | ], 841 | "version": "==3.5.1" 842 | } 843 | }, 844 | "develop": {} 845 | } 846 | --------------------------------------------------------------------------------