From 466490d38bea5eb0b631ca60ddf62e5c69f8b63b Mon Sep 17 00:00:00 2001
From: Pingu Carsti <ehbrecht@dkrz.de>
Date: Wed, 11 Oct 2023 17:33:35 +0200
Subject: [PATCH] generated by cookiecutter

---
 .codacy.yml                            |   8 +
 .cruft.json                            |  27 +++
 .dockerignore                          |   3 +
 .editorconfig                          |  41 +++++
 .eggs/README.txt                       |   6 +
 .github/CONTRIBUTING.md                |   6 +
 .github/ISSUE_TEMPLATE.md              |  19 +++
 .github/PULL_REQUEST_TEMPLATE.md       |  13 ++
 .github/workflows/main.yml             |  39 +++++
 .gitignore                             | 219 ++++++++++---------------
 .readthedocs.yml                       |  30 ++++
 .travis.yml                            |  49 ++++++
 AUTHORS.rst                            |  13 ++
 CHANGES.rst                            |   7 +
 CONTRIBUTING.rst                       | 128 +++++++++++++++
 Dockerfile                             |  33 ++++
 LICENSE                                |  41 ++---
 MANIFEST.in                            |   7 +
 Makefile                               | 158 ++++++++++++++++++
 README.md                              |   2 -
 README.rst                             |  61 +++++++
 docker-compose.yml                     |  13 ++
 docs/Makefile                          |  20 +++
 docs/source/_static/README.txt         |   1 +
 docs/source/_static/birdhouse_logo.svg |  79 +++++++++
 docs/source/_static/favicon.ico        | Bin 0 -> 4286 bytes
 docs/source/authors.rst                |   1 +
 docs/source/changes.rst                |   1 +
 docs/source/conf.py                    | 215 ++++++++++++++++++++++++
 docs/source/configuration.rst          |  49 ++++++
 docs/source/dev_guide.rst              | 107 ++++++++++++
 docs/source/index.rst                  |  19 +++
 docs/source/installation.rst           | 113 +++++++++++++
 docs/source/notebooks/example.ipynb    |  48 ++++++
 docs/source/notebooks/index.rst        |   8 +
 docs/source/processes.rst              |  15 ++
 environment-docs.yml                   |  10 ++
 environment.yml                        |  13 ++
 etc/debug.cfg                          |   2 +
 etc/demo.cfg                           |   2 +
 etc/sample-custom.cfg                  |   6 +
 etc/sample-postgres.cfg                |   3 +
 requirements.txt                       |   4 +
 requirements_dev.txt                   |  16 ++
 setup.cfg                              |  50 ++++++
 setup.py                               |  66 ++++++++
 shearwater/__init__.py                 |   7 +
 shearwater/__version__.py              |   9 +
 shearwater/cli.py                      | 184 +++++++++++++++++++++
 shearwater/default.cfg                 |  20 +++
 shearwater/processes/__init__.py       |   5 +
 shearwater/processes/wps_say_hello.py  |  47 ++++++
 shearwater/templates/pywps.cfg         |  27 +++
 shearwater/wsgi.py                     |  17 ++
 tests/__init__.py                      |   1 +
 tests/common.py                        |  43 +++++
 tests/test_shearwater.py               |  26 +++
 tests/test_wps_caps.py                 |  16 ++
 tests/test_wps_hello.py                |  15 ++
 tox.ini                                |  29 ++++
 60 files changed, 2055 insertions(+), 162 deletions(-)
 create mode 100644 .codacy.yml
 create mode 100644 .cruft.json
 create mode 100644 .dockerignore
 create mode 100644 .editorconfig
 create mode 100644 .eggs/README.txt
 create mode 100644 .github/CONTRIBUTING.md
 create mode 100644 .github/ISSUE_TEMPLATE.md
 create mode 100644 .github/PULL_REQUEST_TEMPLATE.md
 create mode 100644 .github/workflows/main.yml
 create mode 100644 .readthedocs.yml
 create mode 100644 .travis.yml
 create mode 100644 AUTHORS.rst
 create mode 100644 CHANGES.rst
 create mode 100644 CONTRIBUTING.rst
 create mode 100644 Dockerfile
 create mode 100644 MANIFEST.in
 create mode 100644 Makefile
 delete mode 100644 README.md
 create mode 100644 README.rst
 create mode 100644 docker-compose.yml
 create mode 100644 docs/Makefile
 create mode 100644 docs/source/_static/README.txt
 create mode 100644 docs/source/_static/birdhouse_logo.svg
 create mode 100644 docs/source/_static/favicon.ico
 create mode 100644 docs/source/authors.rst
 create mode 100644 docs/source/changes.rst
 create mode 100755 docs/source/conf.py
 create mode 100644 docs/source/configuration.rst
 create mode 100644 docs/source/dev_guide.rst
 create mode 100644 docs/source/index.rst
 create mode 100644 docs/source/installation.rst
 create mode 100644 docs/source/notebooks/example.ipynb
 create mode 100644 docs/source/notebooks/index.rst
 create mode 100644 docs/source/processes.rst
 create mode 100644 environment-docs.yml
 create mode 100644 environment.yml
 create mode 100644 etc/debug.cfg
 create mode 100644 etc/demo.cfg
 create mode 100644 etc/sample-custom.cfg
 create mode 100644 etc/sample-postgres.cfg
 create mode 100644 requirements.txt
 create mode 100644 requirements_dev.txt
 create mode 100644 setup.cfg
 create mode 100644 setup.py
 create mode 100644 shearwater/__init__.py
 create mode 100644 shearwater/__version__.py
 create mode 100644 shearwater/cli.py
 create mode 100644 shearwater/default.cfg
 create mode 100644 shearwater/processes/__init__.py
 create mode 100644 shearwater/processes/wps_say_hello.py
 create mode 100644 shearwater/templates/pywps.cfg
 create mode 100644 shearwater/wsgi.py
 create mode 100644 tests/__init__.py
 create mode 100644 tests/common.py
 create mode 100644 tests/test_shearwater.py
 create mode 100644 tests/test_wps_caps.py
 create mode 100644 tests/test_wps_hello.py
 create mode 100644 tox.ini

diff --git a/.codacy.yml b/.codacy.yml
new file mode 100644
index 0000000..9700d78
--- /dev/null
+++ b/.codacy.yml
@@ -0,0 +1,8 @@
+---
+engines:
+ pylint:
+   enabled: true
+   python_version: 3
+exclude_paths:
+  - 'tests/**'
+  - 'docs/source/conf.py'
diff --git a/.cruft.json b/.cruft.json
new file mode 100644
index 0000000..b5cd0e3
--- /dev/null
+++ b/.cruft.json
@@ -0,0 +1,27 @@
+{
+  "template": "https://github.com/bird-house/cookiecutter-birdhouse.git",
+  "commit": "bc8a389e02a3e55e55dad7657671d91e2f238ed9",
+  "checkout": null,
+  "context": {
+    "cookiecutter": {
+      "full_name": "Carsten Ehbrecht",
+      "email": "ehbrecht@dkrz.de",
+      "github_username": "cehbrecht",
+      "project_name": "ShearWater",
+      "project_slug": "shearwater",
+      "project_repo_name": "shearwater",
+      "project_readthedocs_name": "shearwater",
+      "project_short_description": "A WPS for forecasting ctropical-cyclone activities.",
+      "version": "0.1.0",
+      "open_source_license": "Apache Software License 2.0",
+      "http_port": "5000",
+      "use_pytest": "y",
+      "create_author_file": "y",
+      "_copy_without_render": [
+        "{{cookiecutter.project_slug}}/templates/*.cfg"
+      ],
+      "_template": "https://github.com/bird-house/cookiecutter-birdhouse.git"
+    }
+  },
+  "directory": null
+}
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..e0d5f5a
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,3 @@
+.git
+docs/
+tests/
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..ad431c8
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,41 @@
+# http://editorconfig.org
+
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+trim_trailing_whitespace = true
+end_of_line = lf
+charset = utf-8
+
+# Docstrings and comments use max_line_length = 79
+[*.py]
+max_line_length = 120
+
+# Use 2 spaces for the HTML files
+[*.html]
+indent_size = 2
+
+# The JSON files contain newlines inconsistently
+[*.json]
+indent_size = 2
+insert_final_newline = ignore
+
+[**/admin/js/vendor/**]
+indent_style = ignore
+indent_size = ignore
+
+# Minified JavaScript files shouldn't be changed
+[**.min.js]
+indent_style = ignore
+insert_final_newline = ignore
+
+# Makefiles always use tabs for indentation
+[Makefile]
+indent_style = tab
+
+# Batch files use tabs for indentation
+[*.bat]
+indent_style = tab
diff --git a/.eggs/README.txt b/.eggs/README.txt
new file mode 100644
index 0000000..5d01668
--- /dev/null
+++ b/.eggs/README.txt
@@ -0,0 +1,6 @@
+This directory contains eggs that were downloaded by setuptools to build, test, and run plug-ins.
+
+This directory caches those eggs to prevent repeated downloads.
+
+However, it is safe to delete this directory.
+
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..6fc50c6
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,6 @@
+# Contributing
+
+Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
+
+Please read the Birdhouse [Developer Guide](https://birdhouse.readthedocs.io/en/latest/dev_guide.html)
+and the [ShearWater Documentation](https://shearwater.readthedocs.io/en/latest/) to get started.
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..e6206fd
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,19 @@
+## Description
+
+Describe what you were trying to get done or your feature request.
+
+## Environment
+
+* ShearWater version used, if any:
+* Python version, if any:
+* Operating System:
+
+## Steps to Reproduce
+
+```
+Paste the command(s) you ran and the output.
+```
+
+## Additional Information
+
+Links to other issues or sources.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..da62ccd
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,13 @@
+## Overview
+
+This PR fixes [issue id]
+
+Changes:
+
+* Added ...
+
+## Related Issue / Discussion
+
+## Additional Information
+
+Links to other issues or sources.
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..53960f5
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,39 @@
+
+name: build ⚙️
+
+on: [ push, pull_request ]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        python-version: [3.7, 3.8, 3.9]
+    steps:
+    - name: Checkout repository and submodules
+      uses: actions/checkout@v2
+      with:
+        submodules: recursive
+    - name: Install packages
+      run: |
+        sudo apt-get -y install pandoc
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v2
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install requirements 📦
+      run: |
+        python -m pip install --upgrade pip
+        pip install -e .
+        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+        if [ -f requirements_dev.txt ]; then pip install -r requirements_dev.txt; fi
+    - name: Test with pytest ⚙️
+      run: make test
+    - name: Lint with flake8 ⚙️
+      run: make lint
+      if: matrix.python-version == 3.7
+    - name: Build docs 🏗️
+      run: make docs
+      if: matrix.python-version == 3.7
+
diff --git a/.gitignore b/.gitignore
index 68bc17f..c9c2581 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,132 +1,96 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
+# installer
+#Makefile
 
-# C extensions
-*.so
+# Docker
+#Dockerfile
 
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
+# PyWPS
+custom.cfg
+.custom.cfg
+*.pid
+
+# Python / Extensions etc.
+*~
+*.mo
+*.so
+*.pyc
+*.pyo
 *.egg
-MANIFEST
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
+*.egg-info
+*.sqlite
+*.bak
+__pycache__
+
+# Unit test / Coverage reports
 .cache
+.pytest_cache
+.coverage
+.tox
 nosetests.xml
-coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-cover/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
+unit_tests/testdata.json
+coverage/
 
-# Flask stuff:
-instance/
-.webassets-cache
+# R
+*.Rhistory
 
-# Scrapy stuff:
-.scrapy
+# Eclipse / PyDev
+.project
+.pydevproject
+.settings
 
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-.pybuilder/
-target/
+# PyCharm
+*.idea
+
+# Kate
+*.kate-swp
+
+# Sublime Text Editor
+*.sublime*
+
+# buildout
+bin
+develop-eggs
+eggs
+parts
+build
+dist
+downloads
+.installed.cfg
+.mr.developer.cfg
+bootstrap-buildout.py
+bootstrap.py
+#generated by buildout
+
+*.pid
+
+# sphinx
+#docs/Makefile
+docs/make.bat
+docs/doctrees/
+docs/html/
+docs/build/
+docs/source/output-sanitize.cfg
+
+# External Sources
+#src/external
+src/
+
+# tests
+*.log
+*.lock
+testdata.json
 
-# Jupyter Notebook
+# IPython
 .ipynb_checkpoints
 
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-#   For a library or package, you might want to ignore these files since the code is
-#   intended to run in multiple environments; otherwise, check them in:
-# .python-version
-
-# pipenv
-#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-#   However, in case of collaboration, if having platform-specific dependencies or dependencies
-#   having no cross-platform support, pipenv may install dependencies that don't work, or not
-#   install all needed dependencies.
-#Pipfile.lock
-
-# poetry
-#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
-#   This is especially recommended for binary packages to ensure reproducibility, and is more
-#   commonly ignored for libraries.
-#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
-#poetry.lock
-
-# pdm
-#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
-#pdm.lock
-#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
-#   in version control.
-#   https://pdm.fming.dev/#use-with-ide
-.pdm.toml
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-venv/
-ENV/
-env.bak/
-venv.bak/
+# gcc/fortran
+*.o
+*.a
+*.mod
+*.out
+
+# Merge conflict
+*.orig
 
 # Spyder project settings
 .spyderproject
@@ -140,21 +104,6 @@ venv.bak/
 
 # mypy
 .mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# pytype static type analyzer
-.pytype/
 
-# Cython debug symbols
-cython_debug/
-
-# PyCharm
-#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
-#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
-#  and can be added to the global gitignore or merged into this file.  For a more nuclear
-#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
-#.idea/
+# IDE settings
+.vscode/
diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 0000000..d92d702
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,30 @@
+# .readthedocs.yml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Build documentation in the docs/ directory with Sphinx
+sphinx:
+  configuration: docs/source/conf.py
+  # fail_on_warning might generate hard to fix error, in this case it can be
+  # disabled but this also means those errors will fail silently, choose wisely.
+  fail_on_warning: true
+
+# Build documentation with MkDocs
+#mkdocs:
+#  configuration: mkdocs.yml
+
+# Optionally build your docs in additional formats such as PDF and ePub
+formats: all
+
+# Optionally set the version of Python and requirements required to build your docs
+#python:
+#  version: 3.6
+
+conda:
+  environment: environment-docs.yml
+
+build:
+  image: stable
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2fd6228
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,49 @@
+dist: xenial   # required for Python >= 3.7
+language: python
+os:
+  - linux
+python:
+  - "3.7"
+  - "3.8"
+  - "3.9"
+jobs:
+  include:
+    - os: osx
+      language: shell
+    - env: ALLOW_FAIL=true
+      python: "3.8"
+  allow_failures:
+    - env: ALLOW_FAIL=true
+
+before_install:
+  # Useful for debugging Travis CI environment
+  - printenv
+install:
+  # Python 3.x is default
+  - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh
+  - bash miniconda.sh -b -p $HOME/miniconda
+  - export PATH="$HOME/miniconda/bin:$PATH"
+  - hash -r
+  - conda config --set always_yes yes --set changeps1 no
+  - conda install setuptools
+  - conda update -q conda
+  # Useful for debugging any issues with conda
+  - conda info -a
+  # Prepare env with Python version
+  - conda create -n shearwater -c conda-forge python=$TRAVIS_PYTHON_VERSION
+  # Update now the env with our environment
+  - conda env update -f environment.yml
+  - source activate shearwater
+  # Packages for testing, generating docs and installing WPS
+  - make develop
+before_script:
+  # Start WPS service on port 5000 on 0.0.0.0
+  - shearwater start --daemon --bind-host 0.0.0.0 --port 5000
+  - sleep 2
+script:
+  - pytest
+  - make test-notebooks
+  - flake8
+  - make docs  # default html
+  - make SPHINXOPTS='-b epub' docs  # to match RtD
+  - make SPHINXOPTS='-b latex' docs  # to match RtD
diff --git a/AUTHORS.rst b/AUTHORS.rst
new file mode 100644
index 0000000..3faa8ed
--- /dev/null
+++ b/AUTHORS.rst
@@ -0,0 +1,13 @@
+=======
+Credits
+=======
+
+Development Lead
+----------------
+
+* Carsten Ehbrecht <ehbrecht@dkrz.de>
+
+Contributors
+------------
+
+None yet. Why not be the first?
diff --git a/CHANGES.rst b/CHANGES.rst
new file mode 100644
index 0000000..42b2e4e
--- /dev/null
+++ b/CHANGES.rst
@@ -0,0 +1,7 @@
+Changes
+*******
+
+0.1.0 (2023-10-11)
+==================
+
+* First release.
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
new file mode 100644
index 0000000..7a73e88
--- /dev/null
+++ b/CONTRIBUTING.rst
@@ -0,0 +1,128 @@
+.. highlight:: shell
+
+============
+Contributing
+============
+
+Contributions are welcome, and they are greatly appreciated! Every little bit
+helps, and credit will always be given.
+
+You can contribute in many ways:
+
+Types of Contributions
+----------------------
+
+Report Bugs
+~~~~~~~~~~~
+
+Report bugs at https://github.com/cehbrecht/shearwater/issues.
+
+If you are reporting a bug, please include:
+
+* Your operating system name and version.
+* Any details about your local setup that might be helpful in troubleshooting.
+* Detailed steps to reproduce the bug.
+
+Fix Bugs
+~~~~~~~~
+
+Look through the GitHub issues for bugs. Anything tagged with "bug" and "help
+wanted" is open to whoever wants to implement it.
+
+Implement Features
+~~~~~~~~~~~~~~~~~~
+
+Look through the GitHub issues for features. Anything tagged with "enhancement"
+and "help wanted" is open to whoever wants to implement it.
+
+Write Documentation
+~~~~~~~~~~~~~~~~~~~
+
+ShearWater could always use more documentation, whether as part of the
+official ShearWater docs, in docstrings, or even on the web in blog posts,
+articles, and such.
+
+Submit Feedback
+~~~~~~~~~~~~~~~
+
+The best way to send feedback is to file an issue at https://github.com/cehbrecht/shearwater/issues.
+
+If you are proposing a feature:
+
+* Explain in detail how it would work.
+* Keep the scope as narrow as possible, to make it easier to implement.
+* Remember that this is a volunteer-driven project, and that contributions
+  are welcome :)
+
+Get Started!
+------------
+
+Ready to contribute? Here's how to set up `shearwater` for local development.
+
+1. Fork the `shearwater` repo on GitHub.
+2. Clone your fork locally::
+
+    $ git clone git@github.com:your_name_here/shearwater.git
+
+3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development::
+
+    $ mkvirtualenv shearwater
+    $ cd shearwater/
+    $ python setup.py develop
+
+4. Create a branch for local development::
+
+    $ git checkout -b name-of-your-bugfix-or-feature
+
+   Now you can make your changes locally.
+
+5. When you're done making changes, check that your changes pass flake8 and the
+   tests, including testing other Python versions with tox::
+
+    $ flake8 shearwater tests
+    $ python setup.py test or pytest
+    $ tox
+
+   To get flake8 and tox, just pip install them into your virtualenv.
+
+6. Commit your changes and push your branch to GitHub::
+
+    $ git add .
+    $ git commit -m "Your detailed description of your changes."
+    $ git push origin name-of-your-bugfix-or-feature
+
+7. Submit a pull request through the GitHub website.
+
+Pull Request Guidelines
+-----------------------
+
+Before you submit a pull request, check that it meets these guidelines:
+
+1. The pull request should include tests.
+2. If the pull request adds functionality, the docs should be updated. Put
+   your new functionality into a function with a docstring, and add the
+   feature to the list in README.rst.
+3. The pull request should work for Python 3.5, 3.6, 3.7 and 3.8, and for PyPy. Check
+   https://travis-ci.com/cehbrecht/shearwater/pull_requests
+   and make sure that the tests pass for all supported Python versions.
+
+Tips
+----
+
+To run a subset of tests::
+
+$ pytest tests.test_shearwater
+
+
+Deploying
+---------
+
+A reminder for the maintainers on how to deploy.
+Make sure all your changes are committed (including an entry in HISTORY.rst).
+Then run::
+
+$ bump2version patch # possible: major / minor / patch
+$ git push
+$ git push --tags
+
+Travis will then deploy to PyPI if tests pass.
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..a2e0fe3
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,33 @@
+# vim:set ft=dockerfile:
+FROM continuumio/miniconda3
+MAINTAINER https://github.com/cehbrecht/shearwater
+LABEL Description="ShearWater WPS" Vendor="Birdhouse" Version="0.1.0"
+
+# Update Debian system
+RUN apt-get update && apt-get install -y \
+ build-essential \
+&& rm -rf /var/lib/apt/lists/*
+
+# Update conda
+RUN conda update -n base conda
+
+# Copy WPS project
+COPY . /opt/wps
+
+WORKDIR /opt/wps
+
+# Create conda environment with PyWPS
+RUN ["conda", "env", "create", "-n", "wps", "-f", "environment.yml"]
+
+# Install WPS
+RUN ["/bin/bash", "-c", "source activate wps && pip install -e ."]
+
+# Start WPS service on port 5000 on 0.0.0.0
+EXPOSE 5000
+ENTRYPOINT ["/bin/bash", "-c"]
+CMD ["source activate wps && exec shearwater start -b 0.0.0.0 -c /opt/wps/etc/demo.cfg"]
+
+# docker build -t cehbrecht/shearwater .
+# docker run -p 5000:5000 cehbrecht/shearwater
+# http://localhost:5000/wps?request=GetCapabilities&service=WPS
+# http://localhost:5000/wps?request=DescribeProcess&service=WPS&identifier=all&version=1.0.0
diff --git a/LICENSE b/LICENSE
index 261eeb9..b463e1c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,19 @@
+Apache Software License 2.0
+
+Copyright (c) 2023, Carsten Ehbrecht
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
                                  Apache License
                            Version 2.0, January 2004
                         http://www.apache.org/licenses/
@@ -173,29 +189,4 @@
       incurred by, or claims asserted against, such Contributor by reason
       of your accepting any such warranty or additional liability.
 
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
 
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..5a037a5
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,7 @@
+include Makefile
+include *.txt
+include *.rst
+include tox.ini
+recursive-include shearwater *
+global-exclude __pycache__
+global-exclude *.py[co]
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6ead2af
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,158 @@
+# Configuration
+APP_ROOT := $(abspath $(lastword $(MAKEFILE_LIST))/..)
+APP_NAME := shearwater
+
+WPS_URL = http://localhost:5000
+
+# Used in target refresh-notebooks to make it looks like the notebooks have
+# been refreshed from the production server below instead of from the local dev
+# instance so the notebooks can also be used as tutorial notebooks.
+OUTPUT_URL = https://pavics.ouranos.ca/wpsoutputs
+
+SANITIZE_FILE := https://github.com/Ouranosinc/PAVICS-e2e-workflow-tests/raw/master/notebooks/output-sanitize.cfg
+
+# end of configuration
+
+.DEFAULT_GOAL := help
+
+.PHONY: all
+all: help
+
+.PHONY: help
+help:
+	@echo "Please use 'make <target>' where <target> is one of:"
+	@echo "  help              to print this help message. (Default)"
+	@echo "  install           to install app by running 'pip install -e .'"
+	@echo "  develop           to install with additional development requirements."
+	@echo "  start             to start $(APP_NAME) service as daemon (background process)."
+	@echo "  stop              to stop $(APP_NAME) service."
+	@echo "  restart           to restart $(APP_NAME) service."
+	@echo "  status            to show status of $(APP_NAME) service."
+	@echo "  clean             to remove all files generated by build and tests."
+	@echo "\nTesting targets:"
+	@echo "  test              to run tests (but skip long running tests)."
+	@echo "  test-all          to run all tests (including long running tests)."
+	@echo "  test-notebooks    to verify Jupyter Notebook test outputs are valid."
+	@echo "  lint              to run code style checks with flake8."
+	@echo "  refresh-notebooks to verify Jupyter Notebook test outputs are valid."
+	@echo "\nSphinx targets:"
+	@echo "  docs              to generate HTML documentation with Sphinx."
+	@echo "\nDeployment targets:"
+	@echo "  dist              to build source and wheel package."
+
+## Build targets
+
+.PHONY: install
+install:
+	@echo "Installing application ..."
+	@-bash -c 'pip install -e .'
+	@echo "\nStart service with \`make start'"
+
+.PHONY: develop
+develop:
+	@echo "Installing development requirements for tests and docs ..."
+	@-bash -c 'pip install -e ".[dev]"'
+
+.PHONY: start
+start:
+	@echo "Starting application ..."
+	@-bash -c "$(APP_NAME) start -d"
+
+.PHONY: stop
+stop:
+	@echo "Stopping application ..."
+	@-bash -c "$(APP_NAME) stop"
+
+.PHONY: restart
+restart: stop start
+	@echo "Restarting application ..."
+
+.PHONY: status
+status:
+	@echo "Showing status ..."
+	@-bash -c "$(APP_NAME) status"
+
+.PHONY: clean
+clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts
+
+.PHONY: clean-build
+clean-build:
+	@echo "Removing build artifacts ..."
+	@-rm -fr build/
+	@-rm -fr dist/
+	@-rm -fr .eggs/
+	@-find . -name '*.egg-info' -exec rm -fr {} +
+	@-find . -name '*.egg' -exec rm -f {} +
+	@-find . -name '*.log' -exec rm -fr {} +
+	@-find . -name '*.sqlite' -exec rm -fr {} +
+
+.PHONY: clean-pyc
+clean-pyc:
+	@echo "Removing Python file artifacts ..."
+	@-find . -name '*.pyc' -exec rm -f {} +
+	@-find . -name '*.pyo' -exec rm -f {} +
+	@-find . -name '*~' -exec rm -f {} +
+	@-find . -name '__pycache__' -exec rm -fr {} +
+
+.PHONY: clean-test
+clean-test:
+	@echo "Removing test artifacts ..."
+	@-rm -fr .pytest_cache
+
+.PHONY: clean-dist
+clean-dist: clean
+	@echo "Running 'git clean' ..."
+	@git diff --quiet HEAD || echo "There are uncommitted changes! Aborting 'git clean' ..."
+	## do not use git clean -e/--exclude here, add them to .gitignore instead
+	@-git clean -dfx
+
+## Test targets
+
+.PHONY: test
+test:
+	@echo "Running tests (skip slow and online tests) ..."
+	@bash -c 'pytest -v -m "not slow and not online" tests/'
+
+.PHONY: test-all
+test-all:
+	@echo "Running all tests (including slow and online tests) ..."
+	@bash -c 'pytest -v tests/'
+
+.PHONY: notebook-sanitizer
+notebook-sanitizer:
+	@echo "Copying notebook output sanitizer ..."
+	@-bash -c "curl -L $(SANITIZE_FILE) -o $(CURDIR)/docs/source/output-sanitize.cfg --silent"
+
+.PHONY: test-notebooks
+test-notebooks: notebook-sanitizer
+	@echo "Running notebook-based tests"
+	@bash -c "env WPS_URL=$(WPS_URL) pytest --nbval --verbose $(CURDIR)/docs/source/notebooks/ --sanitize-with $(CURDIR)/docs/source/output-sanitize.cfg --ignore $(CURDIR)/docs/source/notebooks/.ipynb_checkpoints"
+
+.PHONY: lint
+lint:
+	@echo "Running flake8 code style checks ..."
+	@bash -c 'flake8'
+
+.PHONY: refresh-notebooks
+refresh-notebooks:
+	@echo "Refresh all notebook outputs under docs/source/notebooks"
+	@bash -c 'for nb in $(CURDIR)/docs/source/notebooks/*.ipynb; do WPS_URL="$(WPS_URL)" jupyter nbconvert --to notebook --execute --ExecutePreprocessor.timeout=60 --output "$$nb" "$$nb"; sed -i "s@$(WPS_URL)/outputs/@$(OUTPUT_URL)/@g" "$$nb"; done; cd $(APP_ROOT)'
+
+## Sphinx targets
+
+.PHONY: docs
+docs:
+	@echo "Generating docs with Sphinx ..."
+	@bash -c '$(MAKE) -C $@ clean html'
+	@echo "Open your browser to: file:/$(APP_ROOT)/docs/build/html/index.html"
+	## do not execute xdg-open automatically since it hangs travis and job does not complete
+	@echo "xdg-open $(APP_ROOT)/docs/build/html/index.html"
+
+## Deployment targets
+
+.PHONY: dist
+dist: clean
+	@echo "Building source and wheel package ..."
+	@-python setup.py sdist
+	@-python setup.py bdist_wheel
+	@-bash -c 'ls -l dist/'
diff --git a/README.md b/README.md
deleted file mode 100644
index 57e0a3e..0000000
--- a/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# shearwater
-ShearWater
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..6e1922f
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,61 @@
+==========
+ShearWater
+==========
+
+
+.. image:: https://img.shields.io/pypi/v/shearwater.svg
+        :target: https://pypi.python.org/pypi/shearwater
+
+.. image:: https://img.shields.io/travis/cehbrecht/shearwater.svg
+        :target: https://travis-ci.com/cehbrecht/shearwater
+
+.. image:: https://readthedocs.org/projects/shearwater/badge/?version=latest
+        :target: https://shearwater.readthedocs.io/en/latest/?version=latest
+        :alt: Documentation Status
+
+.. image:: https://img.shields.io/github/license/cehbrecht/shearwater.svg
+    :target: https://github.com/cehbrecht/shearwater/blob/master/LICENSE.txt
+    :alt: GitHub license
+
+.. image:: https://badges.gitter.im/bird-house/birdhouse.svg
+    :target: https://gitter.im/bird-house/birdhouse?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+    :alt: Join the chat at https://gitter.im/bird-house/birdhouse
+
+ShearWater (the bird)
+  *ShearWater is a bird ...*
+
+A WPS for forecasting ctropical-cyclone activities.
+
+Documentation
+-------------
+
+Learn more about ShearWater in its official documentation at
+https://shearwater.readthedocs.io.
+
+Submit bug reports, questions and feature requests at
+https://github.com/cehbrecht/shearwater/issues
+
+Contributing
+------------
+
+You can find information about contributing in our `Developer Guide`_.
+
+Please use bumpversion_ to release a new version.
+
+
+License
+-------
+
+* Free software: Apache Software License 2.0
+* Documentation: https://shearwater.readthedocs.io.
+
+
+Credits
+-------
+
+This package was created with Cookiecutter_ and the `bird-house/cookiecutter-birdhouse`_ project template.
+
+.. _Cookiecutter: https://github.com/audreyr/cookiecutter
+.. _`bird-house/cookiecutter-birdhouse`: https://github.com/bird-house/cookiecutter-birdhouse
+.. _`Developer Guide`: https://shearwater.readthedocs.io/en/latest/dev_guide.html
+.. _bumpversion: https://shearwater.readthedocs.io/en/latest/dev_guide.html#bump-a-new-version
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..42fa311
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,13 @@
+version: '3'
+services:
+  wps:
+    build: .
+    image: cehbrecht/shearwater
+    ports:
+      - "5000:5000"
+
+
+# docker-compose build
+# docker-compose up
+# docker-compose down
+# docker-compose rm
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..977d0c3
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+SPHINXPROJ    = shearwater
+SOURCEDIR     = source
+BUILDDIR      = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" -W $(SPHINXOPTS) $(O)
diff --git a/docs/source/_static/README.txt b/docs/source/_static/README.txt
new file mode 100644
index 0000000..764fc26
--- /dev/null
+++ b/docs/source/_static/README.txt
@@ -0,0 +1 @@
+Folder for static files
diff --git a/docs/source/_static/birdhouse_logo.svg b/docs/source/_static/birdhouse_logo.svg
new file mode 100644
index 0000000..1846d23
--- /dev/null
+++ b/docs/source/_static/birdhouse_logo.svg
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
+<g>
+	<path fill="#FEDD5C" d="M386.092,86.899c-17.118,11.915-6.297,36.889,1.396,52.732c-2.773-1.195-5.461-2.62-7.873-3.766
+		c14.626,17.896,15.354,44.354,30.257,62.835c2.789,3.454,5.631,7.194,9.526,9.875c-4.223-1.261-8.694-3.498-11.412-6.199
+		c5.274,10.776,12.915,20.854,21.859,29.31c-5.69-1.695-11.366-6.471-14.99-10.165l-0.097,0.098
+		c-0.376-0.476,4.752,7.829,6.816,13.01c7.942,19.954,0.953,38.476,21.281,58.429c-6.1-1.346-11.49-8.221-15.283-13.01
+		c-2.483,12.186,15.133,32.106,24.468,37.884l0.815,0.324c0.991-4.834,1.795-9.702,2.345-14.602
+		c1.111-10.069,1.461-20.222,1.011-30.347c-0.406-10.124-1.477-20.228-3.208-30.218c-1.659-10.004-3.966-19.904-6.837-29.632
+		c-1.42-4.871-2.993-9.696-4.729-14.463c-0.869-2.383-1.781-4.75-2.727-7.103c-0.935-2.358-1.917-4.696-2.939-7.02
+		c-2.031-4.636-4.341-9.185-6.594-13.769c-2.268-4.571-4.61-9.106-7.028-13.599c-4.808-9.007-9.971-17.824-15.607-26.374
+		c6.428,7.982,12.12,16.552,17.474,25.307c2.656,4.393,5.21,8.847,7.704,13.333c1.251,2.238,2.457,4.505,3.658,6.772
+		c1.204,2.267,2.377,4.576,3.496,6.899c1.118,2.325,2.199,4.672,3.229,7.038c1.025,2.369,1.99,4.761,2.926,7.166
+		c1.864,4.813,3.563,9.69,5.106,14.613c3.045,9.864,5.424,19.928,7.182,30.101c1.681,10.188,2.757,20.483,3.026,30.815
+		c0.221,10.327-0.229,20.692-1.768,30.92c-0.763,5.112-1.722,10.199-3.014,15.204c-1.289,5.006-2.83,9.944-4.689,14.761
+		c-2.42,6.229-5.359,12.27-8.86,17.934l0.048,0.006l-1.51,12.114c3.76-3.558,9.606-16.305,11.595-21.003
+		c2.881-6.786,6.076-14.56,8.268-22.303l0.252,0.068c15.606-12.315,29.812-28.504,33.593-48.706l-0.316-0.061
+		c-2.839,4.399-8.772,7.885-14.341,9.276c6.122-9.51,11.045-17.421,9.961-29.479c-1.325,5.544-5.639,10.049-10.945,11.408
+		c11.964-25.235,5.975-55.295-6.111-79.281c-3.093-6.133-6.549-11.911-10.21-17.704c0.154,4.034-0.367,8.159-1.315,12.257
+		c-2.378-15.406-9.61-29.778-16.955-43.412c1.041,5.681,0.915,10.91,0.348,16.37c-2.867-11.638-6.256-23.164-12.798-33.331
+		C423.791,106.125,403.643,74.68,386.092,86.899z"/>
+	<path fill="#2E3974" d="M93.208,113.689c11.452,17.431,36.706,7.281,52.749,0.014c-1.27,2.741-2.766,5.389-3.975,7.769
+		c18.279-14.142,44.748-14.162,63.62-28.563c3.528-2.697,7.343-5.438,10.127-9.26c-1.374,4.187-3.729,8.598-6.502,11.241
+		c10.913-4.984,21.192-12.352,29.885-21.067c-1.849,5.643-6.773,11.189-10.563,14.713l0.095,0.1
+		c-0.483,0.364,7.955-4.542,13.189-6.467c20.157-7.405,38.487,0.077,58.977-19.71c-1.509,6.061-8.524,11.267-13.414,14.93
+		c12.115,2.807,32.499-14.269,38.524-23.447l0.346-0.807c-4.805-1.12-9.65-2.052-14.534-2.734c-10.035-1.379-20.174-2-30.307-1.822
+		c-10.131,0.136-20.261,0.935-30.295,2.4c-10.044,1.391-20.002,3.432-29.803,6.041c-4.907,1.29-9.772,2.732-14.584,4.341
+		c-2.405,0.805-4.797,1.653-7.174,2.535c-2.382,0.871-4.746,1.79-7.096,2.751c-4.688,1.907-9.297,4.093-13.94,6.223
+		c-4.629,2.145-9.225,4.365-13.781,6.662c-9.134,4.564-18.085,9.49-26.782,14.897c8.15-6.212,16.869-11.673,25.765-16.79
+		c4.462-2.537,8.983-4.972,13.534-7.345c2.27-1.192,4.569-2.337,6.868-3.476c2.298-1.145,4.638-2.253,6.989-3.312
+		c2.354-1.055,4.729-2.072,7.122-3.038c2.396-0.961,4.813-1.862,7.241-2.733c4.861-1.735,9.78-3.303,14.745-4.715
+		c9.94-2.779,20.064-4.889,30.28-6.374c10.229-1.409,20.549-2.208,30.885-2.201c10.329,0.055,20.679,0.782,30.862,2.593
+		c5.09,0.9,10.149,1.993,15.118,3.42c4.968,1.422,9.863,3.095,14.628,5.082c6.163,2.587,12.123,5.686,17.692,9.338l0.007-0.048
+		l12.068,1.834c-3.454-3.854-16.042-10.04-20.685-12.153c-6.707-3.063-14.393-6.463-22.073-8.862l0.076-0.249
+		C317.2,29.47,301.397,14.837,281.303,10.518l-0.069,0.313c4.322,2.957,7.648,8.981,8.89,14.586
+		c-9.342-6.375-17.117-11.509-29.202-10.746c5.506,1.472,9.895,5.905,11.112,11.246c-24.907-12.636-55.116-7.452-79.417,3.988
+		c-6.213,2.927-12.081,6.228-17.97,9.733c4.036-0.047,8.146,0.585,12.218,1.642c-15.464,1.966-30.024,8.811-43.851,15.788
+		c5.707-0.888,10.931-0.622,16.373,0.09c-11.709,2.556-23.322,5.634-33.659,11.903C113.434,76.517,81.462,95.817,93.208,113.689z"/>
+	<path fill="#008380" d="M102.912,424.525c17.984-10.563,9.118-36.296,2.667-52.684c2.674,1.404,5.243,3.033,7.56,4.36
+		c-13.204-18.968-11.893-45.405-25.327-64.978c-2.516-3.658-5.062-7.605-8.738-10.579c4.113,1.583,8.398,4.157,10.9,7.06
+		c-4.429-11.15-11.271-21.787-19.537-30.907c5.542,2.129,10.834,7.328,14.163,11.289l0.104-0.091
+		c0.338,0.503-4.136-8.171-5.793-13.496c-6.383-20.505,2.011-38.435-16.719-59.894c5.976,1.811,10.822,9.081,14.235,14.147
+		c3.413-11.958-12.615-33.176-21.479-39.655l-0.788-0.387c-1.359,4.743-2.535,9.535-3.462,14.378
+		c-1.882,9.954-3.013,20.049-3.345,30.178c-0.374,10.125-0.085,20.281,0.874,30.375c0.883,10.102,2.42,20.149,4.533,30.07
+		c1.041,4.965,2.238,9.896,3.602,14.784c0.683,2.442,1.41,4.873,2.171,7.291c0.75,2.423,1.55,4.83,2.391,7.225
+		c1.669,4.78,3.622,9.492,5.514,14.236c1.907,4.732,3.896,9.435,5.96,14.101c4.101,9.35,8.569,18.538,13.532,27.498
+		c-5.796-8.454-10.812-17.438-15.475-26.577c-2.31-4.586-4.513-9.224-6.655-13.886c-1.074-2.329-2.103-4.683-3.125-7.035
+		c-1.027-2.354-2.017-4.746-2.955-7.148c-0.935-2.404-1.833-4.827-2.678-7.265c-0.838-2.441-1.617-4.9-2.363-7.37
+		c-1.488-4.942-2.807-9.935-3.966-14.963c-2.277-10.068-3.876-20.285-4.845-30.563c-0.891-10.287-1.17-20.635-0.645-30.957
+		c0.576-10.313,1.822-20.613,4.144-30.692c1.155-5.039,2.502-10.037,4.177-14.927c1.67-4.891,3.587-9.696,5.811-14.355
+		c2.895-6.024,6.29-11.82,10.217-17.199l-0.048-0.009l2.438-11.962c-4.022,3.256-10.835,15.517-13.179,20.047
+		c-3.396,6.544-7.179,14.048-9.961,21.6l-0.245-0.087c-16.508,11.077-31.917,26.124-37.242,45.975l0.31,0.085
+		c3.168-4.168,9.354-7.187,15.013-8.146c-6.836,9.01-12.354,16.519-12.2,28.625c1.748-5.425,6.394-9.585,11.791-10.532
+		c-13.871,24.24-10.216,54.671-0.013,79.517c2.611,6.353,5.613,12.379,8.817,18.438c0.155-4.034,0.994-8.106,2.255-12.12
+		c1.185,15.544,7.288,30.43,13.562,44.59c-0.6-5.745-0.071-10.949,0.914-16.349c1.963,11.822,4.454,23.576,10.193,34.216
+		C66.806,402.452,84.473,435.357,102.912,424.525z"/>
+	<path fill="#F7921E" d="M416.962,388.089c-11.048-17.689-36.528-8.124-52.734-1.227c1.332-2.711,2.888-5.324,4.152-7.676
+		c-18.6,13.718-45.063,13.131-64.26,27.095c-3.59,2.613-7.466,5.266-10.337,9.022c1.469-4.152,3.925-8.508,6.759-11.087
+		c-11.025,4.731-21.473,11.861-30.361,20.374c1.977-5.599,7.028-11.029,10.896-14.466l-0.092-0.103
+		c0.492-0.353-8.057,4.357-13.335,6.162c-20.321,6.94-38.475-0.96-59.413,18.35c1.647-6.023,8.781-11.067,13.754-14.616
+		c-12.048-3.086-32.82,13.518-39.053,22.555l-0.365,0.798c4.778,1.229,9.602,2.273,14.468,3.067
+		c10.001,1.61,20.123,2.463,30.257,2.518c10.132,0.098,20.276-0.468,30.342-1.703c10.073-1.158,20.075-2.971,29.934-5.354
+		c4.935-1.178,9.833-2.508,14.68-4.006c2.424-0.748,4.834-1.541,7.23-2.369c2.401-0.815,4.785-1.681,7.157-2.586
+		c4.73-1.798,9.389-3.879,14.078-5.901c4.679-2.037,9.324-4.151,13.933-6.343c9.235-4.354,18.299-9.073,27.117-14.277
+		c-8.291,6.021-17.134,11.281-26.145,16.191c-4.519,2.436-9.095,4.765-13.698,7.032c-2.297,1.141-4.623,2.232-6.945,3.317
+		c-2.325,1.092-4.689,2.146-7.064,3.15c-2.379,1.001-4.775,1.964-7.19,2.873c-2.416,0.906-4.854,1.752-7.301,2.566
+		c-4.902,1.623-9.854,3.078-14.851,4.375c-10.002,2.549-20.171,4.426-30.419,5.677c-10.258,1.172-20.594,1.736-30.927,1.489
+		c-10.325-0.293-20.656-1.256-30.794-3.301c-5.068-1.018-10.101-2.227-15.036-3.768c-4.936-1.535-9.791-3.32-14.507-5.416
+		c-6.103-2.729-11.989-5.962-17.474-9.742l-0.008,0.049l-12.024-2.11c3.365,3.932,15.808,10.405,20.4,12.624
+		c6.635,3.215,14.24,6.793,21.864,9.367l-0.081,0.247c11.524,16.2,26.986,31.191,46.977,35.972l0.076-0.311
+		c-4.252-3.056-7.439-9.154-8.552-14.787c9.192,6.588,16.849,11.899,28.948,11.415c-5.472-1.599-9.757-6.131-10.852-11.499
+		c24.611,13.205,54.932,8.717,79.486-2.162c6.28-2.784,12.222-5.949,18.19-9.318c-4.036-0.045-8.131-0.772-12.178-1.922
+		c15.506-1.61,30.22-8.119,44.202-14.777c-5.726,0.758-10.942,0.371-16.366-0.465c11.765-2.285,23.445-5.098,33.925-11.126
+		C395.887,424.786,428.295,406.225,416.962,388.089z"/>
+</g>
+</svg>
diff --git a/docs/source/_static/favicon.ico b/docs/source/_static/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..51386f615336a85a7fcf53a628cebe74fcc66d24
GIT binary patch
literal 4286
zcmcJSOGs2v7=Vvj8Me?0M5G*vh|nI3AQFmN3GI>y0$UZd5UNE+6i72jh|nT(kwmSE
zkg^sQL@gre4P~~-Fw&e}rkPJ_MjbtU|9H-D?>J+la~t{Q|Ih3H&OLWtDwV-saj}wT
z)s&}HzEWyE(4}^P^#89%(S^|eDm|;NbrA>Q9vp=?FaUR9qbwrMTI*E@wL_riK=!uO
z>wQr3G#rM9AP!3hc_Y-o7qEM4TgWxn_-9u6YgGZrS!Tg@SY)p0Ao(+}9%me)|1CT)
z;}PO>vu>vF9M9r|BG5vzsnlEnnUD`_paNdOB*=cIpbv&kTlz~OS;<&G-Vy63u8a*N
zNt`vwm%}NT0Oz?#{y9mBSU0|Mhx>PIAjJenY$o|Skk`vC=!Si<!2}83WpE$DFb;zW
zrls74FX7w+UDHbv4dB}ga^KrbY$1C7z+WF<6i*I30lD|@K=!dEeqOq5+zM92*THqf
zINMDeji2LH8~<Wxa@NE7-gqyYc-}egMQ*M=n>YdYpuyHP&S~ORh`?(9Sv%@o#90Lq
zs0R(Jq`L8cAby9icSd(5eEW>oPn2`mB{OgizzdMq-8c6t?^^htf?WS47=yL=3PIj;
zFG2jB-WlDM@X48vLKjTRD83T73$H-@*W9bpZ&l8`?+S4C!Y`10MEzzDa{XT+2(9TG
zXIH=%Fy5OcMqg+6q7UQ0GJ9ouJ-FmEC(}6Px*JS>ooL-Q2GX-7UX5qJasDtd;ddKn
zup@DW^m=jj8*j6T#qkv#_n|y~Y@uyja`vUhIcQ?i-(_|W)n%Jp%Hwfu*Wf=IIPGW7
zIC(^-S9VR!xe9+Ke1#!+0q5)ja+{_UalSRzEw8=XsVu@#2s(~Q+CkWDYn&+CY}2F>
zr+nUsyI&?%eoXqa(p3Y`A&375`5#C79eEY3b1kAlpQ{V+29WO?`R;R#C2QCk#8UVP
zau$Pd2f9t$o{yZ1?5`PGq$V-L#3JiR)otfHBlY%x_4Sg!hKtY$?Jx=xAbYEWV^9IP
zC%2Y3OU*l{Mr;jvE!ch7_?<qv9~~g)@YpV>-WL6L&^A4Z)L#pJcn+P=1braaenTWg
zPh9gUf;0MCX1;DMk8rNm!&zEC%Ft7J>dZ)3`G$3mFQ_BFR;@!q0BW@!gCO+O8M0|Z
oEA7@dS_g)-t`$OB)2(yEJ0V;9B1-$FRgTtv#Y%>Taq3U{FT>vl$N&HU

literal 0
HcmV?d00001

diff --git a/docs/source/authors.rst b/docs/source/authors.rst
new file mode 100644
index 0000000..7739272
--- /dev/null
+++ b/docs/source/authors.rst
@@ -0,0 +1 @@
+.. include:: ../../AUTHORS.rst
diff --git a/docs/source/changes.rst b/docs/source/changes.rst
new file mode 100644
index 0000000..d76c92b
--- /dev/null
+++ b/docs/source/changes.rst
@@ -0,0 +1 @@
+.. include:: ../../CHANGES.rst
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100755
index 0000000..529c51e
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+#
+# shearwater documentation build configuration file, created by
+# sphinx-quickstart on Fri Jun  9 13:47:02 2017.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another
+# directory, add these directories to sys.path here. If the directory is
+# relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#
+import os
+import sys
+
+# Add shearwater to sys.path to avoid having to full
+# install shearwater for autodoc.
+# Full install of shearwater will burst memory limit on ReadTheDocs.
+sys.path.insert(0, os.path.abspath("../../"))
+
+
+# -- General configuration ---------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+    "sphinx.ext.autodoc",
+    "sphinx.ext.viewcode",
+    "sphinx.ext.mathjax",
+    "sphinx.ext.napoleon",
+    "sphinx.ext.todo",
+    "pywps.ext_autodoc",
+    "sphinx.ext.autosectionlabel",
+    "sphinx.ext.imgconverter",
+    "nbsphinx",
+    "IPython.sphinxext.ipython_console_highlighting",
+]
+
+# To avoid having to install these and burst memory limit on ReadTheDocs.
+# List of all tested working mock imports from all birds so new birds can
+# inherit without having to test which work which do not.
+autodoc_mock_imports = ["numpy", "xarray", "fiona", "rasterio", "shapely",
+                        "osgeo", "geopandas", "pandas", "statsmodels",
+                        "affine", "rasterstats", "spotpy", "matplotlib",
+                        "scipy", "unidecode", "gdal", "sentry_sdk", "dask",
+                        "numba", "parse", "siphon", "sklearn", "cftime",
+                        "netCDF4", "bottleneck", "ocgis", "geotiff", "geos",
+                        "hdf4", "hdf5", "zlib", "pyproj", "proj", "cartopy",
+                        "scikit-learn", "cairo"]
+
+# Monkeypatch constant because the following are mock imports.
+# Only works if numpy is actually installed and at the same time being mocked.
+#import numpy
+#numpy.pi = 3.1416
+
+# We are using mock imports in readthedocs, so probably safer to not run the notebooks
+nbsphinx_execute = 'never'
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ["_templates"]
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = ".rst"
+
+# The master toctree document.
+master_doc = "index"
+
+# General information about the project.
+project = "ShearWater"
+copyright = "2023, Carsten Ehbrecht"
+author = "Carsten Ehbrecht"
+
+# The version info for the project you're documenting, acts as replacement
+# for |version| and |release|, also used in various other places throughout
+# the built documents.
+#
+# The short X.Y version.
+version = shearwater.__version__
+# The full version, including alpha/beta/rc tags.
+release = shearwater.__version__
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "**.ipynb_checkpoints"]
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = "sphinx"
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+# Suppress "WARNING: unknown mimetype for ..." when building EPUB.
+suppress_warnings = ['epub.unknown_project_files']
+
+# Avoid "configuration.rst:4:duplicate label configuration, other instance in configuration.rst"
+autosectionlabel_prefix_document = True
+
+
+# -- Options for HTML output -------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = "alabaster"
+
+# Theme options are theme-specific and customize the look and feel of a
+# theme further.  For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = "_static/birdhouse_logo.svg"
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = "_static/favicon.ico"
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ["_static"]
+
+
+# -- Options for HTMLHelp output ---------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = "shearwaterdoc"
+
+
+# -- Options for LaTeX output ------------------------------------------
+
+latex_elements = {
+    # The paper size ('letterpaper' or 'a4paper').
+    #
+    # 'papersize': 'letterpaper',
+    # The font size ('10pt', '11pt' or '12pt').
+    #
+    # 'pointsize': '10pt',
+    # Additional stuff for the LaTeX preamble.
+    #
+    # 'preamble': '',
+    # Latex figure (float) alignment
+    #
+    # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass
+# [howto, manual, or own class]).
+latex_documents = [
+    (
+        master_doc,
+        "shearwater.tex",
+        "ShearWater Documentation",
+        "Carsten Ehbrecht",
+        "manual",
+    ),
+]
+
+
+# -- Options for manual page output ------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (
+        master_doc,
+        "shearwater",
+        "ShearWater Documentation",
+        [author],
+        1,
+    )
+]
+
+
+# -- Options for Texinfo output ----------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (
+        master_doc,
+        "shearwater",
+        "ShearWater Documentation",
+        author,
+        "shearwater",
+        "A WPS for forecasting ctropical-cyclone activities.",
+        "Miscellaneous",
+    ),
+]
diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst
new file mode 100644
index 0000000..ce11079
--- /dev/null
+++ b/docs/source/configuration.rst
@@ -0,0 +1,49 @@
+.. _configuration:
+
+Configuration
+=============
+
+Command-line options
+--------------------
+
+You can overwrite the default `PyWPS`_ configuration by using command-line options.
+See the ShearWater help which options are available::
+
+    $ shearwater start --help
+    --hostname HOSTNAME        hostname in PyWPS configuration.
+    --port PORT                port in PyWPS configuration.
+
+Start service with different hostname and port::
+
+    $ shearwater start --hostname localhost --port 5001
+
+Use a custom configuration file
+-------------------------------
+
+You can overwrite the default `PyWPS`_ configuration by providing your own
+PyWPS configuration file (just modifiy the options you want to change).
+Use one of the existing ``sample-*.cfg`` files as example and copy them to ``etc/custom.cfg``.
+
+For example change the hostname (*demo.org*) and logging level:
+
+.. code-block:: console
+
+   $ cd shearwater
+   $ vim etc/custom.cfg
+   $ cat etc/custom.cfg
+   [server]
+   url = http://demo.org:5000/wps
+   outputurl = http://demo.org:5000/outputs
+
+   [logging]
+   level = DEBUG
+
+Start the service with your custom configuration:
+
+.. code-block:: console
+
+   # start the service with this configuration
+   $ shearwater start -c etc/custom.cfg
+
+
+.. _PyWPS: http://pywps.org/
diff --git a/docs/source/dev_guide.rst b/docs/source/dev_guide.rst
new file mode 100644
index 0000000..a80f1d3
--- /dev/null
+++ b/docs/source/dev_guide.rst
@@ -0,0 +1,107 @@
+.. _devguide:
+
+Developer Guide
+===============
+
+.. contents::
+    :local:
+    :depth: 1
+
+.. WARNING:: To create new processes look at examples in Emu_.
+
+Building the docs
+-----------------
+
+First install dependencies for the documentation:
+
+.. code-block:: console
+
+  $ make develop
+
+Run the Sphinx docs generator:
+
+.. code-block:: console
+
+  $ make docs
+
+.. _testing:
+
+Running tests
+-------------
+
+Run tests using pytest_.
+
+First activate the ``shearwater`` Conda environment and install ``pytest``.
+
+.. code-block:: console
+
+   $ source activate shearwater
+   $ pip install -r requirements_dev.txt  # if not already installed
+   OR
+   $ make develop
+
+Run quick tests (skip slow and online):
+
+.. code-block:: console
+
+    $ pytest -m 'not slow and not online'"
+
+Run all tests:
+
+.. code-block:: console
+
+    $ pytest
+
+Check pep8:
+
+.. code-block:: console
+
+    $ flake8
+
+Run tests the lazy way
+----------------------
+
+Do the same as above using the ``Makefile``.
+
+.. code-block:: console
+
+    $ make test
+    $ make test-all
+    $ make lint
+
+Prepare a release
+-----------------
+
+Update the Conda specification file to build identical environments_ on a specific OS.
+
+.. note:: You should run this on your target OS, in our case Linux.
+
+.. code-block:: console
+
+  $ conda env create -f environment.yml
+  $ source activate shearwater
+  $ make clean
+  $ make install
+  $ conda list -n shearwater --explicit > spec-file.txt
+
+.. _environments: https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#building-identical-conda-environments
+
+
+Bump a new version
+------------------
+
+Make a new version of ShearWater in the following steps:
+
+* Make sure everything is commit to GitHub.
+* Update ``CHANGES.rst`` with the next version.
+* Dry Run: ``bumpversion --dry-run --verbose --new-version 0.8.1 patch``
+* Do it: ``bumpversion --new-version 0.8.1 patch``
+* ... or: ``bumpversion --new-version 0.9.0 minor``
+* Push it: ``git push``
+* Push tag: ``git push --tags``
+
+See the bumpversion_ documentation for details.
+
+.. _bumpversion: https://pypi.org/project/bumpversion/
+.. _pytest: https://docs.pytest.org/en/latest/
+.. _Emu: https://github.com/bird-house/emu
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 0000000..318de0c
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,19 @@
+.. include:: ../../README.rst
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents:
+
+   installation
+   configuration
+   notebooks/index
+   dev_guide
+   processes
+   authors
+   changes
+
+Indices and tables
+==================
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/docs/source/installation.rst b/docs/source/installation.rst
new file mode 100644
index 0000000..82f2548
--- /dev/null
+++ b/docs/source/installation.rst
@@ -0,0 +1,113 @@
+.. _installation:
+
+Installation
+============
+
+.. contents::
+    :local:
+    :depth: 1
+
+Install from Conda
+------------------
+
+.. warning::
+
+   TODO: Prepare Conda package.
+
+Install from GitHub
+-------------------
+
+Check out code from the ShearWater GitHub repo and start the installation:
+
+.. code-block:: console
+
+   $ git clone https://github.com/cehbrecht/shearwater.git
+   $ cd shearwater
+
+Create Conda environment named `shearwater`:
+
+.. code-block:: console
+
+   $ conda env create -f environment.yml
+   $ source activate shearwater
+
+Install ShearWater app:
+
+.. code-block:: console
+
+  $ pip install -e .
+  OR
+  make install
+
+For development you can use this command:
+
+.. code-block:: console
+
+  $ pip install -e .[dev]
+  OR
+  $ make develop
+
+Start ShearWater PyWPS service
+------------------------------
+
+After successful installation you can start the service using the ``shearwater`` command-line.
+
+.. code-block:: console
+
+   $ shearwater --help # show help
+   $ shearwater start  # start service with default configuration
+
+   OR
+
+   $ shearwater start --daemon # start service as daemon
+   loading configuration
+   forked process id: 42
+
+The deployed WPS service is by default available on:
+
+http://localhost:5000/wps?service=WPS&version=1.0.0&request=GetCapabilities.
+
+.. NOTE:: Remember the process ID (PID) so you can stop the service with ``kill PID``.
+
+You can find which process uses a given port using the following command (here for port 5000):
+
+.. code-block:: console
+
+   $ netstat -nlp | grep :5000
+
+
+Check the log files for errors:
+
+.. code-block:: console
+
+   $ tail -f  pywps.log
+
+... or do it the lazy way
++++++++++++++++++++++++++
+
+You can also use the ``Makefile`` to start and stop the service:
+
+.. code-block:: console
+
+  $ make start
+  $ make status
+  $ tail -f pywps.log
+  $ make stop
+
+
+Run ShearWater as Docker container
+----------------------------------
+
+You can also run ShearWater as a Docker container.
+
+.. warning::
+
+  TODO: Describe Docker container support.
+
+Use Ansible to deploy ShearWater on your System
+-----------------------------------------------
+
+Use the `Ansible playbook`_ for PyWPS to deploy ShearWater on your system.
+
+
+.. _Ansible playbook: http://ansible-wps-playbook.readthedocs.io/en/latest/index.html
diff --git a/docs/source/notebooks/example.ipynb b/docs/source/notebooks/example.ipynb
new file mode 100644
index 0000000..56e8305
--- /dev/null
+++ b/docs/source/notebooks/example.ipynb
@@ -0,0 +1,48 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Usage Example"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import shearwater"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/source/notebooks/index.rst b/docs/source/notebooks/index.rst
new file mode 100644
index 0000000..cdbc518
--- /dev/null
+++ b/docs/source/notebooks/index.rst
@@ -0,0 +1,8 @@
+========
+Examples
+========
+
+.. toctree::
+   :maxdepth: 1
+
+   example
diff --git a/docs/source/processes.rst b/docs/source/processes.rst
new file mode 100644
index 0000000..f0b1600
--- /dev/null
+++ b/docs/source/processes.rst
@@ -0,0 +1,15 @@
+.. _processes:
+
+Processes
+=========
+
+.. contents::
+    :local:
+    :depth: 1
+
+Say Hello
+---------
+
+.. autoprocess:: shearwater.processes.wps_say_hello.SayHello
+   :docstring:
+   :skiplines: 1
diff --git a/environment-docs.yml b/environment-docs.yml
new file mode 100644
index 0000000..a30796f
--- /dev/null
+++ b/environment-docs.yml
@@ -0,0 +1,10 @@
+# conda env create -f environment-docs.yml
+name: shearwater-docs
+channels:
+- conda-forge
+- defaults
+dependencies:
+- pywps>=4.4
+- sphinx
+- nbsphinx
+- ipython
diff --git a/environment.yml b/environment.yml
new file mode 100644
index 0000000..dd8d389
--- /dev/null
+++ b/environment.yml
@@ -0,0 +1,13 @@
+name: shearwater
+channels:
+- conda-forge
+- defaults
+dependencies:
+- pip
+- python>=3.7,<3.10
+- pywps>=4.5.1,<4.6
+- jinja2
+- click
+- psutil
+# tests
+- pytest
diff --git a/etc/debug.cfg b/etc/debug.cfg
new file mode 100644
index 0000000..c00a2b7
--- /dev/null
+++ b/etc/debug.cfg
@@ -0,0 +1,2 @@
+[logging]
+level = DEBUG
diff --git a/etc/demo.cfg b/etc/demo.cfg
new file mode 100644
index 0000000..52145a3
--- /dev/null
+++ b/etc/demo.cfg
@@ -0,0 +1,2 @@
+[logging]
+level = WARN
diff --git a/etc/sample-custom.cfg b/etc/sample-custom.cfg
new file mode 100644
index 0000000..7b80725
--- /dev/null
+++ b/etc/sample-custom.cfg
@@ -0,0 +1,6 @@
+[server]
+url = http://demo.org:5000/wps
+outputurl = http://demo.org:5000/outputs
+
+[logging]
+level = DEBUG
diff --git a/etc/sample-postgres.cfg b/etc/sample-postgres.cfg
new file mode 100644
index 0000000..a16b904
--- /dev/null
+++ b/etc/sample-postgres.cfg
@@ -0,0 +1,3 @@
+[logging]
+level = INFO
+database = postgresql+psycopg2://postgres:postgres@localhost:5432/postgres
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..01cdf08
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,4 @@
+click
+jinja2
+psutil
+pywps>=4.5.1,<4.6
diff --git a/requirements_dev.txt b/requirements_dev.txt
new file mode 100644
index 0000000..878bba6
--- /dev/null
+++ b/requirements_dev.txt
@@ -0,0 +1,16 @@
+pytest>=6.0
+pytest-runner
+pytest-cov
+flake8
+tox
+pytest-flake8
+ipython
+pytest-notebook
+nbsphinx
+nbval>=0.9.6
+nbconvert
+sphinx>=1.8.5
+bump2version
+Click
+cruft
+# Changing dependencies above this comment will create merge conflicts when updating the cookiecutter template with cruft. Add extra requirements below this line.
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..ada64ab
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,50 @@
+[bumpversion]
+current_version = 0.1.0
+commit = True
+tag = True
+
+[metadata]
+description-file = README.rst
+
+[bumpversion:file:shearwater/__version__.py]
+search = __version__ = '{current_version}'
+replace = __version__ = '{new_version}'
+
+[bumpversion:file:docs/source/conf.py]
+parse = version|release = {current_version}
+replace = {new_version}
+
+[bumpversion:file:Dockerfile]
+search = Version="{current_version}"
+replace = Version="{new_version}"
+
+[bumpversion:file:.cruft.json]
+search = "version": "{current_version}",
+replace = "version": "{new_version}",
+
+[bdist_wheel]
+universal = 1
+
+[flake8]
+max-line-length = 120
+exclude =
+	.git,
+	__pycache__,
+	docs/source/conf.py,
+	build,
+	dist,
+	src,
+
+[aliases]
+# Define setup.py command aliases here
+test = pytest
+
+[tool:pytest]
+addopts =
+	--strict-markers
+	--tb=native
+	tests/
+python_files = test_*.py
+markers =
+	online: mark test to need internet connection
+	slow: mark test to be slow
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..33236fe
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+"""The setup script."""
+
+import os
+
+from setuptools import setup, find_packages
+
+here = os.path.abspath(os.path.dirname(__file__))
+README = open(os.path.join(here, 'README.rst')).read()
+CHANGES = open(os.path.join(here, 'CHANGES.rst')).read()
+REQUIRES_PYTHON = ">=3.6.0"
+
+about = {}
+with open(os.path.join(here, 'shearwater', '__version__.py'), 'r') as f:
+    exec(f.read(), about)
+
+setup_requirements = ['pytest-runner', ]
+
+test_requirements = ['pytest>=3', ]
+
+requirements = [line.strip() for line in open('requirements.txt')]
+
+dev_reqs = [line.strip() for line in open('requirements_dev.txt')]
+
+classifiers = [
+    'Development Status :: 3 - Alpha',
+    'Intended Audience :: Developers',
+    'Intended Audience :: Science/Research',
+    'Operating System :: MacOS :: MacOS X',
+    'Operating System :: POSIX',
+    'Programming Language :: Python',
+    'Natural Language :: English',
+    'Programming Language :: Python :: 3',
+    'Programming Language :: Python :: 3.5',
+    'Programming Language :: Python :: 3.6',
+    'Programming Language :: Python :: 3.7',
+    'Topic :: Scientific/Engineering :: Atmospheric Science',
+    'License :: OSI Approved :: Apache Software License',
+]
+
+setup(name='shearwater',
+      version=about['__version__'],
+      description="A WPS for forecasting ctropical-cyclone activities.",
+      long_description=README + '\n\n' + CHANGES,
+      long_description_content_type="text/x-rst",
+      author=about['__author__'],
+      author_email=about['__email__'],
+      url='https://github.com/cehbrecht/shearwater',
+      python_requires=REQUIRES_PYTHON,
+      classifiers=classifiers,
+      license="Apache Software License 2.0",
+      keywords='wps pywps birdhouse shearwater',
+      packages=find_packages(),
+      include_package_data=True,
+      install_requires=requirements,
+      setup_requires=setup_requirements,
+      test_suite = 'tests',
+      tests_require = test_requirements,
+      extras_require={
+          "dev": dev_reqs,  # pip install ".[dev]"
+      },
+      entry_points={
+          'console_scripts': [
+              'shearwater=shearwater.cli:cli',
+          ]},)
diff --git a/shearwater/__init__.py b/shearwater/__init__.py
new file mode 100644
index 0000000..8e0d2ce
--- /dev/null
+++ b/shearwater/__init__.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+
+"""Top-level package for ShearWater."""
+
+from .__version__ import __author__, __email__, __version__  # noqa: F401
+
+from .wsgi import application  # noqa: F401
diff --git a/shearwater/__version__.py b/shearwater/__version__.py
new file mode 100644
index 0000000..e4a49d3
--- /dev/null
+++ b/shearwater/__version__.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+
+# This information is located in its own file so that it can be loaded
+# without importing the main package when its dependencies are not installed.
+# See: https://packaging.python.org/guides/single-sourcing-package-version
+
+__author__ = "Carsten Ehbrecht"
+__email__ = "ehbrecht@dkrz.de"
+__version__ = "0.1.0"
diff --git a/shearwater/cli.py b/shearwater/cli.py
new file mode 100644
index 0000000..bd0aa66
--- /dev/null
+++ b/shearwater/cli.py
@@ -0,0 +1,184 @@
+###########################################################
+# Demo WPS service for testing and debugging.
+#
+# See the werkzeug documentation on how to use the debugger:
+# http://werkzeug.pocoo.org/docs/0.12/debug/
+###########################################################
+
+import os
+import psutil
+import click
+from jinja2 import Environment, PackageLoader
+from pywps import configuration
+
+from . import wsgi
+from urllib.parse import urlparse
+
+PID_FILE = os.path.abspath(os.path.join(os.path.curdir, "pywps.pid"))
+
+CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
+
+template_env = Environment(
+    loader=PackageLoader('shearwater', 'templates'),
+    autoescape=True
+)
+
+
+def write_user_config(**kwargs):
+    config_templ = template_env.get_template('pywps.cfg')
+    rendered_config = config_templ.render(**kwargs)
+    config_file = os.path.abspath(os.path.join(os.path.curdir, ".custom.cfg"))
+    with open(config_file, 'w') as fp:
+        fp.write(rendered_config)
+    return config_file
+
+
+def get_host():
+    url = configuration.get_config_value('server', 'url')
+    url = url or 'http://localhost:5000/wps'
+
+    click.echo("starting WPS service on {}".format(url))
+
+    parsed_url = urlparse(url)
+    if ':' in parsed_url.netloc:
+        host, port = parsed_url.netloc.split(':')
+        port = int(port)
+    else:
+        host = parsed_url.netloc
+        port = 80
+    return host, port
+
+
+def run_process_action(action=None):
+    """Run an action with psutil on current process
+    and return a status message."""
+    action = action or 'status'
+    try:
+        with open(PID_FILE, 'r') as fp:
+            pid = int(fp.read())
+            p = psutil.Process(pid)
+            if action == 'stop':
+                p.terminate()
+                msg = "pid={}, status=terminated".format(p.pid)
+            else:
+                from psutil import _pprint_secs
+                msg = "pid={}, status={}, created={}".format(
+                    p.pid, p.status(), _pprint_secs(p.create_time()))
+        if action == 'stop':
+            os.remove(PID_FILE)
+    except IOError:
+        msg = 'No PID file found. Service not running? Try "netstat -nlp | grep :5000".'
+    except psutil.NoSuchProcess as e:
+        msg = e.msg
+    click.echo(msg)
+
+
+def _run(application, bind_host=None, daemon=False):
+    from werkzeug.serving import run_simple
+    # call this *after* app is initialized ... needs pywps config.
+    host, port = get_host()
+    bind_host = bind_host or host
+    # need to serve the wps outputs
+    static_files = {
+        '/outputs': configuration.get_config_value('server', 'outputpath')
+    }
+    run_simple(
+        hostname=bind_host,
+        port=port,
+        application=application,
+        use_debugger=False,
+        use_reloader=False,
+        threaded=True,
+        # processes=2,
+        use_evalex=not daemon,
+        static_files=static_files)
+
+
+@click.group(context_settings=CONTEXT_SETTINGS)
+@click.version_option()
+def cli():
+    """Command line to start/stop a PyWPS service.
+
+    Do not use this service in a production environment.
+    It's intended to be running in a test environment only!
+    For more documentation, visit http://pywps.org/doc
+    """
+    pass
+
+
+@cli.command()
+def status():
+    """Show status of PyWPS service"""
+    run_process_action(action='status')
+
+
+@cli.command()
+def stop():
+    """Stop PyWPS service"""
+    run_process_action(action='stop')
+
+
+@cli.command()
+@click.option('--config', '-c', metavar='PATH', help='path to pywps configuration file.')
+@click.option('--bind-host', '-b', metavar='IP-ADDRESS', default='127.0.0.1',
+              help='IP address used to bind service.')
+@click.option('--daemon', '-d', is_flag=True, help='run in daemon mode.')
+@click.option('--hostname', metavar='HOSTNAME', default='localhost', help='hostname in PyWPS configuration.')
+@click.option('--port', metavar='PORT', default='5000', help='port in PyWPS configuration.')
+@click.option('--maxsingleinputsize', default='200mb', help='maxsingleinputsize in PyWPS configuration.')
+@click.option('--maxprocesses', metavar='INT', default='10', help='maxprocesses in PyWPS configuration.')
+@click.option('--parallelprocesses', metavar='INT', default='2', help='parallelprocesses in PyWPS configuration.')
+@click.option('--log-level', metavar='LEVEL', default='INFO', help='log level in PyWPS configuration.')
+@click.option('--log-file', metavar='PATH', default='pywps.log', help='log file in PyWPS configuration.')
+@click.option('--database', default='sqlite:///pywps-logs.sqlite', help='database in PyWPS configuration')
+@click.option('--outputurl', default='', help='base URL for file downloads')
+@click.option('--outputpath', default='', help='base directory where outputs are written')
+def start(config, bind_host, daemon, hostname, port,
+          maxsingleinputsize, maxprocesses, parallelprocesses,
+          log_level, log_file, database, outputurl, outputpath):
+    """Start PyWPS service.
+    This service is by default available at http://localhost:5000/wps
+    """
+    if os.path.exists(PID_FILE):
+        click.echo('PID file exists: "{}". Service still running?'.format(PID_FILE))
+        os._exit(0)
+    cfgfiles = []
+    cfgfiles.append(write_user_config(
+        wps_hostname=hostname,
+        wps_port=port,
+        wps_maxsingleinputsize=maxsingleinputsize,
+        wps_maxprocesses=maxprocesses,
+        wps_parallelprocesses=parallelprocesses,
+        wps_log_level=log_level,
+        wps_log_file=log_file,
+        wps_database=database,
+        wps_outputurl=outputurl,
+        wps_outputpath=outputpath
+    ))
+    if config:
+        cfgfiles.append(config)
+    app = wsgi.create_app(cfgfiles)
+    # let's start the service ...
+    # See:
+    # * https://github.com/geopython/pywps-flask/blob/master/demo.py
+    # * http://werkzeug.pocoo.org/docs/0.14/serving/
+    if daemon:
+        # daemon (fork) mode
+        pid = None
+        try:
+            pid = os.fork()
+            if pid:
+                click.echo('forked process id: {}'.format(pid))
+                with open(PID_FILE, 'w') as fp:
+                    fp.write("{}".format(pid))
+        except OSError as e:
+            raise Exception("%s [%d]" % (e.strerror, e.errno))
+
+        if pid == 0:
+            os.setsid()
+            _run(app, bind_host=bind_host, daemon=True)
+        else:
+            os._exit(0)
+    else:
+        # no daemon
+        _run(app, bind_host=bind_host)
diff --git a/shearwater/default.cfg b/shearwater/default.cfg
new file mode 100644
index 0000000..135c500
--- /dev/null
+++ b/shearwater/default.cfg
@@ -0,0 +1,20 @@
+[metadata:main]
+identification_title = ShearWater
+identification_abstract = A WPS for forecasting ctropical-cyclone activities.
+identification_keywords = PyWPS, WPS, OGC, processing, birdhouse, shearwater, demo
+identification_keywords_type = theme
+provider_name = ShearWater
+provider_url=https://shearwater.readthedocs.org/en/latest/
+
+[server]
+url = http://localhost:5000/wps
+outputurl = http://localhost:5000/outputs
+allowedinputpaths = /
+maxsingleinputsize = 200mb
+maxprocesses = 10
+parallelprocesses = 2
+
+[logging]
+level = INFO
+file = shearwater.log
+format = %(asctime)s] [%(levelname)s] line=%(lineno)s module=%(module)s %(message)s
diff --git a/shearwater/processes/__init__.py b/shearwater/processes/__init__.py
new file mode 100644
index 0000000..437441e
--- /dev/null
+++ b/shearwater/processes/__init__.py
@@ -0,0 +1,5 @@
+from .wps_say_hello import SayHello
+
+processes = [
+    SayHello(),
+]
diff --git a/shearwater/processes/wps_say_hello.py b/shearwater/processes/wps_say_hello.py
new file mode 100644
index 0000000..2d67782
--- /dev/null
+++ b/shearwater/processes/wps_say_hello.py
@@ -0,0 +1,47 @@
+from pywps import Process, LiteralInput, LiteralOutput, UOM
+from pywps.app.Common import Metadata
+
+import logging
+LOGGER = logging.getLogger("PYWPS")
+
+
+class SayHello(Process):
+    """A nice process saying 'hello'."""
+    def __init__(self):
+        inputs = [
+            LiteralInput('name', 'Your name',
+                         abstract='Please enter your name.',
+                         keywords=['name', 'firstname'],
+                         data_type='string')]
+        outputs = [
+            LiteralOutput('output', 'Output response',
+                          abstract='A friendly Hello from us.',
+                          keywords=['output', 'result', 'response'],
+                          data_type='string')]
+
+        super(SayHello, self).__init__(
+            self._handler,
+            identifier='hello',
+            title='Say Hello',
+            abstract='Just says a friendly Hello.'
+                     'Returns a literal string output with Hello plus the inputed name.',
+            keywords=['hello', 'demo'],
+            metadata=[
+                Metadata('PyWPS', 'https://pywps.org/'),
+                Metadata('Birdhouse', 'http://bird-house.github.io/'),
+                Metadata('PyWPS Demo', 'https://pywps-demo.readthedocs.io/en/latest/'),
+                Metadata('Emu: PyWPS examples', 'https://emu.readthedocs.io/en/latest/'),
+            ],
+            version='1.5',
+            inputs=inputs,
+            outputs=outputs,
+            store_supported=True,
+            status_supported=True
+        )
+
+    @staticmethod
+    def _handler(request, response):
+        LOGGER.info("say hello")
+        response.outputs['output'].data = 'Hello ' + request.inputs['name'][0].data
+        response.outputs['output'].uom = UOM('unity')
+        return response
diff --git a/shearwater/templates/pywps.cfg b/shearwater/templates/pywps.cfg
new file mode 100644
index 0000000..20951f8
--- /dev/null
+++ b/shearwater/templates/pywps.cfg
@@ -0,0 +1,27 @@
+[server]
+{% if wps_url %}
+url = {{ wps_url }}
+{% else %}
+url = http://{{ wps_hostname }}:{{ wps_port }}/wps
+{% endif %}
+{% if wps_outputurl %}
+outputurl = {{ wps_outputurl }}
+{% else %}
+outputurl = http://{{ wps_hostname }}:{{ wps_port }}/outputs
+{% endif %}
+allowedinputpaths = /
+maxsingleinputsize = {{ wps_maxsingleinputsize|default('200mb') }}
+maxprocesses = {{ wps_maxprocesses|default('10') }}
+parallelprocesses = {{ wps_parallelprocesses|default('2') }}
+{% if wps_outputpath %}
+outputpath= {{ wps_outputpath }}
+{% endif %}
+{% if wps_workdir %}
+workdir={{ wps_workdir }}
+{% endif %}
+
+[logging]
+level = {{ wps_log_level|default('INFO') }}
+file = {{ wps_log_file|default('pywps.log') }}
+database = {{ wps_database|default('sqlite:///pywps-logs.sqlite') }}
+format = %(asctime)s] [%(levelname)s] line=%(lineno)s module=%(module)s %(message)s
diff --git a/shearwater/wsgi.py b/shearwater/wsgi.py
new file mode 100644
index 0000000..b9812c3
--- /dev/null
+++ b/shearwater/wsgi.py
@@ -0,0 +1,17 @@
+import os
+from pywps.app.Service import Service
+
+from .processes import processes
+
+
+def create_app(cfgfiles=None):
+    config_files = [os.path.join(os.path.dirname(__file__), 'default.cfg')]
+    if cfgfiles:
+        config_files.extend(cfgfiles)
+    if 'PYWPS_CFG' in os.environ:
+        config_files.append(os.environ['PYWPS_CFG'])
+    service = Service(processes=processes, cfgfiles=config_files)
+    return service
+
+
+application = create_app()
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..d322c3d
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1 @@
+"""Unit test package for shearwater."""
diff --git a/tests/common.py b/tests/common.py
new file mode 100644
index 0000000..4aa035d
--- /dev/null
+++ b/tests/common.py
@@ -0,0 +1,43 @@
+from pywps import get_ElementMakerForVersion
+from pywps.app.basic import get_xpath_ns
+from pywps.tests import WpsClient, WpsTestResponse
+
+VERSION = "1.0.0"
+WPS, OWS = get_ElementMakerForVersion(VERSION)
+xpath_ns = get_xpath_ns(VERSION)
+
+
+class WpsTestClient(WpsClient):
+
+    def get(self, *args, **kwargs):
+        query = "?"
+        for key, value in kwargs.items():
+            query += "{0}={1}&".format(key, value)
+        return super(WpsTestClient, self).get(query)
+
+
+def client_for(service):
+    return WpsTestClient(service, WpsTestResponse)
+
+
+def get_output(doc):
+    """Copied from pywps/tests/test_execute.py.
+    TODO: make this helper method public in pywps."""
+    output = {}
+    for output_el in xpath_ns(doc, '/wps:ExecuteResponse'
+                                   '/wps:ProcessOutputs/wps:Output'):
+        [identifier_el] = xpath_ns(output_el, './ows:Identifier')
+
+        lit_el = xpath_ns(output_el, './wps:Data/wps:LiteralData')
+        if lit_el != []:
+            output[identifier_el.text] = lit_el[0].text
+
+        ref_el = xpath_ns(output_el, './wps:Reference')
+        if ref_el != []:
+            output[identifier_el.text] = ref_el[0].attrib['href']
+
+        data_el = xpath_ns(output_el, './wps:Data/wps:ComplexData')
+        if data_el != []:
+            output[identifier_el.text] = data_el[0].text
+
+    return output
diff --git a/tests/test_shearwater.py b/tests/test_shearwater.py
new file mode 100644
index 0000000..d28cd62
--- /dev/null
+++ b/tests/test_shearwater.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+"""Tests for `shearwater` package."""
+
+import pytest
+
+from click.testing import CliRunner
+
+import shearwater
+from shearwater import cli
+
+
+@pytest.fixture
+def response():
+    """Sample pytest fixture.
+
+    See more at: http://doc.pytest.org/en/latest/fixture.html
+    """
+    # import requests
+    # return requests.get('https://github.com/audreyr/cookiecutter-pypackage')
+
+
+def test_content(response):
+    """Sample pytest test function with the pytest fixture as an argument."""
+    # from bs4 import BeautifulSoup
+    # assert 'GitHub' in BeautifulSoup(response.content).title.string
diff --git a/tests/test_wps_caps.py b/tests/test_wps_caps.py
new file mode 100644
index 0000000..cedde26
--- /dev/null
+++ b/tests/test_wps_caps.py
@@ -0,0 +1,16 @@
+from pywps import Service
+
+from .common import client_for
+from shearwater.processes import processes
+
+
+def test_wps_caps():
+    client = client_for(Service(processes=processes))
+    resp = client.get(service='wps', request='getcapabilities', version='1.0.0')
+    names = resp.xpath_text('/wps:Capabilities'
+                            '/wps:ProcessOfferings'
+                            '/wps:Process'
+                            '/ows:Identifier')
+    assert sorted(names.split()) == [
+        'hello',
+    ]
diff --git a/tests/test_wps_hello.py b/tests/test_wps_hello.py
new file mode 100644
index 0000000..f699323
--- /dev/null
+++ b/tests/test_wps_hello.py
@@ -0,0 +1,15 @@
+from pywps import Service
+from pywps.tests import client_for, assert_response_success
+
+from .common import get_output
+from shearwater.processes.wps_say_hello import SayHello
+
+
+def test_wps_hello():
+    client = client_for(Service(processes=[SayHello()]))
+    datainputs = "name=LovelySugarBird"
+    resp = client.get(
+        "?service=WPS&request=Execute&version=1.0.0&identifier=hello&datainputs={}".format(
+            datainputs))
+    assert_response_success(resp)
+    assert get_output(resp.xml) == {'output': "Hello LovelySugarBird"}
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..2d1548e
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,29 @@
+[tox]
+envlist = py36, py37, py38, flake8
+requires = pip >= 20.0
+opts = -v
+
+[travis]
+python =
+    3.8: py38
+    3.7: py37
+    3.6: py36
+
+[testenv:flake8]
+basepython = python
+deps = flake8
+commands = flake8 shearwater tests
+
+[testenv]
+setenv =
+    PYTHONPATH = {toxinidir}
+install_command = python -m pip install --no-user {opts} {packages}
+download = True
+deps =
+    -r{toxinidir}/requirements_dev.txt
+; If you want to make tox run the tests with the same versions, create a
+; requirements.txt with the pinned versions and uncomment the following line:
+;     -r{toxinidir}/requirements.txt
+commands =
+    pytest --basetemp={envtmpdir}
+