├── .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 |
--------------------------------------------------------------------------------