├── Dockerfile ├── README.md ├── app.py ├── docker-compose.yml ├── poetry.lock ├── pyproject.toml ├── src ├── model.py └── utils.py ├── static ├── css │ ├── ol3-sidebar.css │ └── ol3-sidebar.min.css └── js │ ├── main.js │ ├── ol3-sidebar.js │ └── ol3-sidebar.min.js └── template └── map.html /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8-slim-buster 2 | LABEL maintainer="csaybar -- Copernicus Master in Digital Earth (CDE)" 3 | 4 | # Global ARG 5 | ARG YOUR_ENV 6 | ENV YOUR_ENV=${YOUR_ENV} \ 7 | PYTHONFAULTHANDLER=1 \ 8 | PYTHONUNBUFFERED=1 \ 9 | PYTHONHASHSEED=random \ 10 | PIP_NO_CACHE_DIR=off \ 11 | PIP_DISABLE_PIP_VERSION_CHECK=on \ 12 | PIP_DEFAULT_TIMEOUT=100 \ 13 | POETRY_VERSION=1.0.0 14 | 15 | # Install Python3-dev 16 | RUN apt-get update && apt-get install -y python3-dev build-essential 17 | 18 | # Install poetry 19 | RUN pip install poetry==$POETRY_VERSION 20 | 21 | # Copy all files 22 | COPY . . 23 | 24 | # Init the project 25 | RUN poetry config virtualenvs.create false \ 26 | && poetry install $(test "$YOUR_ENV" == production && echo "--no-dev") --no-interaction --no-ansi 27 | 28 | EXPOSE 80 29 | 30 | CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "80"] 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |
3 | 4 |
5 | ee-fastapi: Flood Detection System 6 |
7 |

8 | 9 | 10 | A **ee-fastapi** is a simple [FastAPI](https://fastapi.tiangolo.com/) web application for performing flood detection using Google Earth Engine in the backend. The module [src/model.py](src/model.py) was adapted and translated to Python from [Radar-based Flood Mapping](https://www.un-spider.org/advisory-support/recommended-practices/recommended-practice-radar-based-flood-mapping). If you want to cite the methodology, takes a look at the bibliography available [here](https://www.un-spider.org/advisory-support/recommended-practices/recommended-practice-flood-mapping/in-detail). 11 | 12 | 13 | ### Installation 14 | 15 | 1. Install [Docker Compose](https://docs.docker.com/compose/install/) 16 | 17 | 2. Install the [EarthEngine Python API](https://developers.google.com/earth-engine/guides/python_install). You must have an active Earth Engine account (the credentials are copied to the app through [volumes](https://docs.docker.com/storage/volumes/)) 18 | 19 | 3. Run the command 20 | 21 | ``` 22 | docker-compose up 23 | ``` 24 | 25 | and point your browser to 26 | 27 | ``` 28 | 0.0.0.0:80 29 | ``` 30 | to start work 31 | 32 | 33 | ### Functionality 34 | 35 | **ee-fastapi** use ready-to-use data freely available in the [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets). **ee-fastapi** use the following public dataset: 36 | 37 | - [**Sentinel-1 GRD: C-band Synthetic Aperture Radar**](https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S1_GRD): A composite after and before the flood. Main resource. 38 | - [**MERIT DEM: Multi-Error-Removed Improved-Terrain DEM**](https://developers.google.com/earth-engine/datasets/catalog/MERIT_DEM_v1_0_3): To avoid areas with high slope. 39 | - [**JRC Global Surface Water Metadata, v.1.2**](https://developers.google.com/earth-engine/datasets/catalog/JRC_GSW1_2_Metadata): To avoid water body areas. 40 | 41 |

42 |
43 | 44 |
45 |

46 | 47 | 48 | Flood range dates, a hand-selected ROI, and the flood threshold are sent from the front-end to the back-end using [fetch](https://github.com/csaybar/ee-fastapi/blob/43f25d171a5bb17171d64de15af2d4170ca43c12/static/js/main.js#L158). The users control the response through two buttons: **display** and **download**. The display button will attach XYZ map tile resources with the results to the OpenLayer map. These tiles are obtained after running the model and the [ee.data.getMapId](https://developers.google.com/earth-engine/apidocs/ee-data-getmapid) method. On the other hand, the download button will download the flood area in a GeoPackage vector format. 49 | 50 |

51 |
52 | 53 |
54 |

55 | 56 | ### Design decisions 57 | 58 | #### Why OpenLayer? 59 | 60 | It was my first project using OpenLayer, and I can say that I did not miss Leaflet at all!. In my opinion, OpenLayers has much more advantages 61 | over Leaflet. Here are some reasons from the point of view of a novice Web GIS user: 62 | 63 | - OpenLayer counts with a complex API. There is no reason to load external plugins for simple tasks like in Leaflet. 64 | - Great documentation and thousand of examples. 65 | - Better map projection support 66 | - I found the OpenLayer API more intuitive. 67 | 68 | #### Why Google Earth Engine? 69 | 70 | Google Earth Engine has everything: tons of publicly available datasets, a great well-documented API, and high-performance computing. 71 | 72 | #### Why fetch? 73 | 74 | Fetch API does not need to be installed as a dependency. It utilizes a modern JS syntax and is based on promise rather than callbacks. 75 | 76 | 77 | ### Student personal information 78 | 79 | - **Name**: Cesar Luis Aybar Camacho 80 | - **Program**: Copernicus Master in Digital Earth – CDE 81 | - **Student ID**: s1078735 82 | - **Course**: Geo-application Development 83 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Request, Form 2 | from fastapi.middleware.cors import CORSMiddleware 3 | from fastapi.templating import Jinja2Templates 4 | from fastapi.staticfiles import StaticFiles 5 | 6 | from src.utils import searching_all_files, raster_to_vector 7 | from src.model import db_creator, flood_estimation, display 8 | from zipfile import ZipFile 9 | import geopandas as gpd 10 | import uvicorn 11 | import ee, os, time 12 | 13 | # from src.utils import load_credentials 14 | 15 | # Init Earth Engine 16 | # load_credentials() -> useful to deploy with heroku 17 | ee.Initialize() 18 | 19 | app = FastAPI() 20 | 21 | origins = [ 22 | "http://localhost", 23 | "http://localhost:8000" 24 | "http://localhost:8080", 25 | "http://127.0.0.1", 26 | "http://0.0.0.0", 27 | "http://0.0.0.0:80", 28 | "http://127.0.0.1:8000", 29 | "http://127.0.0.1:8080" 30 | ] 31 | app.add_middleware( 32 | CORSMiddleware, 33 | allow_origins=origins, 34 | allow_credentials=True, 35 | allow_methods=["*"], 36 | allow_headers=["*"], 37 | ) 38 | 39 | # mount static folder in the app 40 | app.mount("/static", StaticFiles(directory="static"), name="static") 41 | app.mount("/output", StaticFiles(directory="output"), name="output") 42 | 43 | # Load html templates 44 | templates = Jinja2Templates(directory="template") 45 | 46 | # display map 47 | @app.get("/") 48 | async def map(request: Request): 49 | return templates.TemplateResponse("map.html", {"request": request}) 50 | 51 | @app.post("/flood_download") 52 | async def flood_model(request: Request): 53 | # request parameters 54 | request_params = await request.json() 55 | 56 | # get parameters 57 | xmin, ymin, xmax, ymax = [float(x) for x in request_params["bbox"].split(",")] 58 | init_start = request_params["init_start"] 59 | init_last = request_params["init_last"] 60 | flood_start = request_params["flood_start"] 61 | flood_last = request_params["flood_last"] 62 | flood_threshold = float(request_params["flood_threshold"]) 63 | 64 | # 1. Create geometry 65 | ee_rectangle = ee.Geometry.Rectangle(xmin, ymin, xmax, ymax) 66 | 67 | # 2. Create range dates 68 | base_period = (init_start, init_last) 69 | flood_period = (flood_start, flood_last) 70 | 71 | # 3. Run the flood model 72 | dict_db = db_creator(base_period, flood_period, ee_rectangle) 73 | flood_added = flood_estimation(dict_db, difference_threshold=flood_threshold) 74 | 75 | # 4. Create GeoJSON 76 | geo_file_geojson = 'output/flood_area_%s.gpkg' % (time.strftime("%Y%m%d%H%M%S", time.gmtime())) 77 | final_flood_area = raster_to_vector(flood_added["flood_results"], ee_rectangle) 78 | final_flood_area_gpd = gpd.GeoDataFrame.from_features(final_flood_area["features"]) 79 | final_flood_area_gpd[final_flood_area_gpd.label == 1].to_file(geo_file_geojson, driver="GPKG") 80 | print(geo_file_geojson) 81 | return geo_file_geojson 82 | 83 | # model 84 | @app.post("/flood_display") 85 | async def flood_model(request: Request): 86 | # 1. request parameters 87 | request_params = await request.json() 88 | 89 | # 2. get parameters 90 | xmin, ymin, xmax, ymax = [float(x) for x in request_params["bbox"].split(",")] 91 | init_start = request_params["init_start"] 92 | init_last = request_params["init_last"] 93 | flood_start = request_params["flood_start"] 94 | flood_last = request_params["flood_last"] 95 | flood_threshold = float(request_params["flood_threshold"]) 96 | 97 | # 3. Create geometry 98 | ee_rectangle = ee.Geometry.Rectangle(xmin, ymin, xmax, ymax) 99 | 100 | # 4. Create range dates 101 | base_period = (init_start, init_last) 102 | flood_period = (flood_start, flood_last) 103 | 104 | # 5. Run the flood model 105 | dict_db = db_creator(base_period, flood_period, ee_rectangle) 106 | flood_added = flood_estimation(dict_db, difference_threshold=flood_threshold) 107 | 108 | # 6. Upload gee tileid 109 | tileids = display(flood_added) 110 | 111 | return tileids 112 | 113 | if __name__ == "__main__": 114 | uvicorn.run(app, host="0.0.0.0", port=80) -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | 3 | services: 4 | app: 5 | container_name: flood-fastapi 6 | image: flood/fastapi 7 | build: 8 | context: . 9 | dockerfile: Dockerfile 10 | ports: 11 | - "80:80" 12 | volumes: 13 | - $HOME/.config/earthengine:/root/.config/earthengine/ 14 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "aiofiles" 3 | version = "0.6.0" 4 | description = "File support for asyncio." 5 | category = "main" 6 | optional = false 7 | python-versions = "*" 8 | 9 | [[package]] 10 | name = "arrow" 11 | version = "1.0.3" 12 | description = "Better dates & times for Python" 13 | category = "main" 14 | optional = false 15 | python-versions = ">=3.6" 16 | 17 | [package.dependencies] 18 | python-dateutil = ">=2.7.0" 19 | 20 | [[package]] 21 | name = "atomicwrites" 22 | version = "1.4.0" 23 | description = "Atomic file writes." 24 | category = "dev" 25 | optional = false 26 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 27 | 28 | [[package]] 29 | name = "attrs" 30 | version = "20.3.0" 31 | description = "Classes Without Boilerplate" 32 | category = "main" 33 | optional = false 34 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 35 | 36 | [package.extras] 37 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] 38 | docs = ["furo", "sphinx", "zope.interface"] 39 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] 40 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] 41 | 42 | [[package]] 43 | name = "cachetools" 44 | version = "4.2.1" 45 | description = "Extensible memoizing collections and decorators" 46 | category = "main" 47 | optional = false 48 | python-versions = "~=3.5" 49 | 50 | [[package]] 51 | name = "certifi" 52 | version = "2020.12.5" 53 | description = "Python package for providing Mozilla's CA Bundle." 54 | category = "main" 55 | optional = false 56 | python-versions = "*" 57 | 58 | [[package]] 59 | name = "cffi" 60 | version = "1.14.5" 61 | description = "Foreign Function Interface for Python calling C code." 62 | category = "main" 63 | optional = false 64 | python-versions = "*" 65 | 66 | [package.dependencies] 67 | pycparser = "*" 68 | 69 | [[package]] 70 | name = "chardet" 71 | version = "4.0.0" 72 | description = "Universal encoding detector for Python 2 and 3" 73 | category = "main" 74 | optional = false 75 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 76 | 77 | [[package]] 78 | name = "click" 79 | version = "7.1.2" 80 | description = "Composable command line interface toolkit" 81 | category = "main" 82 | optional = false 83 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 84 | 85 | [[package]] 86 | name = "click-plugins" 87 | version = "1.1.1" 88 | description = "An extension module for click to enable registering CLI commands via setuptools entry-points." 89 | category = "main" 90 | optional = false 91 | python-versions = "*" 92 | 93 | [package.dependencies] 94 | click = ">=4.0" 95 | 96 | [package.extras] 97 | dev = ["pytest (>=3.6)", "pytest-cov", "wheel", "coveralls"] 98 | 99 | [[package]] 100 | name = "cligj" 101 | version = "0.7.1" 102 | description = "Click params for commmand line interfaces to GeoJSON" 103 | category = "main" 104 | optional = false 105 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <4" 106 | 107 | [package.dependencies] 108 | click = ">=4.0,<8" 109 | 110 | [package.extras] 111 | test = ["pytest-cov"] 112 | 113 | [[package]] 114 | name = "colorama" 115 | version = "0.4.4" 116 | description = "Cross-platform colored terminal text." 117 | category = "dev" 118 | optional = false 119 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 120 | 121 | [[package]] 122 | name = "earthengine-api" 123 | version = "0.1.262" 124 | description = "Earth Engine Python API" 125 | category = "main" 126 | optional = false 127 | python-versions = "*" 128 | 129 | [package.dependencies] 130 | future = "*" 131 | google-api-python-client = ">=1.12.1,<2" 132 | google-auth = ">=1.4.1" 133 | google-auth-httplib2 = ">=0.0.3" 134 | google-cloud-storage = "*" 135 | httplib2 = ">=0.9.2,<1dev" 136 | httplib2shim = "*" 137 | six = "*" 138 | 139 | [[package]] 140 | name = "fastapi" 141 | version = "0.63.0" 142 | description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" 143 | category = "main" 144 | optional = false 145 | python-versions = ">=3.6" 146 | 147 | [package.dependencies] 148 | pydantic = ">=1.0.0,<2.0.0" 149 | starlette = "0.13.6" 150 | 151 | [package.extras] 152 | all = ["requests (>=2.24.0,<3.0.0)", "aiofiles (>=0.5.0,<0.6.0)", "jinja2 (>=2.11.2,<3.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<2.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "graphene (>=2.1.8,<3.0.0)", "ujson (>=3.0.0,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.14.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)"] 153 | dev = ["python-jose[cryptography] (>=3.1.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.14.0)", "graphene (>=2.1.8,<3.0.0)"] 154 | doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=6.1.4,<7.0.0)", "markdown-include (>=0.5.1,<0.6.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.2.0)", "typer-cli (>=0.0.9,<0.0.10)", "pyyaml (>=5.3.1,<6.0.0)"] 155 | test = ["pytest (==5.4.3)", "pytest-cov (==2.10.0)", "pytest-asyncio (>=0.14.0,<0.15.0)", "mypy (==0.790)", "flake8 (>=3.8.3,<4.0.0)", "black (==20.8b1)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.15.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.4.0)", "orjson (>=3.2.1,<4.0.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "aiofiles (>=0.5.0,<0.6.0)", "flask (>=1.1.2,<2.0.0)"] 156 | 157 | [[package]] 158 | name = "fiona" 159 | version = "1.8.19" 160 | description = "Fiona reads and writes spatial data files" 161 | category = "main" 162 | optional = false 163 | python-versions = "*" 164 | 165 | [package.dependencies] 166 | attrs = ">=17" 167 | certifi = "*" 168 | click = ">=4.0,<8" 169 | click-plugins = ">=1.0" 170 | cligj = ">=0.5" 171 | munch = "*" 172 | six = ">=1.7" 173 | 174 | [package.extras] 175 | all = ["pytest (>=3)", "pytest-cov", "shapely", "boto3 (>=1.2.4)", "mock"] 176 | calc = ["shapely"] 177 | s3 = ["boto3 (>=1.2.4)"] 178 | test = ["pytest (>=3)", "pytest-cov", "boto3 (>=1.2.4)", "mock"] 179 | 180 | [[package]] 181 | name = "future" 182 | version = "0.18.2" 183 | description = "Clean single-source support for Python 3 and 2" 184 | category = "main" 185 | optional = false 186 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 187 | 188 | [[package]] 189 | name = "geopandas" 190 | version = "0.9.0" 191 | description = "Geographic pandas extensions" 192 | category = "main" 193 | optional = false 194 | python-versions = ">=3.6" 195 | 196 | [package.dependencies] 197 | fiona = ">=1.8" 198 | pandas = ">=0.24.0" 199 | pyproj = ">=2.2.0" 200 | shapely = ">=1.6" 201 | 202 | [[package]] 203 | name = "google-api-core" 204 | version = "1.26.3" 205 | description = "Google API client core library" 206 | category = "main" 207 | optional = false 208 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" 209 | 210 | [package.dependencies] 211 | google-auth = ">=1.21.1,<2.0dev" 212 | googleapis-common-protos = ">=1.6.0,<2.0dev" 213 | packaging = ">=14.3" 214 | protobuf = ">=3.12.0" 215 | pytz = "*" 216 | requests = ">=2.18.0,<3.0.0dev" 217 | six = ">=1.13.0" 218 | 219 | [package.extras] 220 | grpc = ["grpcio (>=1.29.0,<2.0dev)"] 221 | grpcgcp = ["grpcio-gcp (>=0.2.2)"] 222 | grpcio-gcp = ["grpcio-gcp (>=0.2.2)"] 223 | 224 | [[package]] 225 | name = "google-api-python-client" 226 | version = "1.12.8" 227 | description = "Google API Client Library for Python" 228 | category = "main" 229 | optional = false 230 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" 231 | 232 | [package.dependencies] 233 | google-api-core = ">=1.21.0,<2dev" 234 | google-auth = ">=1.16.0" 235 | google-auth-httplib2 = ">=0.0.3" 236 | httplib2 = ">=0.15.0,<1dev" 237 | six = ">=1.13.0,<2dev" 238 | uritemplate = ">=3.0.0,<4dev" 239 | 240 | [[package]] 241 | name = "google-auth" 242 | version = "1.29.0" 243 | description = "Google Authentication Library" 244 | category = "main" 245 | optional = false 246 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" 247 | 248 | [package.dependencies] 249 | cachetools = ">=2.0.0,<5.0" 250 | pyasn1-modules = ">=0.2.1" 251 | rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""} 252 | six = ">=1.9.0" 253 | 254 | [package.extras] 255 | aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"] 256 | pyopenssl = ["pyopenssl (>=20.0.0)"] 257 | reauth = ["pyu2f (>=0.1.5)"] 258 | 259 | [[package]] 260 | name = "google-auth-httplib2" 261 | version = "0.1.0" 262 | description = "Google Authentication Library: httplib2 transport" 263 | category = "main" 264 | optional = false 265 | python-versions = "*" 266 | 267 | [package.dependencies] 268 | google-auth = "*" 269 | httplib2 = ">=0.15.0" 270 | six = "*" 271 | 272 | [[package]] 273 | name = "google-cloud-core" 274 | version = "1.6.0" 275 | description = "Google Cloud API client core library" 276 | category = "main" 277 | optional = false 278 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" 279 | 280 | [package.dependencies] 281 | google-api-core = ">=1.21.0,<2.0.0dev" 282 | google-auth = ">=1.24.0,<2.0dev" 283 | six = ">=1.12.0" 284 | 285 | [package.extras] 286 | grpc = ["grpcio (>=1.8.2,<2.0dev)"] 287 | 288 | [[package]] 289 | name = "google-cloud-storage" 290 | version = "1.37.1" 291 | description = "Google Cloud Storage API client library" 292 | category = "main" 293 | optional = false 294 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" 295 | 296 | [package.dependencies] 297 | google-auth = ">=1.11.0,<2.0dev" 298 | google-cloud-core = ">=1.4.1,<2.0dev" 299 | google-resumable-media = ">=1.2.0,<2.0dev" 300 | requests = ">=2.18.0,<3.0.0dev" 301 | 302 | [[package]] 303 | name = "google-crc32c" 304 | version = "1.1.2" 305 | description = "A python wrapper of the C library 'Google CRC32C'" 306 | category = "main" 307 | optional = false 308 | python-versions = ">=3.6" 309 | 310 | [package.dependencies] 311 | cffi = ">=1.0.0" 312 | 313 | [package.extras] 314 | testing = ["pytest"] 315 | 316 | [[package]] 317 | name = "google-resumable-media" 318 | version = "1.2.0" 319 | description = "Utilities for Google Media Downloads and Resumable Uploads" 320 | category = "main" 321 | optional = false 322 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" 323 | 324 | [package.dependencies] 325 | google-crc32c = {version = ">=1.0,<2.0dev", markers = "python_version >= \"3.5\""} 326 | six = "*" 327 | 328 | [package.extras] 329 | aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"] 330 | requests = ["requests (>=2.18.0,<3.0.0dev)"] 331 | 332 | [[package]] 333 | name = "googleapis-common-protos" 334 | version = "1.53.0" 335 | description = "Common protobufs used in Google APIs" 336 | category = "main" 337 | optional = false 338 | python-versions = ">=3.6" 339 | 340 | [package.dependencies] 341 | protobuf = ">=3.12.0" 342 | 343 | [package.extras] 344 | grpc = ["grpcio (>=1.0.0)"] 345 | 346 | [[package]] 347 | name = "h11" 348 | version = "0.12.0" 349 | description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" 350 | category = "main" 351 | optional = false 352 | python-versions = ">=3.6" 353 | 354 | [[package]] 355 | name = "httplib2" 356 | version = "0.19.1" 357 | description = "A comprehensive HTTP client library." 358 | category = "main" 359 | optional = false 360 | python-versions = "*" 361 | 362 | [package.dependencies] 363 | pyparsing = ">=2.4.2,<3" 364 | 365 | [[package]] 366 | name = "httplib2shim" 367 | version = "0.0.3" 368 | description = "A wrapper over urllib3 that matches httplib2's interface" 369 | category = "main" 370 | optional = false 371 | python-versions = "*" 372 | 373 | [package.dependencies] 374 | certifi = "*" 375 | httplib2 = "*" 376 | six = "*" 377 | urllib3 = "*" 378 | 379 | [[package]] 380 | name = "idna" 381 | version = "2.10" 382 | description = "Internationalized Domain Names in Applications (IDNA)" 383 | category = "main" 384 | optional = false 385 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 386 | 387 | [[package]] 388 | name = "jinja2" 389 | version = "2.11.3" 390 | description = "A very fast and expressive template engine." 391 | category = "main" 392 | optional = false 393 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 394 | 395 | [package.dependencies] 396 | MarkupSafe = ">=0.23" 397 | 398 | [package.extras] 399 | i18n = ["Babel (>=0.8)"] 400 | 401 | [[package]] 402 | name = "jinja2-time" 403 | version = "0.2.0" 404 | description = "Jinja2 Extension for Dates and Times" 405 | category = "main" 406 | optional = false 407 | python-versions = "*" 408 | 409 | [package.dependencies] 410 | arrow = "*" 411 | jinja2 = "*" 412 | 413 | [[package]] 414 | name = "markupsafe" 415 | version = "1.1.1" 416 | description = "Safely add untrusted strings to HTML/XML markup." 417 | category = "main" 418 | optional = false 419 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" 420 | 421 | [[package]] 422 | name = "more-itertools" 423 | version = "8.7.0" 424 | description = "More routines for operating on iterables, beyond itertools" 425 | category = "dev" 426 | optional = false 427 | python-versions = ">=3.5" 428 | 429 | [[package]] 430 | name = "munch" 431 | version = "2.5.0" 432 | description = "A dot-accessible dictionary (a la JavaScript objects)" 433 | category = "main" 434 | optional = false 435 | python-versions = "*" 436 | 437 | [package.dependencies] 438 | six = "*" 439 | 440 | [package.extras] 441 | testing = ["pytest", "coverage", "astroid (>=1.5.3,<1.6.0)", "pylint (>=1.7.2,<1.8.0)", "astroid (>=2.0)", "pylint (>=2.3.1,<2.4.0)"] 442 | yaml = ["PyYAML (>=5.1.0)"] 443 | 444 | [[package]] 445 | name = "numpy" 446 | version = "1.20.2" 447 | description = "NumPy is the fundamental package for array computing with Python." 448 | category = "main" 449 | optional = false 450 | python-versions = ">=3.7" 451 | 452 | [[package]] 453 | name = "packaging" 454 | version = "20.9" 455 | description = "Core utilities for Python packages" 456 | category = "main" 457 | optional = false 458 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 459 | 460 | [package.dependencies] 461 | pyparsing = ">=2.0.2" 462 | 463 | [[package]] 464 | name = "pandas" 465 | version = "1.2.4" 466 | description = "Powerful data structures for data analysis, time series, and statistics" 467 | category = "main" 468 | optional = false 469 | python-versions = ">=3.7.1" 470 | 471 | [package.dependencies] 472 | numpy = ">=1.16.5" 473 | python-dateutil = ">=2.7.3" 474 | pytz = ">=2017.3" 475 | 476 | [package.extras] 477 | test = ["pytest (>=5.0.1)", "pytest-xdist", "hypothesis (>=3.58)"] 478 | 479 | [[package]] 480 | name = "pluggy" 481 | version = "0.13.1" 482 | description = "plugin and hook calling mechanisms for python" 483 | category = "dev" 484 | optional = false 485 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 486 | 487 | [package.extras] 488 | dev = ["pre-commit", "tox"] 489 | 490 | [[package]] 491 | name = "protobuf" 492 | version = "3.15.8" 493 | description = "Protocol Buffers" 494 | category = "main" 495 | optional = false 496 | python-versions = "*" 497 | 498 | [package.dependencies] 499 | six = ">=1.9" 500 | 501 | [[package]] 502 | name = "py" 503 | version = "1.10.0" 504 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 505 | category = "dev" 506 | optional = false 507 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 508 | 509 | [[package]] 510 | name = "pyasn1" 511 | version = "0.4.8" 512 | description = "ASN.1 types and codecs" 513 | category = "main" 514 | optional = false 515 | python-versions = "*" 516 | 517 | [[package]] 518 | name = "pyasn1-modules" 519 | version = "0.2.8" 520 | description = "A collection of ASN.1-based protocols modules." 521 | category = "main" 522 | optional = false 523 | python-versions = "*" 524 | 525 | [package.dependencies] 526 | pyasn1 = ">=0.4.6,<0.5.0" 527 | 528 | [[package]] 529 | name = "pycparser" 530 | version = "2.20" 531 | description = "C parser in Python" 532 | category = "main" 533 | optional = false 534 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 535 | 536 | [[package]] 537 | name = "pydantic" 538 | version = "1.8.1" 539 | description = "Data validation and settings management using python 3.6 type hinting" 540 | category = "main" 541 | optional = false 542 | python-versions = ">=3.6.1" 543 | 544 | [package.dependencies] 545 | typing-extensions = ">=3.7.4.3" 546 | 547 | [package.extras] 548 | dotenv = ["python-dotenv (>=0.10.4)"] 549 | email = ["email-validator (>=1.0.3)"] 550 | 551 | [[package]] 552 | name = "pyparsing" 553 | version = "2.4.7" 554 | description = "Python parsing module" 555 | category = "main" 556 | optional = false 557 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 558 | 559 | [[package]] 560 | name = "pyproj" 561 | version = "3.0.1" 562 | description = "Python interface to PROJ (cartographic projections and coordinate transformations library)" 563 | category = "main" 564 | optional = false 565 | python-versions = ">=3.6" 566 | 567 | [package.dependencies] 568 | certifi = "*" 569 | 570 | [[package]] 571 | name = "pytest" 572 | version = "5.4.3" 573 | description = "pytest: simple powerful testing with Python" 574 | category = "dev" 575 | optional = false 576 | python-versions = ">=3.5" 577 | 578 | [package.dependencies] 579 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 580 | attrs = ">=17.4.0" 581 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 582 | more-itertools = ">=4.0.0" 583 | packaging = "*" 584 | pluggy = ">=0.12,<1.0" 585 | py = ">=1.5.0" 586 | wcwidth = "*" 587 | 588 | [package.extras] 589 | checkqa-mypy = ["mypy (==v0.761)"] 590 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 591 | 592 | [[package]] 593 | name = "python-dateutil" 594 | version = "2.8.1" 595 | description = "Extensions to the standard Python datetime module" 596 | category = "main" 597 | optional = false 598 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 599 | 600 | [package.dependencies] 601 | six = ">=1.5" 602 | 603 | [[package]] 604 | name = "python-multipart" 605 | version = "0.0.5" 606 | description = "A streaming multipart parser for Python" 607 | category = "main" 608 | optional = false 609 | python-versions = "*" 610 | 611 | [package.dependencies] 612 | six = ">=1.4.0" 613 | 614 | [[package]] 615 | name = "pytz" 616 | version = "2021.1" 617 | description = "World timezone definitions, modern and historical" 618 | category = "main" 619 | optional = false 620 | python-versions = "*" 621 | 622 | [[package]] 623 | name = "requests" 624 | version = "2.25.1" 625 | description = "Python HTTP for Humans." 626 | category = "main" 627 | optional = false 628 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 629 | 630 | [package.dependencies] 631 | certifi = ">=2017.4.17" 632 | chardet = ">=3.0.2,<5" 633 | idna = ">=2.5,<3" 634 | urllib3 = ">=1.21.1,<1.27" 635 | 636 | [package.extras] 637 | security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] 638 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 639 | 640 | [[package]] 641 | name = "rsa" 642 | version = "4.7.2" 643 | description = "Pure-Python RSA implementation" 644 | category = "main" 645 | optional = false 646 | python-versions = ">=3.5, <4" 647 | 648 | [package.dependencies] 649 | pyasn1 = ">=0.1.3" 650 | 651 | [[package]] 652 | name = "shapely" 653 | version = "1.7.1" 654 | description = "Geometric objects, predicates, and operations" 655 | category = "main" 656 | optional = false 657 | python-versions = "*" 658 | 659 | [package.extras] 660 | all = ["numpy", "pytest", "pytest-cov"] 661 | test = ["pytest", "pytest-cov"] 662 | vectorized = ["numpy"] 663 | 664 | [[package]] 665 | name = "six" 666 | version = "1.15.0" 667 | description = "Python 2 and 3 compatibility utilities" 668 | category = "main" 669 | optional = false 670 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 671 | 672 | [[package]] 673 | name = "starlette" 674 | version = "0.13.6" 675 | description = "The little ASGI library that shines." 676 | category = "main" 677 | optional = false 678 | python-versions = ">=3.6" 679 | 680 | [package.extras] 681 | full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "ujson"] 682 | 683 | [[package]] 684 | name = "typing-extensions" 685 | version = "3.7.4.3" 686 | description = "Backported and Experimental Type Hints for Python 3.5+" 687 | category = "main" 688 | optional = false 689 | python-versions = "*" 690 | 691 | [[package]] 692 | name = "uritemplate" 693 | version = "3.0.1" 694 | description = "URI templates" 695 | category = "main" 696 | optional = false 697 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 698 | 699 | [[package]] 700 | name = "urllib3" 701 | version = "1.26.4" 702 | description = "HTTP library with thread-safe connection pooling, file post, and more." 703 | category = "main" 704 | optional = false 705 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 706 | 707 | [package.extras] 708 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] 709 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 710 | brotli = ["brotlipy (>=0.6.0)"] 711 | 712 | [[package]] 713 | name = "uvicorn" 714 | version = "0.13.4" 715 | description = "The lightning-fast ASGI server." 716 | category = "main" 717 | optional = false 718 | python-versions = "*" 719 | 720 | [package.dependencies] 721 | click = ">=7.0.0,<8.0.0" 722 | h11 = ">=0.8" 723 | 724 | [package.extras] 725 | standard = ["websockets (>=8.0.0,<9.0.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "httptools (>=0.1.0,<0.2.0)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] 726 | 727 | [[package]] 728 | name = "wcwidth" 729 | version = "0.2.5" 730 | description = "Measures the displayed width of unicode strings in a terminal" 731 | category = "dev" 732 | optional = false 733 | python-versions = "*" 734 | 735 | [metadata] 736 | lock-version = "1.1" 737 | python-versions = "^3.8" 738 | content-hash = "57e8fdcc5e19a467caa2be8b9b7021ab7f83869712f60c00e6669ad62b57153a" 739 | 740 | [metadata.files] 741 | aiofiles = [ 742 | {file = "aiofiles-0.6.0-py3-none-any.whl", hash = "sha256:bd3019af67f83b739f8e4053c6c0512a7f545b9a8d91aaeab55e6e0f9d123c27"}, 743 | {file = "aiofiles-0.6.0.tar.gz", hash = "sha256:e0281b157d3d5d59d803e3f4557dcc9a3dff28a4dd4829a9ff478adae50ca092"}, 744 | ] 745 | arrow = [ 746 | {file = "arrow-1.0.3-py3-none-any.whl", hash = "sha256:3515630f11a15c61dcb4cdd245883270dd334c83f3e639824e65a4b79cc48543"}, 747 | {file = "arrow-1.0.3.tar.gz", hash = "sha256:399c9c8ae732270e1aa58ead835a79a40d7be8aa109c579898eb41029b5a231d"}, 748 | ] 749 | atomicwrites = [ 750 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 751 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 752 | ] 753 | attrs = [ 754 | {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, 755 | {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, 756 | ] 757 | cachetools = [ 758 | {file = "cachetools-4.2.1-py3-none-any.whl", hash = "sha256:1d9d5f567be80f7c07d765e21b814326d78c61eb0c3a637dffc0e5d1796cb2e2"}, 759 | {file = "cachetools-4.2.1.tar.gz", hash = "sha256:f469e29e7aa4cff64d8de4aad95ce76de8ea1125a16c68e0d93f65c3c3dc92e9"}, 760 | ] 761 | certifi = [ 762 | {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, 763 | {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, 764 | ] 765 | cffi = [ 766 | {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"}, 767 | {file = "cffi-1.14.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1"}, 768 | {file = "cffi-1.14.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa"}, 769 | {file = "cffi-1.14.5-cp27-cp27m-win32.whl", hash = "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3"}, 770 | {file = "cffi-1.14.5-cp27-cp27m-win_amd64.whl", hash = "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5"}, 771 | {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482"}, 772 | {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6"}, 773 | {file = "cffi-1.14.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045"}, 774 | {file = "cffi-1.14.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa"}, 775 | {file = "cffi-1.14.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406"}, 776 | {file = "cffi-1.14.5-cp35-cp35m-win32.whl", hash = "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369"}, 777 | {file = "cffi-1.14.5-cp35-cp35m-win_amd64.whl", hash = "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315"}, 778 | {file = "cffi-1.14.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892"}, 779 | {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"}, 780 | {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"}, 781 | {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"}, 782 | {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"}, 783 | {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"}, 784 | {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"}, 785 | {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"}, 786 | {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"}, 787 | {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"}, 788 | {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"}, 789 | {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"}, 790 | {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"}, 791 | {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"}, 792 | {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"}, 793 | {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"}, 794 | {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"}, 795 | {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"}, 796 | {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"}, 797 | {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"}, 798 | {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"}, 799 | {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"}, 800 | {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"}, 801 | {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"}, 802 | {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"}, 803 | ] 804 | chardet = [ 805 | {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, 806 | {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, 807 | ] 808 | click = [ 809 | {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, 810 | {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, 811 | ] 812 | click-plugins = [ 813 | {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, 814 | {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, 815 | ] 816 | cligj = [ 817 | {file = "cligj-0.7.1-py3-none-any.whl", hash = "sha256:07171c1e287f45511f97df4ea071abc5d19924153413d5683a8e4866369bc676"}, 818 | {file = "cligj-0.7.1.tar.gz", hash = "sha256:b2f1f7247d59a5387bd3013a08b9ed6829e96fafa4a6e6292341efdb46fe6220"}, 819 | ] 820 | colorama = [ 821 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 822 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 823 | ] 824 | earthengine-api = [ 825 | {file = "earthengine-api-0.1.262.tar.gz", hash = "sha256:68902b20873960503e276c7481c127eda11746e470c151bca80830f508886144"}, 826 | ] 827 | fastapi = [ 828 | {file = "fastapi-0.63.0-py3-none-any.whl", hash = "sha256:98d8ea9591d8512fdadf255d2a8fa56515cdd8624dca4af369da73727409508e"}, 829 | {file = "fastapi-0.63.0.tar.gz", hash = "sha256:63c4592f5ef3edf30afa9a44fa7c6b7ccb20e0d3f68cd9eba07b44d552058dcb"}, 830 | ] 831 | fiona = [ 832 | {file = "Fiona-1.8.19-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4e54e9b176f42aa1243dbc9f89509866dc0242cffdde40948d0055041bc80735"}, 833 | {file = "Fiona-1.8.19-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:dd6ce1f64b535ad923d72a6e08eff3becb75d8f416e51c221c06c4fe49b86e3b"}, 834 | {file = "Fiona-1.8.19-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:553036b0891d5a8747759b7e16708e816e0dbb55322f392df7ebcb777133ef78"}, 835 | {file = "Fiona-1.8.19-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4a59f0d9044a4aeb2d8f098888a5c117997e45106b3382badc395d28b32d533"}, 836 | {file = "Fiona-1.8.19-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:658ce97ccd4022d4de75d2f68a087e9e74d5a894a2f8635fbb74d1a6bd9ddd49"}, 837 | {file = "Fiona-1.8.19-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c0e509661ed89f831218a17ba46a3d978be6f07491889d9b434888cfe646768f"}, 838 | {file = "Fiona-1.8.19-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6155f3be8ba00591898b1cdde06bef20901b25a4d3c2b4cf842c278a5169e65a"}, 839 | {file = "Fiona-1.8.19.tar.gz", hash = "sha256:b9059e0b29c2e9e6b817e53f941e77e1aca7075f986005d38db307067b60458f"}, 840 | ] 841 | future = [ 842 | {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, 843 | ] 844 | geopandas = [ 845 | {file = "geopandas-0.9.0-py2.py3-none-any.whl", hash = "sha256:79f6e557ba0dba76eec44f8351b1c6b42a17c38f5f08fef347e98fe4dae563c7"}, 846 | {file = "geopandas-0.9.0.tar.gz", hash = "sha256:63972ab4dc44c4029f340600dcb83264eb8132dd22b104da0b654bef7f42630a"}, 847 | ] 848 | google-api-core = [ 849 | {file = "google-api-core-1.26.3.tar.gz", hash = "sha256:b914345c7ea23861162693a27703bab804a55504f7e6e9abcaff174d80df32ac"}, 850 | {file = "google_api_core-1.26.3-py2.py3-none-any.whl", hash = "sha256:099762d4b4018cd536bcf85136bf337957da438807572db52f21dc61251be089"}, 851 | ] 852 | google-api-python-client = [ 853 | {file = "google-api-python-client-1.12.8.tar.gz", hash = "sha256:f3b9684442eec2cfe9f9bb48e796ef919456b82142c7528c5fd527e5224f08bb"}, 854 | {file = "google_api_python_client-1.12.8-py2.py3-none-any.whl", hash = "sha256:3c4c4ca46b5c21196bec7ee93453443e477d82cbfa79234d1ce0645f81170eaf"}, 855 | ] 856 | google-auth = [ 857 | {file = "google-auth-1.29.0.tar.gz", hash = "sha256:010f011c4e27d3d5eb01106fba6aac39d164842dfcd8709955c4638f5b11ccf8"}, 858 | {file = "google_auth-1.29.0-py2.py3-none-any.whl", hash = "sha256:f30a672a64d91cc2e3137765d088c5deec26416246f7a9e956eaf69a8d7ed49c"}, 859 | ] 860 | google-auth-httplib2 = [ 861 | {file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"}, 862 | {file = "google_auth_httplib2-0.1.0-py2.py3-none-any.whl", hash = "sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10"}, 863 | ] 864 | google-cloud-core = [ 865 | {file = "google-cloud-core-1.6.0.tar.gz", hash = "sha256:c6abb18527545379fc82efc4de75ce9a3772ccad2fc645adace593ba097cbb02"}, 866 | {file = "google_cloud_core-1.6.0-py2.py3-none-any.whl", hash = "sha256:40d9c2da2d03549b5ac3dcccf289d4f15e6d1210044c6381ce45c92913e62904"}, 867 | ] 868 | google-cloud-storage = [ 869 | {file = "google-cloud-storage-1.37.1.tar.gz", hash = "sha256:e06a4797c87ac73c4a74801539fdf0a91761c3014281ff58b7b29f15b34c206e"}, 870 | {file = "google_cloud_storage-1.37.1-py2.py3-none-any.whl", hash = "sha256:63a9dab155bf81c51354db3d11f3e83a1db7d58eff453f1ce51ffa565d32617b"}, 871 | ] 872 | google-crc32c = [ 873 | {file = "google-crc32c-1.1.2.tar.gz", hash = "sha256:dff5bd1236737f66950999d25de7a78144548ebac7788d30ada8c1b6ead60b27"}, 874 | {file = "google_crc32c-1.1.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:8ed8f6dc4f55850cba2eb22b78902ad37f397ee02692d3b8e00842e9af757321"}, 875 | {file = "google_crc32c-1.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:110157fb19ab5db15603debfaf5fcfbac9627576787d9caf8618ff96821a7a1f"}, 876 | {file = "google_crc32c-1.1.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:80abca603187093ea089cd1215c3779040dda55d3cdabc0cd5ea0e10df7bff99"}, 877 | {file = "google_crc32c-1.1.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6789db0b12aab12a0f04de22ed8412dfa5f6abd5a342ea19f15355064e1cc387"}, 878 | {file = "google_crc32c-1.1.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ea170341a4a9078a067b431044cd56c73553425833a7c2bb81734777a230ad4b"}, 879 | {file = "google_crc32c-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:a64e0e8ed6076a8d867fc4622ad821c55eba8dff1b48b18f56b7c2392e22ab9d"}, 880 | {file = "google_crc32c-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9372211acbcc207f63ffaffea1d05f3244a21311e4710721ffff3e8b7a0d24d0"}, 881 | {file = "google_crc32c-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:0ae3cf54e0d4d83c8af1afe96fc0970fbf32f1b29275f3bfd44ce25c4b622a2b"}, 882 | {file = "google_crc32c-1.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:34a97937f164147aefa53c3277364fd3bfa7fd244cbebbd5a976fa8325fb496b"}, 883 | {file = "google_crc32c-1.1.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:91ad96ee2958311d0bb75ffe5c25c87fb521ef547c09e04a8bb6143e75fb1367"}, 884 | {file = "google_crc32c-1.1.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b5ea1055fe470334ced844270e7c808b04fe31e3e6394675daa77f6789ca9eff"}, 885 | {file = "google_crc32c-1.1.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:e6458c41236d37cb982120b070ebcc115687c852bee24cdd18792da2640cf44d"}, 886 | {file = "google_crc32c-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:e5af77656e8d367701f40f80a91c985ca43319f322f0a36ba9f93909d0bc4cb2"}, 887 | {file = "google_crc32c-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:ae7b9e7e2ca1b06c3a68b6ef223947a52c30ffae329b1a2be3402756073f2732"}, 888 | {file = "google_crc32c-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:7c5138ed2e815189ba524756e027ac5833365e86115b1c2e6d9e833974a58d82"}, 889 | {file = "google_crc32c-1.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a6c8a712ffae56c805ca732b735af02860b246bed2c1acb38ea954a8b2dc4581"}, 890 | {file = "google_crc32c-1.1.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:49838ede42592154f9fcd21d07c7a43a67b00a36e252f82ae72542fde09dc51f"}, 891 | {file = "google_crc32c-1.1.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:ef2ed6d0ac4de4ac602903e203eccd25ec8e37f1446fe1a3d2953a658035e0a5"}, 892 | {file = "google_crc32c-1.1.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:51f4aa06125bf0641f65fb83268853545dbeb36b98ccfec69ef57dcb6b73b176"}, 893 | {file = "google_crc32c-1.1.2-cp38-cp38-win32.whl", hash = "sha256:1dc6904c0d958f43102c85d70792cca210d3d051ddbeecd0eff10abcd981fdfa"}, 894 | {file = "google_crc32c-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:298a9a922d35b123a73be80233d0f19c6ea01f008743561a8937f9dd83fb586b"}, 895 | {file = "google_crc32c-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:ab2b31395fbeeae6d15c98bd7f8b9fb76a18f18f87adc11b1f6dbe8f90d8382f"}, 896 | {file = "google_crc32c-1.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d4a0d4fb938c2c3c0076445c9bd1215a3bd3df557b88d8b05ec2889ca0c92f8d"}, 897 | {file = "google_crc32c-1.1.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:d0630670d27785d7e610e72752dc8087436d00d2c7115e149c0a754babb56d3e"}, 898 | {file = "google_crc32c-1.1.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:364eb36e8d9d34542c17b0c410035b0557edd4300a92ed736b237afaa0fd6dae"}, 899 | {file = "google_crc32c-1.1.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:0dd9b61d0c63043b013349c9ec8a83ec2b05c96410c5bc257da5d0de743fc171"}, 900 | {file = "google_crc32c-1.1.2-cp39-cp39-win32.whl", hash = "sha256:92ed6062792b989e84621e07a5f3d37da9cc3153b77d23a582921f14863af31d"}, 901 | {file = "google_crc32c-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:78cf5b1bd30f3a6033b41aa4ce8c796870bc4645a15d3ef47a4b05d31b0a6dc1"}, 902 | ] 903 | google-resumable-media = [ 904 | {file = "google-resumable-media-1.2.0.tar.gz", hash = "sha256:ee98b1921e5bda94867a08c864e55b4763d63887664f49ee1c231988f56b9d43"}, 905 | {file = "google_resumable_media-1.2.0-py2.py3-none-any.whl", hash = "sha256:dbe670cd7f02f3586705fd5a108c8ab8552fa36a1cad8afbc5a54e982cf34f0c"}, 906 | ] 907 | googleapis-common-protos = [ 908 | {file = "googleapis-common-protos-1.53.0.tar.gz", hash = "sha256:a88ee8903aa0a81f6c3cec2d5cf62d3c8aa67c06439b0496b49048fb1854ebf4"}, 909 | {file = "googleapis_common_protos-1.53.0-py2.py3-none-any.whl", hash = "sha256:f6d561ab8fb16b30020b940e2dd01cd80082f4762fa9f3ee670f4419b4b8dbd0"}, 910 | ] 911 | h11 = [ 912 | {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, 913 | {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, 914 | ] 915 | httplib2 = [ 916 | {file = "httplib2-0.19.1-py3-none-any.whl", hash = "sha256:2ad195faf9faf079723f6714926e9a9061f694d07724b846658ce08d40f522b4"}, 917 | {file = "httplib2-0.19.1.tar.gz", hash = "sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d"}, 918 | ] 919 | httplib2shim = [ 920 | {file = "httplib2shim-0.0.3.tar.gz", hash = "sha256:7c61daebd93ed7930df9ded4dbf47f87d35a8f29363d6e399fbf9fec930f8d17"}, 921 | ] 922 | idna = [ 923 | {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, 924 | {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, 925 | ] 926 | jinja2 = [ 927 | {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, 928 | {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, 929 | ] 930 | jinja2-time = [ 931 | {file = "jinja2-time-0.2.0.tar.gz", hash = "sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40"}, 932 | {file = "jinja2_time-0.2.0-py2.py3-none-any.whl", hash = "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa"}, 933 | ] 934 | markupsafe = [ 935 | {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, 936 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, 937 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, 938 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, 939 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, 940 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, 941 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, 942 | {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, 943 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, 944 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, 945 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, 946 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, 947 | {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, 948 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, 949 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, 950 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, 951 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, 952 | {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, 953 | {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5"}, 954 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, 955 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, 956 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f"}, 957 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0"}, 958 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7"}, 959 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, 960 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, 961 | {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, 962 | {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193"}, 963 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, 964 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, 965 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1"}, 966 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1"}, 967 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f"}, 968 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, 969 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, 970 | {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, 971 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, 972 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, 973 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2"}, 974 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032"}, 975 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b"}, 976 | {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, 977 | {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, 978 | {file = "MarkupSafe-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c"}, 979 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb"}, 980 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014"}, 981 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850"}, 982 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85"}, 983 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"}, 984 | {file = "MarkupSafe-1.1.1-cp39-cp39-win32.whl", hash = "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39"}, 985 | {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, 986 | {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, 987 | ] 988 | more-itertools = [ 989 | {file = "more-itertools-8.7.0.tar.gz", hash = "sha256:c5d6da9ca3ff65220c3bfd2a8db06d698f05d4d2b9be57e1deb2be5a45019713"}, 990 | {file = "more_itertools-8.7.0-py3-none-any.whl", hash = "sha256:5652a9ac72209ed7df8d9c15daf4e1aa0e3d2ccd3c87f8265a0673cd9cbc9ced"}, 991 | ] 992 | munch = [ 993 | {file = "munch-2.5.0-py2.py3-none-any.whl", hash = "sha256:6f44af89a2ce4ed04ff8de41f70b226b984db10a91dcc7b9ac2efc1c77022fdd"}, 994 | {file = "munch-2.5.0.tar.gz", hash = "sha256:2d735f6f24d4dba3417fa448cae40c6e896ec1fdab6cdb5e6510999758a4dbd2"}, 995 | ] 996 | numpy = [ 997 | {file = "numpy-1.20.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e9459f40244bb02b2f14f6af0cd0732791d72232bbb0dc4bab57ef88e75f6935"}, 998 | {file = "numpy-1.20.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a8e6859913ec8eeef3dbe9aed3bf475347642d1cdd6217c30f28dee8903528e6"}, 999 | {file = "numpy-1.20.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:9cab23439eb1ebfed1aaec9cd42b7dc50fc96d5cd3147da348d9161f0501ada5"}, 1000 | {file = "numpy-1.20.2-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9c0fab855ae790ca74b27e55240fe4f2a36a364a3f1ebcfd1fb5ac4088f1cec3"}, 1001 | {file = "numpy-1.20.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:61d5b4cf73622e4d0c6b83408a16631b670fc045afd6540679aa35591a17fe6d"}, 1002 | {file = "numpy-1.20.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:d15007f857d6995db15195217afdbddfcd203dfaa0ba6878a2f580eaf810ecd6"}, 1003 | {file = "numpy-1.20.2-cp37-cp37m-win32.whl", hash = "sha256:d76061ae5cab49b83a8cf3feacefc2053fac672728802ac137dd8c4123397677"}, 1004 | {file = "numpy-1.20.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bad70051de2c50b1a6259a6df1daaafe8c480ca98132da98976d8591c412e737"}, 1005 | {file = "numpy-1.20.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:719656636c48be22c23641859ff2419b27b6bdf844b36a2447cb39caceb00935"}, 1006 | {file = "numpy-1.20.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:aa046527c04688af680217fffac61eec2350ef3f3d7320c07fd33f5c6e7b4d5f"}, 1007 | {file = "numpy-1.20.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2428b109306075d89d21135bdd6b785f132a1f5a3260c371cee1fae427e12727"}, 1008 | {file = "numpy-1.20.2-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:e8e4fbbb7e7634f263c5b0150a629342cc19b47c5eba8d1cd4363ab3455ab576"}, 1009 | {file = "numpy-1.20.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:edb1f041a9146dcf02cd7df7187db46ab524b9af2515f392f337c7cbbf5b52cd"}, 1010 | {file = "numpy-1.20.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:c73a7975d77f15f7f68dacfb2bca3d3f479f158313642e8ea9058eea06637931"}, 1011 | {file = "numpy-1.20.2-cp38-cp38-win32.whl", hash = "sha256:6c915ee7dba1071554e70a3664a839fbc033e1d6528199d4621eeaaa5487ccd2"}, 1012 | {file = "numpy-1.20.2-cp38-cp38-win_amd64.whl", hash = "sha256:471c0571d0895c68da309dacee4e95a0811d0a9f9f532a48dc1bea5f3b7ad2b7"}, 1013 | {file = "numpy-1.20.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4703b9e937df83f5b6b7447ca5912b5f5f297aba45f91dbbbc63ff9278c7aa98"}, 1014 | {file = "numpy-1.20.2-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:abc81829c4039e7e4c30f7897938fa5d4916a09c2c7eb9b244b7a35ddc9656f4"}, 1015 | {file = "numpy-1.20.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:377751954da04d4a6950191b20539066b4e19e3b559d4695399c5e8e3e683bf6"}, 1016 | {file = "numpy-1.20.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:6e51e417d9ae2e7848314994e6fc3832c9d426abce9328cf7571eefceb43e6c9"}, 1017 | {file = "numpy-1.20.2-cp39-cp39-win32.whl", hash = "sha256:780ae5284cb770ade51d4b4a7dce4faa554eb1d88a56d0e8b9f35fca9b0270ff"}, 1018 | {file = "numpy-1.20.2-cp39-cp39-win_amd64.whl", hash = "sha256:924dc3f83de20437de95a73516f36e09918e9c9c18d5eac520062c49191025fb"}, 1019 | {file = "numpy-1.20.2-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:97ce8b8ace7d3b9288d88177e66ee75480fb79b9cf745e91ecfe65d91a856042"}, 1020 | {file = "numpy-1.20.2.zip", hash = "sha256:878922bf5ad7550aa044aa9301d417e2d3ae50f0f577de92051d739ac6096cee"}, 1021 | ] 1022 | packaging = [ 1023 | {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, 1024 | {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, 1025 | ] 1026 | pandas = [ 1027 | {file = "pandas-1.2.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c601c6fdebc729df4438ec1f62275d6136a0dd14d332fc0e8ce3f7d2aadb4dd6"}, 1028 | {file = "pandas-1.2.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8d4c74177c26aadcfb4fd1de6c1c43c2bf822b3e0fc7a9b409eeaf84b3e92aaa"}, 1029 | {file = "pandas-1.2.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:b730add5267f873b3383c18cac4df2527ac4f0f0eed1c6cf37fcb437e25cf558"}, 1030 | {file = "pandas-1.2.4-cp37-cp37m-win32.whl", hash = "sha256:2cb7e8f4f152f27dc93f30b5c7a98f6c748601ea65da359af734dd0cf3fa733f"}, 1031 | {file = "pandas-1.2.4-cp37-cp37m-win_amd64.whl", hash = "sha256:2111c25e69fa9365ba80bbf4f959400054b2771ac5d041ed19415a8b488dc70a"}, 1032 | {file = "pandas-1.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:167693a80abc8eb28051fbd184c1b7afd13ce2c727a5af47b048f1ea3afefff4"}, 1033 | {file = "pandas-1.2.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:612add929bf3ba9d27b436cc8853f5acc337242d6b584203f207e364bb46cb12"}, 1034 | {file = "pandas-1.2.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:971e2a414fce20cc5331fe791153513d076814d30a60cd7348466943e6e909e4"}, 1035 | {file = "pandas-1.2.4-cp38-cp38-win32.whl", hash = "sha256:68d7baa80c74aaacbed597265ca2308f017859123231542ff8a5266d489e1858"}, 1036 | {file = "pandas-1.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:bd659c11a4578af740782288cac141a322057a2e36920016e0fc7b25c5a4b686"}, 1037 | {file = "pandas-1.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9db70ffa8b280bb4de83f9739d514cd0735825e79eef3a61d312420b9f16b758"}, 1038 | {file = "pandas-1.2.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:298f0553fd3ba8e002c4070a723a59cdb28eda579f3e243bc2ee397773f5398b"}, 1039 | {file = "pandas-1.2.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52d2472acbb8a56819a87aafdb8b5b6d2b3386e15c95bde56b281882529a7ded"}, 1040 | {file = "pandas-1.2.4-cp39-cp39-win32.whl", hash = "sha256:d0877407359811f7b853b548a614aacd7dea83b0c0c84620a9a643f180060950"}, 1041 | {file = "pandas-1.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:2b063d41803b6a19703b845609c0b700913593de067b552a8b24dd8eeb8c9895"}, 1042 | {file = "pandas-1.2.4.tar.gz", hash = "sha256:649ecab692fade3cbfcf967ff936496b0cfba0af00a55dfaacd82bdda5cb2279"}, 1043 | ] 1044 | pluggy = [ 1045 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 1046 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 1047 | ] 1048 | protobuf = [ 1049 | {file = "protobuf-3.15.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fad4f971ec38d8df7f4b632c819bf9bbf4f57cfd7312cf526c69ce17ef32436a"}, 1050 | {file = "protobuf-3.15.8-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f17b352d7ce33c81773cf81d536ca70849de6f73c96413f17309f4b43ae7040b"}, 1051 | {file = "protobuf-3.15.8-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:4a054b0b5900b7ea7014099e783fb8c4618e4209fffcd6050857517b3f156e18"}, 1052 | {file = "protobuf-3.15.8-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:efa4c4d4fc9ba734e5e85eaced70e1b63fb3c8d08482d839eb838566346f1737"}, 1053 | {file = "protobuf-3.15.8-cp35-cp35m-win32.whl", hash = "sha256:07eec4e2ccbc74e95bb9b3afe7da67957947ee95bdac2b2e91b038b832dd71f0"}, 1054 | {file = "protobuf-3.15.8-cp35-cp35m-win_amd64.whl", hash = "sha256:f9cadaaa4065d5dd4d15245c3b68b967b3652a3108e77f292b58b8c35114b56c"}, 1055 | {file = "protobuf-3.15.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2dc0e8a9e4962207bdc46a365b63a3f1aca6f9681a5082a326c5837ef8f4b745"}, 1056 | {file = "protobuf-3.15.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f80afc0a0ba13339bbab25ca0409e9e2836b12bb012364c06e97c2df250c3343"}, 1057 | {file = "protobuf-3.15.8-cp36-cp36m-win32.whl", hash = "sha256:c5566f956a26cda3abdfacc0ca2e21db6c9f3d18f47d8d4751f2209d6c1a5297"}, 1058 | {file = "protobuf-3.15.8-cp36-cp36m-win_amd64.whl", hash = "sha256:dab75b56a12b1ceb3e40808b5bd9dfdaef3a1330251956e6744e5b6ed8f8830b"}, 1059 | {file = "protobuf-3.15.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3053f13207e7f13dc7be5e9071b59b02020172f09f648e85dc77e3fcb50d1044"}, 1060 | {file = "protobuf-3.15.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1f0b5d156c3df08cc54bc2c8b8b875648ea4cd7ebb2a9a130669f7547ec3488c"}, 1061 | {file = "protobuf-3.15.8-cp37-cp37m-win32.whl", hash = "sha256:90270fe5732c1f1ff664a3bd7123a16456d69b4e66a09a139a00443a32f210b8"}, 1062 | {file = "protobuf-3.15.8-cp37-cp37m-win_amd64.whl", hash = "sha256:f42c2f5fb67da5905bfc03733a311f72fa309252bcd77c32d1462a1ad519521e"}, 1063 | {file = "protobuf-3.15.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f6077db37bfa16494dca58a4a02bfdacd87662247ad6bc1f7f8d13ff3f0013e1"}, 1064 | {file = "protobuf-3.15.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:510e66491f1a5ac5953c908aa8300ec47f793130097e4557482803b187a8ee05"}, 1065 | {file = "protobuf-3.15.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5ff9fa0e67fcab442af9bc8d4ec3f82cb2ff3be0af62dba047ed4187f0088b7d"}, 1066 | {file = "protobuf-3.15.8-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1c0e9e56202b9dccbc094353285a252e2b7940b74fdf75f1b4e1b137833fabd7"}, 1067 | {file = "protobuf-3.15.8-py2.py3-none-any.whl", hash = "sha256:a0a08c6b2e6d6c74a6eb5bf6184968eefb1569279e78714e239d33126e753403"}, 1068 | {file = "protobuf-3.15.8.tar.gz", hash = "sha256:0277f62b1e42210cafe79a71628c1d553348da81cbd553402a7f7549c50b11d0"}, 1069 | ] 1070 | py = [ 1071 | {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, 1072 | {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, 1073 | ] 1074 | pyasn1 = [ 1075 | {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, 1076 | {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, 1077 | {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, 1078 | {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, 1079 | {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, 1080 | {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, 1081 | {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, 1082 | {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, 1083 | {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, 1084 | {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, 1085 | {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, 1086 | {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, 1087 | {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, 1088 | ] 1089 | pyasn1-modules = [ 1090 | {file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"}, 1091 | {file = "pyasn1_modules-0.2.8-py2.4.egg", hash = "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199"}, 1092 | {file = "pyasn1_modules-0.2.8-py2.5.egg", hash = "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"}, 1093 | {file = "pyasn1_modules-0.2.8-py2.6.egg", hash = "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb"}, 1094 | {file = "pyasn1_modules-0.2.8-py2.7.egg", hash = "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8"}, 1095 | {file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"}, 1096 | {file = "pyasn1_modules-0.2.8-py3.1.egg", hash = "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d"}, 1097 | {file = "pyasn1_modules-0.2.8-py3.2.egg", hash = "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45"}, 1098 | {file = "pyasn1_modules-0.2.8-py3.3.egg", hash = "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4"}, 1099 | {file = "pyasn1_modules-0.2.8-py3.4.egg", hash = "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811"}, 1100 | {file = "pyasn1_modules-0.2.8-py3.5.egg", hash = "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed"}, 1101 | {file = "pyasn1_modules-0.2.8-py3.6.egg", hash = "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0"}, 1102 | {file = "pyasn1_modules-0.2.8-py3.7.egg", hash = "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd"}, 1103 | ] 1104 | pycparser = [ 1105 | {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, 1106 | {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, 1107 | ] 1108 | pydantic = [ 1109 | {file = "pydantic-1.8.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0c40162796fc8d0aa744875b60e4dc36834db9f2a25dbf9ba9664b1915a23850"}, 1110 | {file = "pydantic-1.8.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:fff29fe54ec419338c522b908154a2efabeee4f483e48990f87e189661f31ce3"}, 1111 | {file = "pydantic-1.8.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:fbfb608febde1afd4743c6822c19060a8dbdd3eb30f98e36061ba4973308059e"}, 1112 | {file = "pydantic-1.8.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:eb8ccf12295113ce0de38f80b25f736d62f0a8d87c6b88aca645f168f9c78771"}, 1113 | {file = "pydantic-1.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:20d42f1be7c7acc352b3d09b0cf505a9fab9deb93125061b376fbe1f06a5459f"}, 1114 | {file = "pydantic-1.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dde4ca368e82791de97c2ec019681ffb437728090c0ff0c3852708cf923e0c7d"}, 1115 | {file = "pydantic-1.8.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:3bbd023c981cbe26e6e21c8d2ce78485f85c2e77f7bab5ec15b7d2a1f491918f"}, 1116 | {file = "pydantic-1.8.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:830ef1a148012b640186bf4d9789a206c56071ff38f2460a32ae67ca21880eb8"}, 1117 | {file = "pydantic-1.8.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:fb77f7a7e111db1832ae3f8f44203691e15b1fa7e5a1cb9691d4e2659aee41c4"}, 1118 | {file = "pydantic-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3bcb9d7e1f9849a6bdbd027aabb3a06414abd6068cb3b21c49427956cce5038a"}, 1119 | {file = "pydantic-1.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2287ebff0018eec3cc69b1d09d4b7cebf277726fa1bd96b45806283c1d808683"}, 1120 | {file = "pydantic-1.8.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4bbc47cf7925c86a345d03b07086696ed916c7663cb76aa409edaa54546e53e2"}, 1121 | {file = "pydantic-1.8.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:6388ef4ef1435364c8cc9a8192238aed030595e873d8462447ccef2e17387125"}, 1122 | {file = "pydantic-1.8.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:dd4888b300769ecec194ca8f2699415f5f7760365ddbe243d4fd6581485fa5f0"}, 1123 | {file = "pydantic-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:8fbb677e4e89c8ab3d450df7b1d9caed23f254072e8597c33279460eeae59b99"}, 1124 | {file = "pydantic-1.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2f2736d9a996b976cfdfe52455ad27462308c9d3d0ae21a2aa8b4cd1a78f47b9"}, 1125 | {file = "pydantic-1.8.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:3114d74329873af0a0e8004627f5389f3bb27f956b965ddd3e355fe984a1789c"}, 1126 | {file = "pydantic-1.8.1-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:258576f2d997ee4573469633592e8b99aa13bda182fcc28e875f866016c8e07e"}, 1127 | {file = "pydantic-1.8.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c17a0b35c854049e67c68b48d55e026c84f35593c66d69b278b8b49e2484346f"}, 1128 | {file = "pydantic-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:e8bc082afef97c5fd3903d05c6f7bb3a6af9fc18631b4cc9fedeb4720efb0c58"}, 1129 | {file = "pydantic-1.8.1-py3-none-any.whl", hash = "sha256:e3f8790c47ac42549dc8b045a67b0ca371c7f66e73040d0197ce6172b385e520"}, 1130 | {file = "pydantic-1.8.1.tar.gz", hash = "sha256:26cf3cb2e68ec6c0cfcb6293e69fb3450c5fd1ace87f46b64f678b0d29eac4c3"}, 1131 | ] 1132 | pyparsing = [ 1133 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, 1134 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, 1135 | ] 1136 | pyproj = [ 1137 | {file = "pyproj-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f942a976ea3de6a519cf48be30a12f465e44d0ac0c38a0d820ab3acfcc0a48a6"}, 1138 | {file = "pyproj-3.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:09db64a8088b23f001e574d92bcc3080bf7de44ddca152d0282a2b50c918a64a"}, 1139 | {file = "pyproj-3.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:cba99e171d744969e13a865ad28fa9c949c4400b0e9c431a802cdd804f52f632"}, 1140 | {file = "pyproj-3.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:81c06df20d09d621e52791c19ce3c880695fb430061e59c2472fa5467e890391"}, 1141 | {file = "pyproj-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:3e7e851e6d58c16ac2cd920a1bacb7fbb24758a6fcd7f234d594a88ebae04ec9"}, 1142 | {file = "pyproj-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:aa0a2981b25145523ca17a643c5be077fe13e514fdca9b6d1c412a95d723a5a5"}, 1143 | {file = "pyproj-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:708d6e01b9ff3d6dc62a5ad2d2ba1264a863eaa657c1a9bf713a10cc35d34553"}, 1144 | {file = "pyproj-3.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:36ba436675f9dea4ab3db7d9a32d3ff11c2fbb4d6690a83454d2f3c5c0b54041"}, 1145 | {file = "pyproj-3.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:489a96da87d8846c34c90da90e637544e4f4f50a13589b5aac54297f5ee1b01d"}, 1146 | {file = "pyproj-3.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:4a333f3e46fe8b2eb4647a3daa3a2cec52ddc6c107c653b45880526114942ee8"}, 1147 | {file = "pyproj-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:9e2ef75401f17062166d3fe53c555cd62c9577697a2f5ded916b23c54e5db497"}, 1148 | {file = "pyproj-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7bfaa34e8bb0510d4380310374deecd9e4328b9cf556925cfb45b5a94d5bbdbe"}, 1149 | {file = "pyproj-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9666d01faf4e758ac68f2c16695c90de49c3170e3760988bf76a34aae11f4e15"}, 1150 | {file = "pyproj-3.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c658afc8a6115b58b02aa53d27bf2a67c1b00b55067edb1b7711c6c7391cfaa9"}, 1151 | {file = "pyproj-3.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:fee7517bd389a1db7b8bebb18838d04dedca9eaacda01d353d98f5ee421f263e"}, 1152 | {file = "pyproj-3.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:86ef2fcd584a3222bf73e2befc24b2badd139b3371f4a1e88649978ef7649540"}, 1153 | {file = "pyproj-3.0.1-cp38-cp38-win32.whl", hash = "sha256:d27d40ec541ef69a5107bfcd85f40170e9e122ceb6315ce508cd44d199983d41"}, 1154 | {file = "pyproj-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:bc70b6adcfa713d89bc561673cb57af5fb3a1718cd7d57ec537430cd1007a864"}, 1155 | {file = "pyproj-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b845510255f9580d7e226dd3321a51c468cefb7be24e46415caf67caa4287c4"}, 1156 | {file = "pyproj-3.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7ae8e7052f18fde1884574da449010e94fa205ad27aeeaa34a097f49a1ed6a2b"}, 1157 | {file = "pyproj-3.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:a3805e026a5547be205a5e322c08e3069f0a48c63bbd53dbc7a8e3499bc66d58"}, 1158 | {file = "pyproj-3.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:1be7d54900eb7e2d1e637319080b3a047c70d1fb2f3c12d3400c0fa8a90cf440"}, 1159 | {file = "pyproj-3.0.1-cp39-cp39-win32.whl", hash = "sha256:09bead60769e69b592e8cb3ac51b5215f75e9bb9c213ce575031961deb48d6da"}, 1160 | {file = "pyproj-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:a3a8ab19232bf4f4bb2590536538881b7bd0c07df23e0c2a792402ca2476c197"}, 1161 | {file = "pyproj-3.0.1.tar.gz", hash = "sha256:bfbac35490dd17f706700673506eeb8170f8a2a63fb5878171d4e6eef242d141"}, 1162 | ] 1163 | pytest = [ 1164 | {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, 1165 | {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, 1166 | ] 1167 | python-dateutil = [ 1168 | {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, 1169 | {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, 1170 | ] 1171 | python-multipart = [ 1172 | {file = "python-multipart-0.0.5.tar.gz", hash = "sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"}, 1173 | ] 1174 | pytz = [ 1175 | {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, 1176 | {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, 1177 | ] 1178 | requests = [ 1179 | {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, 1180 | {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, 1181 | ] 1182 | rsa = [ 1183 | {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"}, 1184 | {file = "rsa-4.7.2.tar.gz", hash = "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"}, 1185 | ] 1186 | shapely = [ 1187 | {file = "Shapely-1.7.1-1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:46da0ea527da9cf9503e66c18bab6981c5556859e518fe71578b47126e54ca93"}, 1188 | {file = "Shapely-1.7.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4c10f317e379cc404f8fc510cd9982d5d3e7ba13a9cfd39aa251d894c6366798"}, 1189 | {file = "Shapely-1.7.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:17df66e87d0fe0193910aeaa938c99f0b04f67b430edb8adae01e7be557b141b"}, 1190 | {file = "Shapely-1.7.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:da38ed3d65b8091447dc3717e5218cc336d20303b77b0634b261bc5c1aa2bae8"}, 1191 | {file = "Shapely-1.7.1-cp35-cp35m-win32.whl", hash = "sha256:8e7659dd994792a0aad8fb80439f59055a21163e236faf2f9823beb63a380e19"}, 1192 | {file = "Shapely-1.7.1-cp35-cp35m-win_amd64.whl", hash = "sha256:791477edb422692e7dc351c5ed6530eb0e949a31b45569946619a0d9cd5f53cb"}, 1193 | {file = "Shapely-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e3afccf0437edc108eef1e2bb9cc4c7073e7705924eb4cd0bf7715cd1ef0ce1b"}, 1194 | {file = "Shapely-1.7.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8f15b6ce67dcc05b61f19c689b60f3fe58550ba994290ff8332f711f5aaa9840"}, 1195 | {file = "Shapely-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:60e5b2282619249dbe8dc5266d781cc7d7fb1b27fa49f8241f2167672ad26719"}, 1196 | {file = "Shapely-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:de618e67b64a51a0768d26a9963ecd7d338a2cf6e9e7582d2385f88ad005b3d1"}, 1197 | {file = "Shapely-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:182716ffb500d114b5d1b75d7fd9d14b7d3414cef3c38c0490534cc9ce20981a"}, 1198 | {file = "Shapely-1.7.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4f3c59f6dbf86a9fc293546de492f5e07344e045f9333f3a753f2dda903c45d1"}, 1199 | {file = "Shapely-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:6871acba8fbe744efa4f9f34e726d070bfbf9bffb356a8f6d64557846324232b"}, 1200 | {file = "Shapely-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:35be1c5d869966569d3dfd4ec31832d7c780e9df760e1fe52131105685941891"}, 1201 | {file = "Shapely-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:052eb5b9ba756808a7825e8a8020fb146ec489dd5c919e7d139014775411e688"}, 1202 | {file = "Shapely-1.7.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:90a3e2ae0d6d7d50ff2370ba168fbd416a53e7d8448410758c5d6a5920646c1d"}, 1203 | {file = "Shapely-1.7.1-cp38-cp38-win32.whl", hash = "sha256:a3774516c8a83abfd1ddffb8b6ec1b0935d7fe6ea0ff5c31a18bfdae567b4eba"}, 1204 | {file = "Shapely-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:6593026cd3f5daaea12bcc51ae5c979318070fefee210e7990cb8ac2364e79a1"}, 1205 | {file = "Shapely-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:617bf046a6861d7c6b44d2d9cb9e2311548638e684c2cd071d8945f24a926263"}, 1206 | {file = "Shapely-1.7.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b40cc7bb089ae4aa9ddba1db900b4cd1bce3925d2a4b5837b639e49de054784f"}, 1207 | {file = "Shapely-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2df5260d0f2983309776cb41bfa85c464ec07018d88c0ecfca23d40bfadae2f1"}, 1208 | {file = "Shapely-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:a5c3a50d823c192f32615a2a6920e8c046b09e07a58eba220407335a9cd2e8ea"}, 1209 | {file = "Shapely-1.7.1.tar.gz", hash = "sha256:1641724c1055459a7e2b8bbe47ba25bdc89554582e62aec23cb3f3ca25f9b129"}, 1210 | ] 1211 | six = [ 1212 | {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, 1213 | {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, 1214 | ] 1215 | starlette = [ 1216 | {file = "starlette-0.13.6-py3-none-any.whl", hash = "sha256:bd2ffe5e37fb75d014728511f8e68ebf2c80b0fa3d04ca1479f4dc752ae31ac9"}, 1217 | {file = "starlette-0.13.6.tar.gz", hash = "sha256:ebe8ee08d9be96a3c9f31b2cb2a24dbdf845247b745664bd8a3f9bd0c977fdbc"}, 1218 | ] 1219 | typing-extensions = [ 1220 | {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, 1221 | {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, 1222 | {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, 1223 | ] 1224 | uritemplate = [ 1225 | {file = "uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"}, 1226 | {file = "uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"}, 1227 | ] 1228 | urllib3 = [ 1229 | {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, 1230 | {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, 1231 | ] 1232 | uvicorn = [ 1233 | {file = "uvicorn-0.13.4-py3-none-any.whl", hash = "sha256:7587f7b08bd1efd2b9bad809a3d333e972f1d11af8a5e52a9371ee3a5de71524"}, 1234 | {file = "uvicorn-0.13.4.tar.gz", hash = "sha256:3292251b3c7978e8e4a7868f4baf7f7f7bb7e40c759ecc125c37e99cdea34202"}, 1235 | ] 1236 | wcwidth = [ 1237 | {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, 1238 | {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, 1239 | ] 1240 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "dev" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["csaybar "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.8" 9 | fastapi = "^0.63.0" 10 | uvicorn = "^0.13.4" 11 | aiofiles = "^0.6.0" 12 | Jinja2 = "^2.11.3" 13 | jinja2-time = "^0.2.0" 14 | earthengine-api = "^0.1.262" 15 | python-multipart = "^0.0.5" 16 | geopandas = "^0.9.0" 17 | 18 | [tool.poetry.dev-dependencies] 19 | pytest = "^5.2" 20 | 21 | [build-system] 22 | requires = ["poetry-core>=1.0.0"] 23 | build-backend = "poetry.core.masonry.api" 24 | -------------------------------------------------------------------------------- /src/model.py: -------------------------------------------------------------------------------- 1 | """SAR-FLOOD MAPPING USING A CHANGE DETECTION APPROACH 2 | 3 | This script use SAR Sentinel-1 images to generate a flood extent map. A 4 | change detection approach was chosen, where a before- and after-flood 5 | event image will be compared. The dataset available in the Earth Engine 6 | Data Catalog includes the following preprocessing steps: Thermal-Noise 7 | Removal, Radiometric calibration, and Terrain-correction. 8 | """ 9 | 10 | import ee 11 | 12 | # Earth Engine Viz Parameters 13 | geoviz_app = { 14 | "s1_img": {"min": -25, "max": 0}, 15 | "diff_s1": {"min": 0, "max": 2}, 16 | "flood": {"palette": "0000FF"}, 17 | "populationCountVis": { 18 | "min": 0, "max": 200.0, 19 | "palette": ['060606', '337663', '337663', 'ffffff'] 20 | }, 21 | "populationExposedVis": { 22 | "min": 0, "max": 200.0, 23 | "palette": ['yellow', 'orange', 'red'] 24 | }, 25 | "LCVis": { 26 | "min": 1.0, "max": 17.0, 27 | "palette": [ 28 | '05450a', '086a10', '54a708', '78d203', 29 | '009900', 'c6b044', 'dcd159', 'dade48', 30 | 'fbff13', 'b6ff05', '27ff87', 'c24f44', 31 | 'a5a5a5', 'ff6d4c', '69fff8', 'f9ffa4', 32 | '1c0dff' 33 | ] 34 | }, 35 | "croplandVis": {"min": 0, "max": 14.0, "palette": ['30b21c']}, 36 | "urbanVis": {"min": 0, "max": 13.0, "palette": ['grey']} 37 | } 38 | 39 | 40 | # Display basemap 41 | def display(dict_db): 42 | """ Display a basic Earth Engine map 43 | Returns: 44 | str: earthengine tiles googleapis 45 | """ 46 | 47 | # S1 before flood 48 | s1_bf = ee.Image.visualize(dict_db["before_flood"], **geoviz_app["s1_img"]) 49 | s1_bf_id = ee.data.getMapId({"image": s1_bf})["tile_fetcher"].url_format 50 | 51 | # S1 after flood 52 | s1_af = ee.Image.visualize(dict_db["after_flood"], **geoviz_app["s1_img"]) 53 | s1_af_id = ee.data.getMapId({"image": s1_af})["tile_fetcher"].url_format 54 | 55 | # Flood results 56 | s1_fresults = ee.Image.visualize(dict_db["flood_results"], **geoviz_app["flood"]) 57 | s1_fresults_id = ee.data.getMapId({"image": s1_fresults})["tile_fetcher"].url_format 58 | 59 | layer_to_display = { 60 | "before_flood": s1_bf_id, 61 | "after_flood": s1_af_id, 62 | "s1_fresults_id": s1_fresults_id 63 | } 64 | return layer_to_display 65 | 66 | # Extract date from meta data 67 | def dates(imgcol): 68 | range = imgcol.reduceColumns(ee.Reducer.minMax(), ["system:time_start"]) 69 | ee_min = ee.Date(range.get('min')).format('YYYY-MM-dd').getInfo() 70 | ee_max = ee.Date(range.get('max')).format('YYYY-MM-dd').getInfo() 71 | printed = "from %s to %s" % (ee_min, ee_max) 72 | return printed 73 | 74 | 75 | def db_creator(base_period , flood_period, geometry, polarization="VH", 76 | pass_direction="DESCENDING", quiet=False): 77 | 78 | # rename selected geometry feature 79 | aoi = ee.FeatureCollection(geometry) 80 | 81 | # Load and filter Sentinel-1 GRD data by predefined parameters 82 | collection = ee.ImageCollection("COPERNICUS/S1_GRD")\ 83 | .filter(ee.Filter.eq("instrumentMode", "IW"))\ 84 | .filter(ee.Filter.listContains("transmitterReceiverPolarisation", polarization))\ 85 | .filter(ee.Filter.eq("orbitProperties_pass",pass_direction))\ 86 | .filter(ee.Filter.eq("resolution_meters",10)) \ 87 | .filterBounds(aoi)\ 88 | .select(polarization) 89 | # .filter(ee.Filter.eq('relativeOrbitNumber_start', relative_orbit)) \ 90 | 91 | # Select images by predefined dates 92 | before_collection = collection.filterDate(base_period[0], base_period[1]) 93 | after_collection = collection.filterDate(flood_period[0], flood_period[1]) 94 | 95 | if quiet: 96 | # print dates of before images to console 97 | before_count = before_collection.size().getInfo() 98 | print("Tiles selected: Before Flood (%s) \n %s" % (before_count, dates(before_collection))) 99 | 100 | # print dates of after images to console 101 | after_count = before_collection.size().getInfo() 102 | print("Tiles selected: After Flood (%s) \n %s" % (after_count, dates(after_collection))) 103 | 104 | # Create a mosaic of selected tiles and clip to study area 105 | before = before_collection.mosaic().clip(aoi) 106 | after = after_collection.mosaic().clip(aoi) 107 | 108 | # Apply reduce the radar speckle by smoothing 109 | smoothing_radius = 50 110 | before_filtered = before.focal_mean(smoothing_radius, "circle", "meters") 111 | after_filtered = after.focal_mean(smoothing_radius, "circle", "meters") 112 | dict_preprocessing = dict(before_flood=before_filtered, 113 | after_flood=after_filtered, 114 | base_period=base_period, 115 | flood_period=flood_period, 116 | aoi=aoi, 117 | polarization=polarization) 118 | return dict_preprocessing 119 | 120 | 121 | def flood_estimation(dict_db, difference_threshold=1.25, stats=True): 122 | 123 | before_filtered = dict_db["before_flood"] 124 | after_filtered = dict_db["after_flood"] 125 | polarization = dict_db["polarization"] 126 | aoi = dict_db["aoi"] 127 | 128 | # Calculate the difference between the before and after images 129 | difference = after_filtered.divide(before_filtered) 130 | 131 | # Apply the predefined difference-threshold and create the flood extent mask 132 | threshold = difference_threshold 133 | difference_binary = difference.gt(threshold) 134 | 135 | # Refine flood result using additional datasets 136 | # Include JRC layer on surface water seasonality to mask flood pixels from areas 137 | # of "permanent" water (where there is water > 10 months of the year) 138 | swater = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select('seasonality') 139 | swater_mask = swater.gte(10).updateMask(swater.gte(10)) 140 | 141 | # Flooded layer where perennial water bodies (water > 10 mo/yr) is assigned a 0 value 142 | flooded_mask = difference_binary.where(swater_mask, 0) 143 | # final flooded area without pixels in perennial waterbodies 144 | flooded = flooded_mask.updateMask(flooded_mask) 145 | 146 | # Compute connectivity of pixels to eliminate those connected to 8 or fewer neighbours 147 | # This operation reduces noise of the flood extent product 148 | connections = flooded.connectedPixelCount() 149 | flooded = flooded.updateMask(connections.gte(8)) 150 | 151 | # Mask out areas with more than 5 percent slope using a Digital Elevation Model 152 | DEM = ee.Image('WWF/HydroSHEDS/03VFDEM') 153 | terrain = ee.Algorithms.Terrain(DEM) 154 | slope = terrain.select('slope') 155 | flooded = flooded.updateMask(slope.lt(5)) 156 | 157 | dict_db.update({"flood_results": flooded}) # add flood mask results to the db 158 | 159 | if stats: 160 | # Calculate flood extent area 161 | # Create a raster layer containing the area information of each pixel 162 | flood_pixelarea = flooded.select(polarization).multiply(ee.Image.pixelArea()) 163 | 164 | # Sum the areas of flooded pixels 165 | # default is set to 'bestEffort: true' in order to reduce compuation time, for a more 166 | # accurate result set bestEffort to false and increase 'maxPixels'. 167 | flood_stats = flood_pixelarea.reduceRegion( 168 | reducer=ee.Reducer.sum(), 169 | geometry=aoi, 170 | scale=10, # native resolution 171 | bestEffort=True 172 | ) 173 | 174 | # Convert the flood extent to hectares (area calculations are originally given in meters) 175 | flood_area_ha = flood_stats\ 176 | .getNumber(polarization)\ 177 | .divide(10000)\ 178 | .round() \ 179 | .getInfo() 180 | dict_db.update({"flood_area_stats":flood_area_ha}) # add flood stats results to the db 181 | return dict_db -------------------------------------------------------------------------------- /src/utils.py: -------------------------------------------------------------------------------- 1 | import os, re 2 | from pathlib import Path 3 | from typing import List 4 | 5 | # Copy the token to the container 6 | def load_credentials(): 7 | ee_token = os.environ['EARTHENGINE_TOKEN'] 8 | credential = '{"refresh_token":"%s"}' % ee_token 9 | credential_file_path = os.path.expanduser("~/.config/earthengine/") 10 | os.makedirs(credential_file_path,exist_ok=True) 11 | with open(credential_file_path + 'credentials', 'w') as file: 12 | file.write(credential) 13 | return True 14 | 15 | 16 | def replace_line(file_name: str, line_num: int, text: str): 17 | """ Replace a specific line in a file 18 | 19 | Args: 20 | file_name (str): file path 21 | line_num (int): line to replace. 22 | text (str): Text to put in the line. 23 | 24 | Returns: 25 | bool: If the line was replaced will return True. 26 | """ 27 | with open(file_name, 'r+') as f: 28 | lines = f.readlines() 29 | lines[line_num] = text 30 | f.writelines(lines) 31 | with open(file_name, 'w') as fw: 32 | fw.writelines(lines) 33 | return True 34 | 35 | def searching_all_files(path:str = ".", pattern : str="\.tiff$|\.csv$") -> List: 36 | dirpath = Path(path) 37 | assert(dirpath.is_dir()) 38 | file_list = [] 39 | for x in dirpath.iterdir(): 40 | if x.is_file() and re.search(pattern, x.as_posix()): 41 | file_list.append(x.absolute().as_posix()) 42 | elif x.is_dir(): 43 | file_list.extend(searching_all_files(x, pattern)) 44 | return file_list 45 | 46 | def raster_to_vector(image, geom): 47 | vector_img = image.unmask(0).reduceToVectors( 48 | geometry = geom, 49 | scale = 10, 50 | bestEffort =True 51 | ) 52 | return vector_img.getInfo() -------------------------------------------------------------------------------- /static/css/ol3-sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | position: absolute; 3 | top: 0; 4 | bottom: 0; 5 | width: 100%; 6 | overflow: hidden; 7 | z-index: 2000; } 8 | .sidebar.collapsed { 9 | width: 40px; } 10 | @media (min-width: 768px) { 11 | .sidebar { 12 | top: 6px; 13 | bottom: 6px; 14 | transition: width 500ms; } } 15 | @media (min-width: 768px) and (max-width: 991px) { 16 | .sidebar { 17 | width: 305px; } } 18 | @media (min-width: 992px) and (max-width: 1199px) { 19 | .sidebar { 20 | width: 390px; } } 21 | @media (min-width: 1200px) { 22 | .sidebar { 23 | width: 460px; } } 24 | 25 | .sidebar-left { 26 | left: 0; } 27 | @media (min-width: 768px) { 28 | .sidebar-left { 29 | left: 6px; } } 30 | 31 | .sidebar-right { 32 | right: 0; } 33 | @media (min-width: 768px) { 34 | .sidebar-right { 35 | right: 6px; } } 36 | 37 | .sidebar-tabs { 38 | top: 0; 39 | bottom: 0; 40 | height: 100%; 41 | background-color: rgba(0, 60, 136, 0.5); } 42 | .sidebar-left .sidebar-tabs { 43 | left: 0; } 44 | .sidebar-right .sidebar-tabs { 45 | right: 0; } 46 | .sidebar-tabs, .sidebar-tabs > ul { 47 | position: absolute; 48 | width: 40px; 49 | margin: 0; 50 | padding: 0; 51 | list-style-type: none; } 52 | .sidebar-tabs > li, .sidebar-tabs > ul > li { 53 | width: 100%; 54 | height: 40px; 55 | color: #fff; 56 | font-size: 12pt; 57 | overflow: hidden; 58 | transition: all 80ms; } 59 | .sidebar-tabs > li:hover, .sidebar-tabs > ul > li:hover { 60 | color: #fff; 61 | background-color: rgba(0, 60, 136, 0.6); } 62 | .sidebar-tabs > li.active, .sidebar-tabs > ul > li.active { 63 | color: #fff; 64 | background-color: #0074d9; } 65 | .sidebar-tabs > li.disabled, .sidebar-tabs > ul > li.disabled { 66 | color: rgba(255, 255, 255, 0.4); } 67 | .sidebar-tabs > li.disabled:hover, .sidebar-tabs > ul > li.disabled:hover { 68 | background: transparent; } 69 | .sidebar-tabs > li.disabled > a, .sidebar-tabs > ul > li.disabled > a { 70 | cursor: default; } 71 | .sidebar-tabs > li > a, .sidebar-tabs > ul > li > a { 72 | display: block; 73 | width: 100%; 74 | height: 100%; 75 | line-height: 40px; 76 | color: inherit; 77 | text-decoration: none; 78 | text-align: center; } 79 | .sidebar-tabs > ul + ul { 80 | bottom: 0; } 81 | 82 | .sidebar-content { 83 | position: absolute; 84 | top: 0; 85 | bottom: 0; 86 | background-color: rgba(255, 255, 255, 0.95); 87 | overflow-x: hidden; 88 | overflow-y: auto; } 89 | .sidebar-left .sidebar-content { 90 | left: 40px; 91 | right: 0; } 92 | .sidebar-right .sidebar-content { 93 | left: 0; 94 | right: 40px; } 95 | .sidebar.collapsed > .sidebar-content { 96 | overflow-y: hidden; } 97 | 98 | .sidebar-pane { 99 | display: none; 100 | left: 0; 101 | right: 0; 102 | box-sizing: border-box; 103 | padding: 10px 20px; } 104 | .sidebar-pane.active { 105 | display: block; } 106 | @media (min-width: 768px) and (max-width: 991px) { 107 | .sidebar-pane { 108 | min-width: 265px; } } 109 | @media (min-width: 992px) and (max-width: 1199px) { 110 | .sidebar-pane { 111 | min-width: 350px; } } 112 | @media (min-width: 1200px) { 113 | .sidebar-pane { 114 | min-width: 420px; } } 115 | 116 | .sidebar-header { 117 | margin: -10px -20px 0; 118 | height: 40px; 119 | padding: 0 20px; 120 | line-height: 40px; 121 | font-size: 14.4pt; 122 | color: #fff; 123 | background-color: #0074d9; } 124 | .sidebar-right .sidebar-header { 125 | padding-left: 40px; } 126 | 127 | .sidebar-close { 128 | position: absolute; 129 | top: 0; 130 | width: 40px; 131 | height: 40px; 132 | text-align: center; 133 | cursor: pointer; } 134 | .sidebar-left .sidebar-close { 135 | right: 0; } 136 | .sidebar-right .sidebar-close { 137 | left: 0; } 138 | 139 | .sidebar { 140 | background-color: rgba(255, 255, 255, 0.4); } 141 | @media (min-width: 768px) { 142 | .sidebar { 143 | border: 3px solid transparent; 144 | border-radius: 4px; } } 145 | 146 | .sidebar-left { 147 | border-right: 3px solid transparent; } 148 | 149 | .sidebar-right { 150 | border-left: 3px solid transparent; } 151 | 152 | .sidebar-tabs { 153 | overflow: hidden; } 154 | @media (min-width: 768px) { 155 | .sidebar-tabs { 156 | border-radius: 2px 0 0 2px; } 157 | .collapsed .sidebar-tabs { 158 | border-radius: 2px; } } 159 | 160 | @media (min-width: 768px) { 161 | .sidebar-content { 162 | border-radius: 0 2px 2px 0; } } 163 | 164 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 165 | margin-left: 46px; } 166 | @media (min-width: 768px) { 167 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 168 | transition: margin-left 500ms; } } 169 | @media (min-width: 768px) and (max-width: 991px) { 170 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 171 | margin-left: 317px; } } 172 | @media (min-width: 992px) and (max-width: 1199px) { 173 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 174 | margin-left: 402px; } } 175 | @media (min-width: 1200px) { 176 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 177 | margin-left: 472px; } } 178 | 179 | @media (min-width: 768px) { 180 | .sidebar-left.collapsed ~ .sidebar-map .ol-zoom, .sidebar-left.collapsed ~ .sidebar-map .ol-scale-line { 181 | margin-left: 52px; } } 182 | 183 | .sidebar-right ~ .sidebar-map .ol-rotate, 184 | .sidebar-right ~ .sidebar-map .ol-attribution, 185 | .sidebar-right ~ .sidebar-map .ol-full-screen { 186 | margin-right: 46px; } 187 | @media (min-width: 768px) { 188 | .sidebar-right ~ .sidebar-map .ol-rotate, 189 | .sidebar-right ~ .sidebar-map .ol-attribution, 190 | .sidebar-right ~ .sidebar-map .ol-full-screen { 191 | transition: margin-right 500ms; } } 192 | @media (min-width: 768px) and (max-width: 991px) { 193 | .sidebar-right ~ .sidebar-map .ol-rotate, 194 | .sidebar-right ~ .sidebar-map .ol-attribution, 195 | .sidebar-right ~ .sidebar-map .ol-full-screen { 196 | margin-right: 317px; } } 197 | @media (min-width: 992px) and (max-width: 1199px) { 198 | .sidebar-right ~ .sidebar-map .ol-rotate, 199 | .sidebar-right ~ .sidebar-map .ol-attribution, 200 | .sidebar-right ~ .sidebar-map .ol-full-screen { 201 | margin-right: 402px; } } 202 | @media (min-width: 1200px) { 203 | .sidebar-right ~ .sidebar-map .ol-rotate, 204 | .sidebar-right ~ .sidebar-map .ol-attribution, 205 | .sidebar-right ~ .sidebar-map .ol-full-screen { 206 | margin-right: 472px; } } 207 | 208 | @media (min-width: 768px) { 209 | .sidebar-right.collapsed ~ .sidebar-map .ol-rotate, 210 | .sidebar-right.collapsed ~ .sidebar-map .ol-attribution, 211 | .sidebar-right.collapsed ~ .sidebar-map .ol-full-screen { 212 | margin-right: 52px; } } 213 | -------------------------------------------------------------------------------- /static/css/ol3-sidebar.min.css: -------------------------------------------------------------------------------- 1 | .sidebar{position:absolute;top:0;bottom:0;width:100%;overflow:hidden;z-index:2000}.sidebar.collapsed{width:40px}@media (min-width:768px) and (max-width:991px){.sidebar{width:305px}.sidebar-pane{min-width:265px}}@media (min-width:992px) and (max-width:1199px){.sidebar{width:390px}}@media (min-width:1200px){.sidebar{width:460px}}.sidebar-left{left:0;border-right:3px solid transparent}.sidebar-right{right:0;border-left:3px solid transparent}@media (min-width:768px){.sidebar{top:6px;bottom:6px;transition:width .5s;border:3px solid transparent;border-radius:4px}.sidebar-left{left:6px}.sidebar-right{right:6px}}.sidebar-tabs{top:0;bottom:0;height:100%;background-color:rgba(0,60,136,.5)}.sidebar-left .sidebar-tabs{left:0}.sidebar-right .sidebar-tabs{right:0}.sidebar-tabs,.sidebar-tabs>ul{position:absolute;width:40px;margin:0;padding:0;list-style-type:none}.sidebar-tabs>li,.sidebar-tabs>ul>li{width:100%;height:40px;color:#fff;font-size:12pt;overflow:hidden;transition:80ms}.sidebar-tabs>li:hover,.sidebar-tabs>ul>li:hover{color:#fff;background-color:rgba(0,60,136,.6)}.sidebar-tabs>li.active,.sidebar-tabs>ul>li.active{color:#fff;background-color:#0074d9}.sidebar-tabs>li.disabled,.sidebar-tabs>ul>li.disabled{color:rgba(255,255,255,.4)}.sidebar-tabs>li.disabled:hover,.sidebar-tabs>ul>li.disabled:hover{background:0 0}.sidebar-tabs>li.disabled>a,.sidebar-tabs>ul>li.disabled>a{cursor:default}.sidebar-tabs>li>a,.sidebar-tabs>ul>li>a{display:block;width:100%;height:100%;line-height:40px;color:inherit;text-decoration:none;text-align:center}.sidebar-tabs>ul+ul{bottom:0}.sidebar-content{position:absolute;top:0;bottom:0;background-color:rgba(255,255,255,.95);overflow-x:hidden;overflow-y:auto}.sidebar-left .sidebar-content{left:40px;right:0}.sidebar-right .sidebar-content{left:0;right:40px}.sidebar.collapsed>.sidebar-content{overflow-y:hidden}.sidebar-pane{display:none;left:0;right:0;box-sizing:border-box;padding:10px 20px}.sidebar-pane.active{display:block}.sidebar-header{margin:-10px -20px 0;height:40px;padding:0 20px;line-height:40px;font-size:14.4pt;color:#fff;background-color:#0074d9}.sidebar-right .sidebar-header{padding-left:40px}.sidebar-close{position:absolute;top:0;width:40px;height:40px;text-align:center;cursor:pointer}.sidebar-left .sidebar-close{right:0}.sidebar-right .sidebar-close{left:0}.sidebar{background-color:rgba(255,255,255,.4)}.sidebar-tabs{overflow:hidden}.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{margin-left:46px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{margin-right:46px}@media (min-width:768px) and (max-width:991px){.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{margin-left:317px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{margin-right:317px}}@media (min-width:992px) and (max-width:1199px){.sidebar-pane{min-width:350px}.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{margin-left:402px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{margin-right:402px}}@media (min-width:1200px){.sidebar-pane{min-width:420px}.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{margin-left:472px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{margin-right:472px}}@media (min-width:768px){.sidebar-tabs{border-radius:2px 0 0 2px}.collapsed .sidebar-tabs{border-radius:2px}.sidebar-content{border-radius:0 2px 2px 0}.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{transition:margin-left .5s}.sidebar-left.collapsed~.sidebar-map .ol-scale-line,.sidebar-left.collapsed~.sidebar-map .ol-zoom{margin-left:52px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{transition:margin-right .5s}.sidebar-right.collapsed~.sidebar-map .ol-attribution,.sidebar-right.collapsed~.sidebar-map .ol-full-screen,.sidebar-right.collapsed~.sidebar-map .ol-rotate{margin-right:52px}} -------------------------------------------------------------------------------- /static/js/main.js: -------------------------------------------------------------------------------- 1 | var origin = "http://0.0.0.0" 2 | var port = "80" 3 | 4 | // raster layer (OSM) 5 | var raster = new ol.layer.Tile({ 6 | title:"OSM basemap", 7 | source: new ol.source.OSM(), 8 | }) 9 | 10 | // vector layer (bbox) 11 | var source = new ol.source.Vector({wrapX: false}); 12 | var vector = new ol.layer.Vector({ 13 | title:"geometry", 14 | source: source, 15 | }); 16 | 17 | // Map Creator 18 | function CreateMap(layers) { 19 | var map = new ol.Map({ 20 | target: 'map', 21 | layers: layers, 22 | view: new ol.View({ 23 | center: ol.proj.transform([34.09, -17.87], 'EPSG:4326', 'EPSG:3857'), 24 | zoom: 8 25 | }) 26 | }); 27 | return map 28 | } 29 | 30 | var map = CreateMap(layers=[raster, vector]); 31 | 32 | // Add sidebar 33 | var sidebar = new ol.control.Sidebar({ element: 'sidebar', position: 'left' }); 34 | map.addControl(sidebar); 35 | 36 | // Draw a box 37 | var draw; // global so we can remove it later 38 | function addInteraction() { 39 | draw = new ol.interaction.Draw({ 40 | source: source, 41 | type: "Circle", 42 | geometryFunction: ol.interaction.Draw.createBox() 43 | }); 44 | 45 | // Add vector draw layer to the main map 46 | map.addInteraction(draw); 47 | } 48 | 49 | // Handle change event. 50 | document.getElementById('undo').addEventListener('click', function () { 51 | map.getLayers().getArray().forEach(layer => { 52 | if (layer.values_.title == "Flood Area" | layer.values_.title == "After Flood" | layer.values_.title == "Before Flood"){ 53 | map.removeLayer(layer) 54 | } 55 | }); 56 | 57 | map.getLayers().getArray().forEach(layer => { 58 | if (layer.values_.title == "Flood Area" | layer.values_.title == "After Flood" | layer.values_.title == "Before Flood"){ 59 | map.removeLayer(layer) 60 | } 61 | }); 62 | 63 | var features = source.getFeatures(); 64 | var lastFeature = features[features.length - 1]; 65 | source.removeFeature(lastFeature); 66 | }); 67 | 68 | // Handle change event. 69 | document.getElementById('download').addEventListener('click', function () { 70 | 71 | document.getElementById('download').value = '...' 72 | 73 | // Obtain ROI 74 | var features = source.getFeatures(); 75 | var lastFeature = features[features.length - 1].clone(); 76 | var bbox = lastFeature.getGeometry().transform('EPSG:3857', 'EPSG:4326').getExtent().toString(); 77 | 78 | // Obtain Dates 79 | var init_start = document.getElementById("init_start").value; 80 | var init_last = document.getElementById("init_last").value; 81 | 82 | var flood_start = document.getElementById("flood_start").value; 83 | var flood_last = document.getElementById("flood_last").value; 84 | 85 | // Obtain threshold 86 | var flood_threshold = document.getElementById("threshold").value; 87 | 88 | const request = new Request( 89 | origin.concat(":").concat(port).concat("/flood_download/"), 90 | { 91 | method: 'POST', 92 | body: JSON.stringify( 93 | { 94 | bbox: bbox, 95 | init_start: init_start, 96 | init_last: init_last, 97 | flood_start: flood_start, 98 | flood_last: flood_last, 99 | flood_threshold: flood_threshold 100 | } 101 | ) 102 | } 103 | ); 104 | 105 | fetch(request) 106 | .then(response => { 107 | if (response.status === 200) { 108 | return response.json(); 109 | } else { 110 | throw new Error('Something went wrong on api server!'); 111 | } 112 | }) 113 | .then(response => { 114 | document.location.href = origin.concat(":").concat(port).concat("/").concat(response); 115 | document.getElementById('download').value = 'download' 116 | }).catch(error => { 117 | console.error(error); 118 | }); 119 | }); 120 | 121 | // Handle change event. 122 | document.getElementById('display').addEventListener('click', function () { 123 | 124 | document.getElementById('display').value = '...' 125 | 126 | // Obtain ROI 127 | var features = source.getFeatures(); 128 | var lastFeature = features[features.length - 1].clone(); 129 | var bbox = lastFeature.getGeometry().transform('EPSG:3857', 'EPSG:4326').getExtent().toString(); 130 | 131 | // Obtain Dates 132 | var init_start = document.getElementById("init_start").value; 133 | var init_last = document.getElementById("init_last").value; 134 | 135 | var flood_start = document.getElementById("flood_start").value; 136 | var flood_last = document.getElementById("flood_last").value; 137 | 138 | // Obtain threshold 139 | var flood_threshold = document.getElementById("threshold").value; 140 | 141 | const request = new Request( 142 | origin.concat(":").concat(port).concat("/flood_display/"), 143 | { 144 | method: 'POST', 145 | body: JSON.stringify( 146 | { 147 | bbox: bbox, 148 | init_start: init_start, 149 | init_last: init_last, 150 | flood_start: flood_start, 151 | flood_last: flood_last, 152 | flood_threshold: flood_threshold 153 | } 154 | ) 155 | } 156 | ); 157 | 158 | fetch(request) 159 | .then(response => { 160 | if (response.status === 200) { 161 | return response.json(); 162 | } else { 163 | throw new Error('Something went wrong on api server!'); 164 | } 165 | }) 166 | .then(response => { 167 | // Before Flood 168 | bflood = new ol.layer.Tile({ 169 | source: new ol.source.XYZ({ 170 | url: response["before_flood"] 171 | }), 172 | title: "Before Flood" 173 | }); 174 | // After Flood 175 | aflood = new ol.layer.Tile({ 176 | source: new ol.source.XYZ({ 177 | url: response["after_flood"] 178 | }), 179 | title: "After Flood", 180 | }); 181 | 182 | // Flood Area 183 | final = new ol.layer.Tile({ 184 | source: new ol.source.XYZ({ 185 | url: response["s1_fresults_id"] 186 | }), 187 | title: "Flood Area" 188 | }); 189 | 190 | map.addLayer(final); 191 | map.addLayer(aflood); 192 | map.addLayer(bflood); 193 | 194 | var layerSwitcher = new ol.control.LayerSwitcher(); 195 | map.addControl(layerSwitcher); 196 | document.getElementById('display').value = 'display' 197 | 198 | }).catch(error => { 199 | console.error(error); 200 | }); 201 | }); 202 | 203 | addInteraction() -------------------------------------------------------------------------------- /static/js/ol3-sidebar.js: -------------------------------------------------------------------------------- 1 | /* global ol */ 2 | 3 | ol.control.Sidebar = function (settings) { 4 | 5 | var defaults = { 6 | element: null, 7 | position: 'left' 8 | }, i, child; 9 | 10 | this._options = Object.assign({}, defaults, settings); 11 | 12 | ol.control.Control.call(this, { 13 | element: document.getElementById(this._options.element), 14 | target: this._options.target 15 | }); 16 | 17 | // Attach .sidebar-left/right class 18 | this.element.classList.add('sidebar-' + this._options.position); 19 | 20 | // Find sidebar > div.sidebar-content 21 | for (i = this.element.children.length - 1; i >= 0; i--) { 22 | child = this.element.children[i]; 23 | if (child.tagName === 'DIV' && 24 | child.classList.contains('sidebar-content')) { 25 | this._container = child; 26 | } 27 | } 28 | 29 | // Find sidebar ul.sidebar-tabs > li, sidebar .sidebar-tabs > ul > li 30 | this._tabitems = this.element.querySelectorAll('ul.sidebar-tabs > li, .sidebar-tabs > ul > li'); 31 | for (i = this._tabitems.length - 1; i >= 0; i--) { 32 | this._tabitems[i]._sidebar = this; 33 | } 34 | 35 | // Find sidebar > div.sidebar-content > div.sidebar-pane 36 | this._panes = []; 37 | this._closeButtons = []; 38 | for (i = this._container.children.length - 1; i >= 0; i--) { 39 | child = this._container.children[i]; 40 | if (child.tagName == 'DIV' && 41 | child.classList.contains('sidebar-pane')) { 42 | this._panes.push(child); 43 | 44 | var closeButtons = child.querySelectorAll('.sidebar-close'); 45 | for (var j = 0, len = closeButtons.length; j < len; j++) { 46 | this._closeButtons.push(closeButtons[j]); 47 | } 48 | } 49 | } 50 | }; 51 | 52 | if ('inherits' in ol) { 53 | ol.inherits(ol.control.Sidebar, ol.control.Control); 54 | } else { 55 | ol.control.Sidebar.prototype = Object.create(ol.control.Control.prototype); 56 | ol.control.Sidebar.prototype.constructor = ol.control.Sidebar; 57 | } 58 | 59 | ol.control.Sidebar.prototype.setMap = function(map) { 60 | var i, child; 61 | 62 | for (i = this._tabitems.length - 1; i >= 0; i--) { 63 | child = this._tabitems[i]; 64 | var sub = child.querySelector('a'); 65 | if (sub.hasAttribute('href') && sub.getAttribute('href').slice(0,1) == '#') { 66 | sub.onclick = this._onClick.bind(child); 67 | } 68 | } 69 | 70 | for (i = this._closeButtons.length - 1; i >= 0; i--) { 71 | child = this._closeButtons[i]; 72 | child.onclick = this._onCloseClick.bind(this); 73 | } 74 | }; 75 | 76 | ol.control.Sidebar.prototype.open = function(id) { 77 | var i, child; 78 | 79 | // hide old active contents and show new content 80 | for (i = this._panes.length - 1; i >= 0; i--) { 81 | child = this._panes[i]; 82 | if (child.id == id) 83 | child.classList.add('active'); 84 | else if (child.classList.contains('active')) 85 | child.classList.remove('active'); 86 | } 87 | 88 | // remove old active highlights and set new highlight 89 | for (i = this._tabitems.length - 1; i >= 0; i--) { 90 | child = this._tabitems[i]; 91 | if (child.querySelector('a').hash == '#' + id) 92 | child.classList.add('active'); 93 | else if (child.classList.contains('active')) 94 | child.classList.remove('active'); 95 | } 96 | 97 | // open sidebar (if necessary) 98 | if (this.element.classList.contains('collapsed')) { 99 | this.element.classList.remove('collapsed'); 100 | } 101 | 102 | return this; 103 | }; 104 | 105 | ol.control.Sidebar.prototype.close = function() { 106 | // remove old active highlights 107 | for (var i = this._tabitems.length - 1; i >= 0; i--) { 108 | var child = this._tabitems[i]; 109 | if (child.classList.contains('active')) 110 | child.classList.remove('active'); 111 | } 112 | 113 | // close sidebar 114 | if (!this.element.classList.contains('collapsed')) { 115 | this.element.classList.add('collapsed'); 116 | } 117 | 118 | return this; 119 | }; 120 | 121 | ol.control.Sidebar.prototype._onClick = function(evt) { 122 | evt.preventDefault(); 123 | if (this.classList.contains('active')) { 124 | this._sidebar.close(); 125 | } else if (!this.classList.contains('disabled')) { 126 | this._sidebar.open(this.querySelector('a').hash.slice(1)); 127 | } 128 | }; 129 | 130 | ol.control.Sidebar.prototype._onCloseClick = function() { 131 | this.close(); 132 | }; 133 | -------------------------------------------------------------------------------- /static/js/ol3-sidebar.min.js: -------------------------------------------------------------------------------- 1 | ol.control.Sidebar=function(t){var e,s;for(this._options=Object.assign({},{element:null,position:"left"},t),ol.control.Control.call(this,{element:document.getElementById(this._options.element),target:this._options.target}),this.element.classList.add("sidebar-"+this._options.position),e=this.element.children.length-1;e>=0;e--)"DIV"===(s=this.element.children[e]).tagName&&s.classList.contains("sidebar-content")&&(this._container=s);for(this._tabitems=this.element.querySelectorAll("ul.sidebar-tabs > li, .sidebar-tabs > ul > li"),e=this._tabitems.length-1;e>=0;e--)this._tabitems[e]._sidebar=this;for(this._panes=[],this._closeButtons=[],e=this._container.children.length-1;e>=0;e--)if("DIV"==(s=this._container.children[e]).tagName&&s.classList.contains("sidebar-pane")){this._panes.push(s);for(var i=s.querySelectorAll(".sidebar-close"),o=0,l=i.length;o=0;e--){var i=(s=this._tabitems[e]).querySelector("a");i.hasAttribute("href")&&"#"==i.getAttribute("href").slice(0,1)&&(i.onclick=this._onClick.bind(s))}for(e=this._closeButtons.length-1;e>=0;e--)(s=this._closeButtons[e]).onclick=this._onCloseClick.bind(this)},ol.control.Sidebar.prototype.open=function(t){var e,s;for(e=this._panes.length-1;e>=0;e--)(s=this._panes[e]).id==t?s.classList.add("active"):s.classList.contains("active")&&s.classList.remove("active");for(e=this._tabitems.length-1;e>=0;e--)(s=this._tabitems[e]).querySelector("a").hash=="#"+t?s.classList.add("active"):s.classList.contains("active")&&s.classList.remove("active");return this.element.classList.contains("collapsed")&&this.element.classList.remove("collapsed"),this},ol.control.Sidebar.prototype.close=function(){for(var t=this._tabitems.length-1;t>=0;t--){var e=this._tabitems[t];e.classList.contains("active")&&e.classList.remove("active")}return this.element.classList.contains("collapsed")||this.element.classList.add("collapsed"),this},ol.control.Sidebar.prototype._onClick=function(t){t.preventDefault(),this.classList.contains("active")?this._sidebar.close():this.classList.contains("disabled")||this._sidebar.open(this.querySelector("a").hash.slice(1))},ol.control.Sidebar.prototype._onCloseClick=function(){this.close()}; -------------------------------------------------------------------------------- /template/map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Flood Detection System 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 30 | 31 | 32 | 33 | 87 | 88 | 89 | 90 | 91 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | --------------------------------------------------------------------------------