diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..59eb89be2e3ed040f5303fa138d814bd90fcb4d7
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,22 @@
+name: Pages
+on:
+  push:
+    branches:
+    - master
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/setup-python@v2
+    - uses: actions/checkout@master
+      with:
+        fetch-depth: 0 # otherwise, you will failed to push refs to dest repo
+    - name: Build and Commit
+      uses: sphinx-notes/pages@v2
+      with:
+        requirements_path: ./docs/requirements.txt
+    - name: Push changes
+      uses: ad-m/github-push-action@master
+      with:
+        github_token: ${{ secrets.GITHUB_TOKEN }}
+        branch: gh-pages
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index fc6f6f49ab8833ad839524e8eb13e52b9e1e1043..6769e21d99a63338394e47bc4c7d0aba1e88d5a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,160 @@
-*~
-*__pycache__*
-.vscode
-docs/_build
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.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.*
+.cache
+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
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.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/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# 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/
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2486223eaf9b86fb7dda0fedbe6e927036de7242..98fda7dece3062da0befe82344f9fdb50455f043 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -80,7 +80,7 @@ run-functional-tests:
     # Thus, we need to override the command so that the server is run on port 8080.
     - docker run --name $TESTS_CONTAINER_NAME -d -e "UVICORN_PORT=8080" $TMP_IMAGE
     # Install everything required for the tests.
-    - docker exec -i $TESTS_CONTAINER_NAME /bin/bash -c "pip install -r dev-requirements.txt"
+    - docker exec -i $TESTS_CONTAINER_NAME /bin/bash -c "pip install -r requirements.txt"
     # Run the tests.
     - docker exec -i $TESTS_CONTAINER_NAME /bin/bash -c "python -m pytest"
     # Stop the tests container.
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a83fae56dc39d959ba8ba3a020cf158ab586b0bd
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,29 @@
+# .readthedocs.yaml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the version of Python and other tools you might need
+build:
+  os: ubuntu-22.04
+  tools:
+    python: "3.11"
+    # You can also specify other tool versions:
+    # nodejs: "19"
+    # rust: "1.64"
+    # golang: "1.19"
+
+# Build documentation in the docs/ directory with Sphinx
+sphinx:
+   configuration: docs/conf.py
+
+# If using Sphinx, optionally build your docs in additional formats such as PDF
+# formats:
+#    - pdf
+
+# Optionally declare the Python requirements required to build your docs
+python:
+   install:
+   - requirements: docs/requirements.txt
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..07b18dd254201ea8bb522d1fb986dc0a091ad5c2
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,19 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Python: MC Synthesis",
+            "type": "python",
+            "request": "launch",
+            "module": "mc_openapi",
+            "justMyCode": true,
+            "args": [
+                "-d", "tests/doml/openstack_template.domlx",
+                "--synth"
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..9b388533ae2b0b526768b898c911b1a364096bf9
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,7 @@
+{
+    "python.testing.pytestArgs": [
+        "tests"
+    ],
+    "python.testing.unittestEnabled": false,
+    "python.testing.pytestEnabled": true
+}
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index bfdfb934d99907633722c02ff2c6d5f31d906017..91058b6e1cc012d8f53da9c33d1ee4b9a885162e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -9,7 +9,7 @@ RUN pip install --upgrade pip \
     && pip install -r /opt/mc_openapi/requirements.txt
 WORKDIR /opt/mc_openapi
 
-ENV UVICORN_PORT=80 \
+ENV UVICORN_PORT=8080 \
     UVICORN_HOST=0.0.0.0
 
 CMD ["uvicorn", "--interface", "wsgi", "mc_openapi.app_config:app"]
diff --git a/README.md b/README.md
index 42e6b9b4ae2f082ecc6f5cf2a7a5137a6639f262..12333fd089a0b00d89c683d15378b51ff492c716 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,50 @@
+[![Documentation Status](https://readthedocs.org/projects/piacere-model-checker/badge/?version=latest)](https://piacere-model-checker.readthedocs.io/en/latest/?badge=latest)
+
 # PIACERE Model Checker
 
+**📖 You can read the [docs here](https://piacere-model-checker.readthedocs.io/en/latest/) for more details. 📖**
+
 The DOML Model Checker is a component of the [PIACERE](https://www.piacere-project.eu/) framework
 in charge of checking the correctness and consistency of
 [DOML](https://www.piacere-doml.deib.polimi.it/) models.
 
-This project is packaged with [Poetry](https://python-poetry.org/).
 
+ We provide a `requirements.txt` file for CI/CD purposes.
+
+ If you add a new package, regenerate it by running:
+ 
+ ```sh
+ pip freeze > requirements.txt
+ ```
 
-## Build and Run
+## Setup
 
-Build with
+Activate the Python Virtual Environment with:
 ```sh
-poetry install
+source .venv/bin/activate
 ```
-then run with
+Install the required packages with:
 ```sh
-poetry run python -m mc_openapi
+pip install -r requirements.txt
 ```
 
-Run tests with:
+## Run the model checker web server
 ```sh
-poetry run python -m pytest
+python -m mc_openapi
 ```
 
-
 ## Run with Uvicorn
 
 The project may be run with [Uvicorn](https://www.uvicorn.org/) as follows:
 ```sh
 uvicorn --port 8080 --host 0.0.0.0 --interface wsgi --workers 2 mc_openapi.app_config:app
 ```
+## Run tests
+
+Run tests with:
+```sh
+python -m pytest
+```
 
 
 ## Run with Docker
@@ -42,21 +57,18 @@ And then run it with
 ```sh
 docker run -d wp4/dmc
 ```
-The Uvicorn server will be running and listening on port 80 of the container.
-To use it locally, you may e.g. bind it with port 8080 of `localhost`
-by adding `-p 127.0.0.1:8080:80/tcp` to the `docker run` command.
+The Uvicorn server will be running and listening on port `8080` of the container.
+To use it locally, you may bind it with port `8080` of `localhost`
+by adding `-p 127.0.0.1:8080:8080/tcp` to the `docker run` command.
 
 
 ## Building the Documentation
 
 The documentation has been written in [Sphinx](https://www.sphinx-doc.org/)
 and covers both usage through the PIACERE IDE and the REST APIs.
+You can read the latest version at [readthedocs.io](https://piacere-model-checker.readthedocs.io/en/latest/)
 
-To build it, type
-```sh
-poetry shell
-```
-and then
+If you want to build the documentation manually, run:
 ```sh
 cd docs
 make html
diff --git a/dev-requirements.txt b/dev-requirements.txt
deleted file mode 100644
index e411cde070bc961d66cc31ed5ba228dbb2c6ea5a..0000000000000000000000000000000000000000
--- a/dev-requirements.txt
+++ /dev/null
@@ -1,95 +0,0 @@
-alabaster==0.7.12 ; python_version >= "3.9" and python_version < "4.0"
-anyio==3.6.1 ; python_version >= "3.9" and python_version < "4.0"
-appnope==0.1.3 ; python_version >= "3.9" and python_version < "4.0" and platform_system == "Darwin" or python_version >= "3.9" and python_version < "4.0" and sys_platform == "darwin"
-asttokens==2.0.8 ; python_version >= "3.9" and python_version < "4.0"
-attrs==22.1.0 ; python_version >= "3.9" and python_version < "4.0"
-babel==2.10.3 ; python_version >= "3.9" and python_version < "4.0"
-backcall==0.2.0 ; python_version >= "3.9" and python_version < "4.0"
-certifi==2022.9.24 ; python_version >= "3.9" and python_version < "4"
-cffi==1.15.1 ; python_version >= "3.9" and python_version < "4.0" and implementation_name == "pypy"
-charset-normalizer==2.1.1 ; python_version >= "3.9" and python_version < "4"
-click==8.1.3 ; python_version >= "3.9" and python_version < "4.0"
-clickclick==20.10.2 ; python_version >= "3.9" and python_version < "4.0"
-colorama==0.4.5 ; python_version >= "3.9" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.9" and python_version < "4.0" and platform_system == "Windows"
-colorful==0.5.4 ; python_version >= "3.9" and python_version < "4.0"
-connexion[swagger-ui]==2.14.1 ; python_version >= "3.9" and python_version < "4.0"
-debugpy==1.6.3 ; python_version >= "3.9" and python_version < "4.0"
-decorator==5.1.1 ; python_version >= "3.9" and python_version < "4.0"
-docutils==0.17.1 ; python_version >= "3.9" and python_version < "4.0"
-entrypoints==0.4 ; python_version >= "3.9" and python_version < "4.0"
-executing==1.1.0 ; python_version >= "3.9" and python_version < "4.0"
-flask==2.2.2 ; python_version >= "3.9" and python_version < "4.0"
-future-fstrings==1.2.0 ; python_version >= "3.9" and python_version < "4.0"
-h11==0.14.0 ; python_version >= "3.9" and python_version < "4.0"
-httptools==0.5.0 ; python_version >= "3.9" and python_version < "4.0"
-idna==3.4 ; python_version >= "3.9" and python_version < "4"
-imagesize==1.4.1 ; python_version >= "3.9" and python_version < "4.0"
-importlib-metadata==5.0.0 ; python_version >= "3.9" and python_version < "3.10"
-inflection==0.5.1 ; python_version >= "3.9" and python_version < "4.0"
-iniconfig==1.1.1 ; python_version >= "3.9" and python_version < "4.0"
-ipykernel==6.16.0 ; python_version >= "3.9" and python_version < "4.0"
-ipython==8.5.0 ; python_version >= "3.9" and python_version < "4.0"
-itsdangerous==2.1.2 ; python_version >= "3.9" and python_version < "4.0"
-jedi==0.18.1 ; python_version >= "3.9" and python_version < "4.0"
-jinja2==3.1.2 ; python_version >= "3.9" and python_version < "4.0"
-joblib==1.2.0 ; python_version >= "3.9" and python_version < "4.0"
-jsonschema==4.16.0 ; python_version >= "3.9" and python_version < "4.0"
-jupyter-client==7.3.5 ; python_version >= "3.9" and python_version < "4.0"
-jupyter-core==4.11.1 ; python_version >= "3.9" and python_version < "4.0"
-lxml==4.9.1 ; python_version >= "3.9" and python_version < "4.0"
-markupsafe==2.1.1 ; python_version >= "3.9" and python_version < "4.0"
-matplotlib-inline==0.1.6 ; python_version >= "3.9" and python_version < "4.0"
-nest-asyncio==1.5.6 ; python_version >= "3.9" and python_version < "4.0"
-networkx==2.8.7 ; python_version >= "3.9" and python_version < "4.0"
-ordered-set==4.1.0 ; python_version >= "3.9" and python_version < "4.0"
-packaging==21.3 ; python_version >= "3.9" and python_version < "4.0"
-parso==0.8.3 ; python_version >= "3.9" and python_version < "4.0"
-pexpect==4.8.0 ; python_version >= "3.9" and python_version < "4.0" and sys_platform != "win32"
-pickleshare==0.7.5 ; python_version >= "3.9" and python_version < "4.0"
-pluggy==1.0.0 ; python_version >= "3.9" and python_version < "4.0"
-prettyprinter==0.18.0 ; python_version >= "3.9" and python_version < "4.0"
-prompt-toolkit==3.0.31 ; python_version >= "3.9" and python_version < "4.0"
-psutil==5.9.2 ; python_version >= "3.9" and python_version < "4.0"
-ptyprocess==0.7.0 ; python_version >= "3.9" and python_version < "4.0" and sys_platform != "win32"
-pure-eval==0.2.2 ; python_version >= "3.9" and python_version < "4.0"
-py==1.11.0 ; python_version >= "3.9" and python_version < "4.0"
-pycparser==2.21 ; python_version >= "3.9" and python_version < "4.0" and implementation_name == "pypy"
-pyecore==0.12.2 ; python_version >= "3.9" and python_version < "4.0"
-pygments==2.13.0 ; python_version >= "3.9" and python_version < "4.0"
-pyparsing==3.0.9 ; python_version >= "3.9" and python_version < "4.0"
-pyrsistent==0.18.1 ; python_version >= "3.9" and python_version < "4.0"
-pytest==7.1.3 ; python_version >= "3.9" and python_version < "4.0"
-python-dateutil==2.8.2 ; python_version >= "3.9" and python_version < "4.0"
-python-dotenv==0.21.0 ; python_version >= "3.9" and python_version < "4.0"
-pytz==2022.4 ; python_version >= "3.9" and python_version < "4.0"
-pywin32==304 ; sys_platform == "win32" and platform_python_implementation != "PyPy" and python_version >= "3.9" and python_version < "4.0"
-pyyaml==6.0 ; python_version >= "3.9" and python_version < "4.0"
-pyzmq==24.0.1 ; python_version >= "3.9" and python_version < "4.0"
-requests==2.28.1 ; python_version >= "3.9" and python_version < "4"
-restrictedpython==5.0 ; python_version >= "3.9" and python_version < "4.0"
-setuptools==65.4.1 ; python_version >= "3.9" and python_version < "4.0"
-six==1.16.0 ; python_version >= "3.9" and python_version < "4.0"
-sniffio==1.3.0 ; python_version >= "3.9" and python_version < "4.0"
-snowballstemmer==2.2.0 ; python_version >= "3.9" and python_version < "4.0"
-sphinx-rtd-theme==1.0.0 ; python_version >= "3.9" and python_version < "4.0"
-sphinx==5.2.3 ; python_version >= "3.9" and python_version < "4.0"
-sphinxcontrib-applehelp==1.0.2 ; python_version >= "3.9" and python_version < "4.0"
-sphinxcontrib-devhelp==1.0.2 ; python_version >= "3.9" and python_version < "4.0"
-sphinxcontrib-htmlhelp==2.0.0 ; python_version >= "3.9" and python_version < "4.0"
-sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.9" and python_version < "4.0"
-sphinxcontrib-qthelp==1.0.3 ; python_version >= "3.9" and python_version < "4.0"
-sphinxcontrib-serializinghtml==1.1.5 ; python_version >= "3.9" and python_version < "4.0"
-stack-data==0.5.1 ; python_version >= "3.9" and python_version < "4.0"
-swagger-ui-bundle==0.0.9 ; python_version >= "3.9" and python_version < "4.0"
-tomli==2.0.1 ; python_version >= "3.9" and python_version < "4.0"
-tornado==6.2 ; python_version >= "3.9" and python_version < "4.0"
-traitlets==5.4.0 ; python_version >= "3.9" and python_version < "4.0"
-urllib3==1.26.12 ; python_version >= "3.9" and python_version < "4"
-uvicorn[standard]==0.18.3 ; python_version >= "3.9" and python_version < "4.0"
-uvloop==0.17.0 ; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" and python_version >= "3.9" and python_version < "4.0"
-watchfiles==0.17.0 ; python_version >= "3.9" and python_version < "4.0"
-wcwidth==0.2.5 ; python_version >= "3.9" and python_version < "4.0"
-websockets==10.3 ; python_version >= "3.9" and python_version < "4.0"
-werkzeug==2.2.2 ; python_version >= "3.9" and python_version < "4.0"
-z3-solver==4.11.2.0 ; python_version >= "3.9" and python_version < "4.0"
-zipp==3.8.1 ; python_version >= "3.9" and python_version < "3.10"
diff --git a/docker-compose.yaml b/docker-compose.yaml
index c2c1b74739367efc21a07f847a418bbf49f8d1f0..2bbf5c3aaebf132d4a7ccf5a80818e779532008c 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -3,8 +3,8 @@ services:
   dmc:
     build: .
     ports:
-      - "8080:80"
+      - "8080:8080"
     environment:
-      UVICORN_PORT: 80
+      UVICORN_PORT: 8080
       UVICORN_HOST: "0.0.0.0"
       UVICORN_WORKERS: 2
diff --git a/docs/PIACERE_logo.png b/docs/PIACERE_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..8225ccc44d7c081e988f3de5e93695d155e8a919
Binary files /dev/null and b/docs/PIACERE_logo.png differ
diff --git a/docs/conf.py b/docs/conf.py
index fadcaeb668b0220b440d553067858c47450ecdd1..2efa10453c1433dff2ec21e3105175944cf00f50 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -13,17 +13,17 @@
 # import os
 # import sys
 # sys.path.insert(0, os.path.abspath('.'))
-import sphinx_rtd_theme
+# import sphinx_rtd_theme
 
 
 # -- Project information -----------------------------------------------------
 
 project = 'DOML Model Checker'
-copyright = '2022, Michele Chiari and Michele De Pascalis'
-author = 'Michele Chiari and Michele De Pascalis'
+copyright = '2022, Michele Chiari, Michele De Pascalis, Andrea Franchini'
+author = 'Michele Chiari, Michele De Pascalis, Andrea Franchini'
 
 # The full version, including alpha/beta/rc tags
-release = '1.1.0'
+release = '2.0.0'
 
 
 # -- General configuration ---------------------------------------------------
@@ -32,7 +32,7 @@ release = '1.1.0'
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
 extensions = [
-    'sphinx_rtd_theme'
+    # 'sphinx_rtd_theme'
 ]
 
 # Add any paths that contain templates here, relative to this directory.
@@ -41,7 +41,7 @@ templates_path = []
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'requirements.txt']
 
 
 # -- Options for HTML output -------------------------------------------------
@@ -49,8 +49,9 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-html_theme = 'sphinx_rtd_theme'
-
+# html_theme = 'sphinx_rtd_theme'
+html_theme = 'furo'
+html_logo = "PIACERE_logo.png"
 # 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".
diff --git a/docs/dict_reference.rst b/docs/dict_reference.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f081c0ae71596cee72ea04bc90f9fb25211feeee
--- /dev/null
+++ b/docs/dict_reference.rst
@@ -0,0 +1,171 @@
+Reference for Attributes, Association and Classes keys
+======================================================
+
+Attributes
+----------
+
+commons_DOMLElement::name
+commons_DOMLElement::description
+commons_Property::key
+commons_IProperty::value
+commons_SProperty::value
+commons_FProperty::value
+commons_BProperty::value
+application_SoftwareComponent::isPersistent
+application_SoftwareComponent::licenseCost
+application_SoftwareComponent::configFile
+application_SaaS::licenseCost
+application_SoftwareInterface::endPoint
+infrastructure_ComputingNode::architecture
+infrastructure_ComputingNode::os
+infrastructure_ComputingNode::memory_mb
+infrastructure_ComputingNode::memory_kb
+infrastructure_ComputingNode::storage
+infrastructure_ComputingNode::cpu_count
+infrastructure_ComputingNode::cost
+infrastructure_VirtualMachine::sizeDescription
+infrastructure_Location::region
+infrastructure_Location::zone
+infrastructure_ComputingNodeGenerator::uri
+infrastructure_ComputingNodeGenerator::kind
+infrastructure_AutoScalingGroup::min
+infrastructure_AutoScalingGroup::max
+infrastructure_AutoScalingGroup::loadBalancer
+infrastructure_Storage::label
+infrastructure_Storage::size_gb
+infrastructure_Storage::cost
+infrastructure_FunctionAsAService::cost
+infrastructure_Network::protocol
+infrastructure_Network::address_lb
+infrastructure_Network::address_ub
+infrastructure_NetworkInterface::endPoint
+infrastructure_NetworkInterface::speed
+infrastructure_Rule::kind
+infrastructure_Rule::protocol
+infrastructure_Rule::fromPort
+infrastructure_Rule::toPort
+infrastructure_Rule::cidr
+infrastructure_KeyPair::user
+infrastructure_KeyPair::keyfile
+infrastructure_KeyPair::algorithm
+infrastructure_KeyPair::bits
+infrastructure_UserPass::username
+infrastructure_UserPass::password
+infrastructure_SwarmRole::kind
+concrete_ConcreteElement::configurationScript
+
+Associations
+------------
+
+commons_DOMLElement::annotations
+commons_Property::reference
+commons_Configuration::deployments
+commons_Deployment::component
+commons_Deployment::node
+application_ApplicationLayer::components
+application_SoftwareComponent::exposedInterfaces
+application_SoftwareComponent::consumedInterfaces
+application_SaaS::exposedInterfaces
+infrastructure_InfrastructureLayer::nodes
+infrastructure_InfrastructureLayer::generators
+infrastructure_InfrastructureLayer::storages
+infrastructure_InfrastructureLayer::faas
+infrastructure_InfrastructureLayer::credentials
+infrastructure_InfrastructureLayer::groups
+infrastructure_InfrastructureLayer::securityGroups
+infrastructure_InfrastructureLayer::networks
+infrastructure_ComputingNode::ifaces
+infrastructure_ComputingNode::location
+infrastructure_ComputingNode::credentials
+infrastructure_ComputingNode::group
+infrastructure_VirtualMachine::generatedFrom
+infrastructure_Container::generatedFrom
+infrastructure_Container::hosts
+infrastructure_VMImage::generatedVMs
+infrastructure_ContainerImage::generatedContainers
+infrastructure_AutoScalingGroup::machineDefinition
+infrastructure_AutoScalingGroup::deploymentNetwork
+infrastructure_AutoScalingGroup::securityGroup
+infrastructure_Storage::ifaces
+infrastructure_FunctionAsAService::ifaces
+infrastructure_Network::connectedIfaces
+infrastructure_Network::igws
+infrastructure_Network::subnets
+infrastructure_Subnet::connectedTo
+infrastructure_NetworkInterface::belongsTo
+infrastructure_NetworkInterface::associated
+infrastructure_ComputingGroup::groupedNodes
+infrastructure_SecurityGroup::rules
+infrastructure_SecurityGroup::ifaces
+infrastructure_SwarmRole::nodes
+infrastructure_Swarm::roles
+concrete_ConcreteInfrastructure::providers
+concrete_RuntimeProvider::vms
+concrete_RuntimeProvider::vmImages
+concrete_RuntimeProvider::containerImages
+concrete_RuntimeProvider::networks
+concrete_RuntimeProvider::storages
+concrete_RuntimeProvider::faas
+concrete_RuntimeProvider::group
+concrete_VirtualMachine::maps
+concrete_VMImage::maps
+concrete_ContainerImage::maps
+concrete_Network::maps
+concrete_Storage::maps
+concrete_FunctionAsAService::maps
+concrete_ComputingGroup::maps
+
+Classes
+-------
+
+commons_DOMLElement
+commons_Property
+commons_IProperty
+commons_SProperty
+commons_FProperty
+commons_BProperty
+commons_Configuration
+commons_Deployment
+application_ApplicationLayer
+application_ApplicationComponent
+application_SoftwareComponent
+application_SaaS
+application_SoftwareInterface
+application_DBMS
+application_SaaSDBMS
+infrastructure_InfrastructureLayer
+infrastructure_InfrastructureElement
+infrastructure_ComputingNode
+infrastructure_PhysicalComputingNode
+infrastructure_VirtualMachine
+infrastructure_Location
+infrastructure_Container
+infrastructure_ComputingNodeGenerator
+infrastructure_VMImage
+infrastructure_ContainerImage
+infrastructure_AutoScalingGroup
+infrastructure_Storage
+infrastructure_FunctionAsAService
+infrastructure_Network
+infrastructure_Subnet
+infrastructure_NetworkInterface
+infrastructure_InternetGateway
+infrastructure_ComputingGroup
+infrastructure_SecurityGroup
+infrastructure_Rule
+infrastructure_Credentials
+infrastructure_KeyPair
+infrastructure_UserPass
+infrastructure_SwarmRole
+infrastructure_Swarm
+infrastructure_ExtInfrastructureElement
+concrete_ConcreteInfrastructure
+concrete_ConcreteElement
+concrete_RuntimeProvider
+concrete_VirtualMachine
+concrete_VMImage
+concrete_ContainerImage
+concrete_Network
+concrete_Storage
+concrete_FunctionAsAService
+concrete_ComputingGroup
\ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
index ec8ef513ffa8ae204f1b6e2847034e325e90bd0b..dbb3f36d3a996bdf801893b338c2ae04707ab7cb 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -3,7 +3,7 @@
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
 
-DOML Model Checker's documentation
+DOML Model Checker Documentation
 ==================================
 
 The DOML Model Checker is a component of the `PIACERE`_ framework
@@ -15,7 +15,9 @@ in charge of checking the correctness and consistency of `DOML`_ models.
    :caption: Contents:
 
    installation
+   tests
    usage
+   writing-requirements
    requirements
    restapis
 
@@ -28,8 +30,8 @@ in charge of checking the correctness and consistency of `DOML`_ models.
    * :ref:`search`
 
 
-This project has received funding from the European Union's Horizon 2020
-research and innovation programme under grant agreement No. 101000162.
+*This project has received funding from the European Union's Horizon 2020
+research and innovation programme under grant agreement No. 101000162.*
 
 
 .. _PIACERE: https://www.piacere-project.eu/
diff --git a/docs/installation.rst b/docs/installation.rst
index 9f30192cd963cf9ffa789f61aacdfd4ff5c70a56..3f0bcb706003d52e91d709582c034fbeb1b482f5 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -1,35 +1,28 @@
 Installation
-============
+************
 
-The DOML Model Checker receives user inputs through its REST APIs.
-In this guide we illuestrate saveral ways of setting up the server for these APIs.
+The model checker can be run in two configurations, *REST API* and *CLI*.
 
+First, you'll need to install the dependencies to run this tool.
 
-Build and run locally for testing
----------------------------------
+Installing the dependencies
+===========================
 
-This project is packaged with `Poetry`_, which we assume you have already
-`installed <https://python-poetry.org/docs/#installation>`_ into your system.
-
-
-Build with::
+This project is packaged with `Poetry`_, so you should install it first.
 
+Once *Poetry* has been installed, install the dependencies with::
+  
   poetry install
 
-then run with::
+
+Run locally for testing
+-----------------------
+Run with::
 
   poetry run python -m mc_openapi
 
-this command serves the APIs through a `Flask`_ instance,
+This command serves the APIs through a `Flask`_ instance,
 which is suitable for testing, but not recommended for production.
-You may read the API specification generated by `Swagger-UI`_ by
-pointing your browser to http://127.0.0.1:8080/ui/.
-
-
-Then, run tests with::
-
-  poetry run python -m pytest
-
 
 Run locally with Uvicorn
 ------------------------
@@ -61,8 +54,13 @@ The Uvicorn server will be running and listening on port 80 of the container.
 To use it locally, you may e.g. bind it with port 8080 of ``localhost``
 by adding ``-p 127.0.0.1:8080:80/tcp`` to the ``docker run`` command.
 
+REST API Endpoints
+==================
+
+You may read the API specification generated by `Swagger-UI`_ at http://127.0.0.1:8080/ui/.
+
 Building the Documentation
---------------------------
+==========================
 
 The documentation has been written in `Sphinx`_.
 
diff --git a/docs/requirements.rst b/docs/requirements.rst
index 6ea7e25dba686b611fb61c5de902540fecc5210c..0fb3c49c2298a4b3347a18c92c280bfd25f5e1a4 100644
--- a/docs/requirements.rst
+++ b/docs/requirements.rst
@@ -1,5 +1,5 @@
-Checked Requirements
-====================
+Built-in Requirements
+=====================
 
 The DOML Model Checker verifies DOML models against a collection of requirements
 devised to highlight the most common mistakes made by users when specifying cloud deployments.
@@ -60,3 +60,18 @@ Concrete Infrastructure Elements have a maps Association
   All elements in the active concretization are mapped to some abstract infrastructure element.
 
 Makes sure each concrete infrastructure element is mapped to a node in the Abstract Infrastructure Layer.
+
+Network Interfaces belong to a Security Group
+---------------------------------------------
+
+  All network interfaces belong to a security group.
+
+Makes sure all network interfaces have been configured to belong to a security group.
+This way, the user will be reminded to configure adequate rules for each network.
+
+External Services are reached through HTTPS
+-------------------------------------------
+
+  All external SaaS can be reached only through a secure connection.
+
+Makes sure that an HTTPS rule is enforced for a Network Interface of a Software Component that interfaces with a SaaS.
\ No newline at end of file
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9e279e79d32427f119426d5f3ec50ce026c4daa9
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1 @@
+furo
\ No newline at end of file
diff --git a/docs/tests.rst b/docs/tests.rst
new file mode 100644
index 0000000000000000000000000000000000000000..fb6c26cf1df92aa2c6084ce220ea1858c46d7b30
--- /dev/null
+++ b/docs/tests.rst
@@ -0,0 +1,10 @@
+Testing
+=======
+
+To run the tests with *PyTest* you'll need to setup the server::
+  
+  poetry run python -m mc_openapi
+
+and then run separately::
+
+  poetry run python -m pytest
diff --git a/docs/usage.rst b/docs/usage.rst
index 0b9c29f39340dc9a2f19c0f639740bd4c4f8000e..0d0478bd24785447bd89fe271474f2acb7e8ff39 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -1,9 +1,9 @@
-Usage through the PIACERE IDE
-=============================
+Usage
+*****
 
 
-Invoking the DOML Model Checker from the PIACERE IDE
------------------------------------------------------
+Through the PIACERE IDE
+=======================
 
 The DOML Model Checker is usually invoked from the PIACERE IDE.
 It expects a DOML file in XMI format as its input,
@@ -48,3 +48,62 @@ and then choose *Piacere* -> *Model Checker Preferences*.
 
 Here you may enter the endpoint address and port, which is useful in case you want to
 run the DOML Model Checker locally, instead of using the official deployment.
+
+Through the Command Line Interface
+==================================
+
+Another way to use the model checker is through the CLI.
+It provides additional options that are not available in the IDE at
+the moment, such as support for a separate user requirement file
+and synthesis of DOMLX.
+
+You can run it with::
+
+  python -m mc_openapi [options]
+
+To display all the available flags, run::
+
+  python -m mc_openapi -h
+
+Options
+-------
+
+Please note that not all flags work with eachother. In most cases, some won't have
+any effect in certain CLI flags combinations.
+
+There are **3 Modes** in which the CLI can run:
+
+- REST API (**R**)
+- Model Checker (**C**)
+- Model Synthesis (**S**)
+
+======  =========================  =========  =================
+Flags                              Mode       Description
+---------------------------------  ---------  -----------------
+Short   Long         
+======  =========================  =========  =================
+``-h``  ``--help``                 C, S, R    Print the all the available flags with an explanation
+``-v``  ``--verbose``              C, S, R    Print a detailed human-readable output of everything going on. Helpful for debugging
+``-p``  ``--port``                 R          The port that will expose the REST API (default: 8080)
+``-d``  ``--doml``                 C, S       The DOMLX file to check with the model checker
+``-V``  ``--doml-version``         C, S       The DOML version in which the DOMLX file is written in
+``-r``  ``--requirements``         C, S       A text file containing the user-defined requirements written in :doc:`DOMLR <writing-requirements>`.
+``-S``  ``--skip-common-checks``   C          Skips :doc:`build-in requirements <requirements>` checks
+``-c``  ``--check-consistency``    C          Perform additional consistency checks (legacy)
+``-t``  ``--threads``              C, R       The number of threads used by the model checker (default: 2)
+``-s``  ``--synth``                S          Synthetize a new DOMLX file from requirements
+``-m``  ``--max-tries``            S          Max number of tries to solve a model during synthesis (default: 10)
+======  =========================  =========  =================
+
+*If you do not provide the ``--doml`` option or the ``--synth`` option it will start the web server hosting the REST API!*
+
+Examples
+--------
+
+To check a DOMLX file with user-provided custom requirements, you may run::
+
+  python -m mc_openapi -d ./path/to/myModel.domlx -r ./path/to/myRequirements.domlr -V V2_0
+
+To synthetize a new DOMLX file with 4 threads and a maximum of 15 tries, you may run::
+
+  python -m mc_openapi -d ./path/to/myModel.domlx --synth -m 15
\ No newline at end of file
diff --git a/docs/writing-requirements.rst b/docs/writing-requirements.rst
new file mode 100644
index 0000000000000000000000000000000000000000..b30ec9408365d27dd0f516257badfe6922cbecd0
--- /dev/null
+++ b/docs/writing-requirements.rst
@@ -0,0 +1,118 @@
+Writing Requirements
+********************
+
+A feature of the DOML Model Checker is a Domain Specific Language (DSL)
+called **DOMLR** (the R stands for requirements).
+
+It will be integrated in the DOML in a future release.
+For now, it can be provided to the Model Checker through the CLI.
+
+Getting Started
+===============
+
+First, create a new file with a ``.domlr`` extension.
+
+If you use VS Code, there's a `Syntax Highlight`_ extension for it.
+
+Every user requirement file is a list of requirement::
+
+    + "All Virtual Machines have a Interface and at least 4 cpu cores"
+    forall vm (
+        vm is class abstract.VirtualMachine
+        implies
+        exists iface (
+            vm has abstract.ComputingNode.ifaces iface
+            and
+            vm has abstract.ComputingNode.cpu_count >= 4 
+        )
+    )
+    error: "A vm does lacks an associated interface or has less than 4 CPUs"
+
+Rules in 1 minute
+-----------------
+
+The language is *case-sensitive* but it's not indentation-based, so you are free to write it as you prefer.
+
+1.  A requirement must **start** with a ``+`` or ``-`` character.
+
+    -   ``+`` means that the requirement is in **positive form**: the requirement is satisfied when its logic expression is satisfied.
+
+    -   ``-`` means that the requirement is in **negative form**: the requirement is satisfied when its logic expression **is not** satisfied.
+
+    The difference is that in **positive form** you would generally use a *for all* quantifier at the beginning,
+    which doesn't allow you to know which specific element didn't satisfy the requirement, while in **negative form**
+    you'll have some variables that are not quantified, meaning that it's usually possible to retrieve the names of the
+    elements associated to those variables that do not satisfy the requirement.
+
+2.  After the ``+`` or ``-`` there's the **name** of the requirement, which is a string between double quotes ``"..."``.
+    Single quotes ``'...'`` won't work.
+
+3.  Following the requirement name, there's the **logic expression** which is the core of the requirement.
+    It is written in `First Order Logic`_, so it will evaluate to either true or false. See the `Syntax`_ for details.
+
+4.  Last, following ``error:``, there is the **error message** that is printed when the requirement is not satisfied.
+    If you have a free variable, which means a variable that is not quantified, you can print its value by putting it in the
+    string between curly brackets like this: ``{myVar}``. You'll get a warning if the Model Checker can't assign a value to that variable.
+
+.. `Syntax`:
+
+Syntax
+======
+
+The syntax is the following:
+
+- Unary operators: ``not``
+    - Example: ``not <expression>``
+- Binary operators: ``or``, ``and``, ``implies``, ``iff`` (if and only if, AKA double implication)
+    - Example: ``<expression> and <expression>``
+- Quantifiers: ``forall``, ``exists``
+    - Example: ``forall x, y ( <expression> )``
+    - After the quantifier keywork (``forall``, ``exists``) you must specify a list of quantified variables
+        (separated by a comma ``,`` if there's more than one).
+    - Between the mandatory pair of parenthesis, you'll be able to use the quantified variables in a logic expression.
+- Parenthesis: ``(`` ... ``)``
+    - Useful when you have doubts about the precedence of operators, or want to increase legibility in certain situations.
+- Elements (variables):
+    - Begin with a lowercase letter.
+    - Example: ``virtualMachine`` or ``vm``
+- Values (constants):
+    - Strings are delimited by double quotes ``"..."``
+    - Numbers are integers.
+    - Booleans are either ``:true`` or ``:false``
+    - Example: ``56``, ``"linux"``, ``:true``
+- Relationships: ``<elem> has <relationship> <elem/value>``
+    - There are two types of relationships:
+        - **Associations** are a relationship between two elements (variables).
+        - **Attributes** are a relationship between an element (variable) and a value (variable or constant).
+    - Relationships follow this naming structure ``<package>.<class>.<relationship>``.
+    - Example:
+        - ``vm has abstract.ComputingNode.ifaces iface`` is an **Association**, as it puts in relationship the element ``vm`` with the element ``iface``.
+
+        - ``vm has abstract.ComputingNode.cpu_count >= 4`` is an **Attribute** Relationship, as it compares a property (``cpu_count``) of the element ``vm`` with a constant number.
+- Classes: ``class <class name>``
+    - They represent a kind of element in the architecture.
+    - Classes follow this naming structure ``<package>.<class>``
+- Equality: ``is``, ``is not``
+    - Used to set an equality (or inequality) constraint on an element variable. You can use it to assign a class to an element.
+    - Example: ``vm is class abstract.VirtualMachine``
+- Comparisons: ``>``,  ``>=``,  ``<``,  ``<=``,  ``==``,  ``!=``
+    - You can compare attributes with constants, or attributes with attributes.
+    - Example: 
+        - ``vm has abstract.ComputingNode.cpu_count >= 4`` compares attribute ``cpu_count`` with a numeric constant.
+        - ``vm1 has abstract.ComputingNode.cpu_count >= vm2 abstract.ComputingNode.cpu_count`` compares attribute ``cpu_count`` of ``vm1`` with the one of ``vm2``.
+
+
+
+Operator Precedence
+-------------------
+
+``exists``/``forall`` > ``not`` > ``or`` > ``and`` > ``implies`` > ``iff``
+
+Grammar
+=======
+See the `grammar.lark`_ file on GitHub, it's written in a EBNF-like form.
+
+
+.. _`Syntax Highlight`: https://marketplace.visualstudio.com/items?itemName=andreafra.piacere-domlr
+.. _`First Order Logic`: https://en.wikipedia.org/wiki/First-order_logic
+.. _`grammar.lark`: https://github.com/andreafra/piacere-model-checker/blob/main/mc_openapi/doml_mc/dsl_parser/grammar.lark
\ No newline at end of file
diff --git a/mc_openapi/__init__.py b/mc_openapi/__init__.py
index 58d478ab160be0a838dab2d6ce9a15ce6d80b07b..a33997dd1004d8fb312324a652e27fcab292f4eb 100644
--- a/mc_openapi/__init__.py
+++ b/mc_openapi/__init__.py
@@ -1 +1 @@
-__version__ = '1.2.0'
+__version__ = '2.1.0'
diff --git a/mc_openapi/__main__.py b/mc_openapi/__main__.py
index 4289b5dfd801aafbfdaced9b7877ca948fda7523..3ce069095a1d1f2cecafadd719dcc8868f5c5655 100644
--- a/mc_openapi/__main__.py
+++ b/mc_openapi/__main__.py
@@ -1,5 +1,198 @@
 #!/usr/bin/env python3
+import argparse
+import sys
+
+from doml_synthesis.data import init_data
+from doml_synthesis.requirements import builtin_requirements
+from doml_synthesis.results import check_synth_results, save_results
+from doml_synthesis.solver import solve
+from doml_synthesis.types import State
 
 from mc_openapi.app_config import app
+from mc_openapi.doml_mc import DOMLVersion
+from mc_openapi.doml_mc.domlr_parser.exceptions import RequirementException
+from mc_openapi.doml_mc.domlr_parser.parser import (DOMLRTransformer, Parser,
+                                                    SynthesisDOMLRTransformer)
+from mc_openapi.doml_mc.imc import RequirementStore
+from mc_openapi.doml_mc.intermediate_model.metamodel import MetaModelDocs
+from mc_openapi.doml_mc.mc import ModelChecker
+from mc_openapi.doml_mc.mc_result import MCResult
+from mc_openapi.doml_mc.xmi_parser.doml_model import get_pyecore_model
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument("-d", "--doml", dest="doml", help="the DOMLX file to check")
+parser.add_argument("-V", "--doml-version", dest="doml_version", help="(optional) the version used by the DOMLX file")
+parser.add_argument("-r", "--requirements", dest="requirements", help="the user-specified requirements file to check")
+parser.add_argument("-p", "--port", dest="port", type=int, default=8080, help="the port exposing the model checker REST API (default: 8080)")
+parser.add_argument("-v", "--verbose", dest="verbose", action='store_true', help="print a detailed human-readable output of everything going on. Helpful for debugging.")
+# Model Checker
+parser.add_argument("-c", "--check-consistency", dest="consistency", action='store_true', help="check on additional built-in consistency requirements")
+parser.add_argument("-S", "--skip-common-checks", dest="skip_common", action='store_true', help="skip check on common built-in requirements")
+parser.add_argument("-t", "--threads", dest="threads", type=int, default=2, help="number of threads used by the model checker")
+# Synthesis
+parser.add_argument("-s", "--synth", dest="synth", action='store_true', help="synthetize a new DOMLX file from requirements")
+parser.add_argument("-m", "--max-tries", dest="tries", type=int, default=8, help="max number of iteration while trying to solve the model with unbounded variables")
+
+args = parser.parse_args()
+
+# Print only when -v flag is true
+def printv(*_args):
+    if args.verbose:
+        print(*_args)
+
+printv("== Verbose: ON ==")
+
+if not args.doml and not args.synth:
+    # Start the webserver
+    app.run(port=args.port)
+else:
+    # Run only it via command line
+    doml_path = args.doml
+    reqs_path = args.requirements
+
+    # Try using the user-provided DOML version
+    doml_ver = None
+    if args.doml_version is not None:
+        try:
+            doml_ver = DOMLVersion[args.doml_version]
+        except:
+            # Suggest valid DOML versions
+            print(f"Unknown DOML version '{args.doml_version}'")
+            versions = [ ver.name for ver in list(DOMLVersion)]
+            print(f"Available DOML versions = {versions}")
+            exit(1)
+
+    with open(doml_path, "rb") as xmif:
+        # Read DOML file from path
+        doml_xmi = xmif.read()
+
+    # Config the model checker (setup metamodels and intermediate models)
+    dmc = ModelChecker(doml_xmi, doml_ver)
+    doml_ver = dmc.doml_version
+
+    # Store of Requirements and unique string constants
+    user_req_store = RequirementStore()
+    user_req_str_consts = []
+
+    synth_user_reqs = []
+    synth_user_reqs_strings = []
+
+    try:
+        domlr_parser = Parser(DOMLRTransformer)
+        if args.synth:
+            synth_domlr_parser = Parser(SynthesisDOMLRTransformer)
+    except Exception as e:
+        print(e, file=sys.stderr)
+        print("Failed to setup DOMLR Parser")
+        exit(-1)
+
+    user_reqs = None
+
+    if reqs_path:
+        with open(reqs_path, "r") as reqsf:
+        # Read the user requirements written in DSL
+            user_reqs = reqsf.read()
+        # Parse them
+        try:
+            user_req_store, user_req_str_consts = domlr_parser.parse(user_reqs)
+        except Exception as e:
+            print(e, file=sys.stderr)
+            print("Failed to parse the DOMLR.", file=sys.stderr)
+            exit(-1)
+
+    if doml_ver == DOMLVersion.V2_2:
+        model = get_pyecore_model(doml_xmi, doml_ver)
+        func_reqs = model.functionalRequirements.items
+        for req in func_reqs:
+            req_name: str = req.name
+            req_text: str = req.description
+            req_text = req_text.replace("```", "")
+
+            doml_req_store, doml_req_str_consts = domlr_parser.parse(req_text)
+            user_req_store += doml_req_store
+            user_req_str_consts += doml_req_str_consts
+
+            if args.synth:
+                synth_doml_req_store, synth_doml_req_str_consts = synth_domlr_parser.parse(req_text, for_synthesis=True)
+                synth_user_reqs.append(synth_doml_req_store)
+                synth_user_reqs_strings += synth_doml_req_str_consts
+
+    # Remove possible duplicates
+    user_req_str_consts = list(set(user_req_str_consts))
+
+    if not args.synth:
+        try:
+            # Check satisfiability
+            results = dmc.check_requirements(
+                threads=args.threads, 
+                user_requirements=user_req_store,
+                user_str_values=user_req_str_consts,
+                consistency_checks=args.consistency,
+                skip_common_requirements=args.skip_common
+            )
+
+            res, msg = results.summarize()
+
+            if res == MCResult.sat:
+                print("sat")
+            else:
+                print(res.name)
+                print("\033[91m{}\033[00m".format(msg))
+        except RequirementException as e:
+            print(e.message)
+
+    else: # Synthesis
+        printv("Running synthesis...")
+        
+
+        # Required files:
+        mm = MetaModelDocs[doml_ver]
+        im = {
+            k: { 
+                'id': v.id_,
+                'name': v.user_friendly_name,
+                'class': v.class_,
+                'assocs': v.associations,
+                'attrs': v.attributes
+            }
+            for k, v in  dmc.intermediate_model.items()
+        }
+
+        if user_reqs:
+            try:
+                ext_domlr_reqs, ext_domlr_reqs_strings = synth_domlr_parser.parse(user_reqs, for_synthesis=True)
+                synth_user_reqs.append(ext_domlr_reqs)
+                synth_user_reqs_strings += ext_domlr_reqs_strings
+            except Exception as e:
+                print(e, file=sys.stderr)
+                print("Failed to parse the DOMLR.", file=sys.stderr)
+                exit(-1)
+
+    
+        # Remove duplicated strings
+        print(synth_user_reqs_strings)
+        synth_user_reqs_strings = list(set(synth_user_reqs_strings))
+
+        state = State()
+        # Parse MM and IM
+        state = init_data(
+            state, 
+            doml=im, 
+            metamodel=mm, 
+        )
+
+        reqs = synth_user_reqs
+        if not args.skip_common:
+            reqs.append(builtin_requirements)
 
-app.run(port=8080)
+        state = solve(
+            state, 
+            requirements=reqs, 
+            strings=synth_user_reqs_strings,
+            max_tries=args.tries
+        )
+        # Update state
+        state = save_results(state)
+        # Print output
+        state = check_synth_results(state)
\ No newline at end of file
diff --git a/mc_openapi/assets/doml_meta_v2.0.yaml b/mc_openapi/assets/doml_meta_v2.0.yaml
index f2b58f9344e22f1c759f37c6fa84a3b125e894ba..08cc7176fbeda1681e86fbc37afa83080423522c 100644
--- a/mc_openapi/assets/doml_meta_v2.0.yaml
+++ b/mc_openapi/assets/doml_meta_v2.0.yaml
@@ -84,10 +84,10 @@ application:
         associations:
             exposedInterfaces:
                 class: application_SoftwareInterface
-                mutiplicity: "0..*"
+                multiplicity: "0..*"
             consumedInterfaces:
                 class: application_SoftwareInterface
-                mutiplicity: "0..*"
+                multiplicity: "0..*"
     SaaS:
         superclass: application_ApplicationComponent
         attributes:
@@ -97,7 +97,7 @@ application:
         associations:
             exposedInterfaces:
                 class: application_SoftwareInterface
-                mutiplicity: "0..*"
+                multiplicity: "0..*"
     SoftwareInterface:
         superclass: application_ApplicationComponent
         attributes:
diff --git a/mc_openapi/assets/doml_meta_v2.1.1.yaml b/mc_openapi/assets/doml_meta_v2.1.1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..df4d72d197d0de585dc74c85c9c487fc59b4dc98
--- /dev/null
+++ b/mc_openapi/assets/doml_meta_v2.1.1.yaml
@@ -0,0 +1,541 @@
+commons:
+    DOMLElement:
+        attributes:
+            name:
+                type: String
+                multiplicity: "0..1"
+            description:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            annotations:
+                class: commons_Property
+                multiplicity: "0..*"
+    Property:
+        attributes:
+            key:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            reference:
+                class: commons_DOMLElement
+                multiplicity: "0..1"
+    IProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: Integer
+                multiplicity: "0..1"
+    SProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: String
+                multiplicity: "0..1"
+    FProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: String
+                multiplicity: "0..1"
+    BProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: Boolean
+                multiplicity: "0..1"
+    Configuration:
+        superclass: commons_DOMLElement
+        associations:
+            deployments:
+                class: commons_Deployment
+                multiplicity: "0..*"
+    Credentials:
+        abstract: true
+        superclass: commons_DOMLElement
+    DeployableElement:
+        abstract: true
+        superclass: commons_DOMLElement # It's not present in the ECore, but without it breaks.
+    Deployment:
+        associations:
+            component:
+                class: commons_DeployableElement
+                multiplicity: "1"
+            node:
+                class: infrastructure_InfrastructureElement
+                multiplicity: "1"
+    KeyPair:
+        superclass: commons_Credentials
+        attributes:
+            user:
+                type: String
+                multiplicity: "0..1"
+            keyfile:
+                type: String
+                multiplicity: "0..1"
+            algorithm:
+                type: String
+                multiplicity: "0..1"
+            bits:
+                type: Integer
+                multiplicity: "0..1"
+    UserPass:
+        superclass: commons_Credentials
+        attributes:
+            user:
+                type: String
+                multiplicity: "0..1"
+            password:
+                type: String
+                multiplicity: "0..1"
+    Source:
+        superclass: commons_DOMLElement
+        attributes:
+            engine:
+                type: String
+                multiplicity: "0..*"
+            uri:
+                type: String
+                multiplicity: "0..*"
+            entry:
+                type: String
+                multiplicity: "0..*"
+            backend:
+                type: String
+                multiplicity: "0..*"
+        associations:
+            credential:
+                class: commons_Credentials
+application:
+    ApplicationLayer:
+        superclass: commons_DOMLElement
+        associations:
+            components:
+                class: application_ApplicationComponent
+                multiplicity: "0..*"
+    ApplicationComponent:
+        superclass: commons_DOMLElement
+    SoftwareComponent:
+        superclass: application_ApplicationComponent # and commons_DeployableElement, but we can't handle multiple parent classes, can't we?
+        attributes:
+            isPersistent:
+                type: Boolean
+                multiplicity: "1"
+                default: false
+            licenseCost:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            exposedInterfaces:
+                class: application_SoftwareInterface
+                multiplicity: "0..*"
+            consumedInterfaces:
+                class: application_SoftwareInterface
+                multiplicity: "0..*"
+            src:
+                class: commons_Source
+                multiplicity: "0..1"
+    SaaS:
+        superclass: application_ApplicationComponent
+        attributes:
+            licenseCost:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            exposedInterfaces:
+                class: application_SoftwareInterface
+                multiplicity: "0..*"
+    SoftwareInterface:
+        superclass: application_ApplicationComponent
+        attributes:
+            endPoint:
+                type: String
+                multiplicity: "0..1"
+    DBMS:
+        superclass: application_SoftwareComponent
+    SaaSDBMS:
+        superclass: application_SaaS
+
+infrastructure:
+    InfrastructureLayer:
+        superclass: commons_DOMLElement
+        associations:
+            nodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+            generators:
+                class: infrastructure_ComputingNodeGenerator
+                multiplicity: "0..*"
+            storages:
+                class: infrastructure_Storage
+                multiplicity: "0..*"
+            faas:
+                class: infrastructure_FunctionAsAService
+                multiplicity: "0..*"
+            credentials:
+                class: commons_Credentials
+                multiplicity: "0..*"
+            groups:
+                class: infrastructure_ComputingGroup
+                multiplicity: "0..*"
+            securityGroups:
+                class: infrastructure_SecurityGroup
+                multiplicity: "0..*"
+            networks:
+                class: infrastructure_Network
+                multiplicity: "0..*"
+            rules:
+                class: infrastructure_MonitoringRule
+                multiplicity: "0..*"
+    MonitoringRule:
+        superclass: commons_DOMLElement
+        attributes:
+            condition:
+                type: String 
+                multiplicity: "1"
+            strategy:
+                type: String 
+                multiplicity: "1"
+            strategyConfigurationString:
+                type: String 
+                multiplicity: "0..1"
+    InfrastructureElement:
+        superclass: commons_DeployableElement
+    ComputingNode:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            architecture: 
+                type: String 
+                multiplicity: "0..1"
+            os: 
+                type: String 
+                multiplicity: "0..1"
+            memory_mb:
+                type: Integer 
+                multiplicity: "0..1"
+            memory_kb:  # Missing in official Ecore, added by parser
+                type: Integer 
+                multiplicity: "0..1"
+            storage: 
+                type: String 
+                multiplicity: "0..1"
+            cpu_count: 
+                type: Integer 
+                multiplicity: "0..1"
+            cost: 
+                type: Integer  # in cents 
+                multiplicity: "0..1"
+            disabledMonitorings:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+            location:
+                class: infrastructure_Location
+                multiplicity: "0..1"
+            credentials:
+                class: commons_Credentials
+                multiplicity: "0..1"
+            group:
+                class: infrastructure_ComputingGroup
+                multiplicity: "0..1"
+                inverse_of: infrastructure_ComputingGroup::groupedNodes
+    PhysicalComputingNode:
+        superclass: infrastructure_ComputingNode
+    VirtualMachine:
+        superclass: infrastructure_ComputingNode
+        attributes:
+            sizeDescription:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            generatedFrom:
+                class: infrastructure_VMImage
+                multiplicity: "0..1"
+    Location:
+        superclass: commons_DOMLElement
+        attributes:
+            region:
+                type: String
+                multiplicity: "0..1"
+            zone:
+                type: String
+                multiplicity: "0..1"
+    ContainerConfig:
+        superclass: commons_DOMLElement
+        attributes:
+            container_port:
+                type: Integer
+                multiplicity: "0..1"
+            vm_port:
+                type: Integer
+                multiplicity: "0..1"
+        associations:
+            host:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..1"
+            iface:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..1"
+    Container:
+        superclass: infrastructure_ComputingNode
+        associations:
+            generatedFrom:
+                class: infrastructure_ContainerImage
+                multiplicity: "0..1"
+            configs:
+                class: infrastructure_ContainerConfig
+                multiplicity: "0..*"
+    ComputingNodeGenerator:
+        superclass: commons_DOMLElement
+        attributes:
+            uri:
+                type: String
+                multiplicity: "0..1"
+            kind:
+                type: GeneratorKind  # enum { SCRIPT, IMAGE }
+    VMImage:
+        superclass: infrastructure_ComputingNodeGenerator
+        associations:
+            generatedVMs:
+                class: infrastructure_VirtualMachine
+                multiplicity: "0..*"
+                inverse_of: infrastructure_VirtualMachine::generatedFrom
+    ContainerImage:
+        superclass: infrastructure_ComputingNodeGenerator
+        associations:
+            generatedContainers:
+                class: infrastructure_Container
+                multiplicity: "0..*"
+                inverse_of: infrastructure_Container::generatedFrom
+    AutoScalingGroup:
+        superclass: infrastructure_ComputingGroup
+        attributes:
+            min:
+                type: Integer
+                multiplicity: "0..1"
+            max:
+                type: Integer
+                multiplicity: "0..1"
+            loadBalancer:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            machineDefinition:
+                class: infrastructure_VirtualMachine
+                multiplicity: "1"
+            securityGroup:
+                class: infrastructure_SecurityGroup
+                multiplicity: "0..1"
+    Storage:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            label:
+                type: String
+                multiplicity: "0..1"
+            size_gb:
+                type: Integer  # in GBs
+                multiplicity: "0..1"
+            cost: 
+                type: Integer  # in cents 
+                multiplicity: "0..1"
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+    FunctionAsAService:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            cost:
+                type: Integer  # in cents
+                multiplicity: "0..1"
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+    Network:
+        superclass: commons_DOMLElement
+        attributes:
+            protocol:
+                type: String
+                multiplicity: "0..1"
+            addressRange:
+                type: String
+                multiplicity: "0..1"
+            cidr:
+                type: Integer
+                multiplicity: "0..1"
+        associations:
+            connectedIfaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+                inverse_of: infrastructure_NetworkInterface::belongsTo
+            igws:
+                class: infrastructure_InternetGateway
+                multiplicity: "0..*"
+            subnets:
+                class: infrastructure_Subnet
+                multiplicity: "0..*"
+    Subnet:
+        superclass: infrastructure_Network
+        associations:
+            connectedTo:
+                class: infrastructure_Network
+                multiplicity: "0..1"
+    NetworkInterface:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            endPoint:
+                type: Integer
+                multiplicity: "0..1"
+            speed:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            belongsTo:
+                class: infrastructure_Network
+                multiplicity: "0..1" # This should be "1", but it would break InternetGateway
+            associated:
+                class: infrastructure_SecurityGroup
+                multiplicity: "0..1" # TODO: try putting this to 1 and see why it fails
+    InternetGateway:
+        superclass: infrastructure_NetworkInterface
+    ComputingGroup:
+        superclass: commons_DOMLElement
+        associations:
+            groupedNodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+                inverse_of: infrastructure_ComputingNode::group
+    SecurityGroup:
+        superclass: commons_DOMLElement
+        associations:
+            rules:
+                class: infrastructure_Rule
+                multiplicity: "0..*"
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+                inverse_of: infrastructure_NetworkInterface::associated
+    Rule:
+        superclass: commons_DOMLElement
+        attributes:
+            kind:
+                type: String
+                multiplicity: "1"
+            protocol:
+                type: String
+                multiplicity: "1"
+            fromPort:
+                type: Integer
+                multiplicity: "1"
+            toPort:
+                type: Integer
+                multiplicity: "1"
+            cidr:
+                type: String
+                multiplicity: "0..*"
+    SwarmRole:
+        superclass: commons_DOMLElement
+        attributes:
+            kind:
+                type: String
+                multiplicity: "1"
+        associations:
+            nodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+    Swarm:
+        superclass: infrastructure_ComputingGroup
+        associations:
+            roles:
+                class: infrastructure_SwarmRole
+                multiplicity: "0..*"
+    ExtInfrastructureElement:
+        superclass: infrastructure_InfrastructureElement
+
+concrete:
+    ConcreteInfrastructure:
+        superclass: commons_DOMLElement
+        associations:
+            providers:
+                class: concrete_RuntimeProvider
+                multiplicity: "0..*"
+    ConcreteElement:
+        superclass: commons_DOMLElement
+        attributes:
+            configurationScript:
+                type: String
+                multiplicity: "0..1"
+            preexisting:
+                multiplicity: "1"
+                type: Boolean
+                default: false
+    RuntimeProvider:
+        superclass: commons_DOMLElement
+        associations:
+            vms:
+                class: concrete_VirtualMachine
+                multiplicity: "0..*"
+            vmImages:
+                class: concrete_VMImage
+                multiplicity: "0..*"
+            containerImages:
+                class: concrete_ContainerImage
+                multiplicity: "0..*"
+            networks:
+                class: concrete_Network
+                multiplicity: "0..*"
+            storages:
+                class: concrete_Storage
+                multiplicity: "0..*"
+            faas:
+                class: concrete_FunctionAsAService
+                multiplicity: "0..*"
+            group:
+                class: concrete_ComputingGroup
+                multiplicity: "0..*"
+    VirtualMachine:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_VirtualMachine
+                multiplicity: "0..1"
+    VMImage:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_VMImage
+                multiplicity: "0..1"
+    ContainerImage:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_ContainerImage
+                multiplicity: "0..1"
+    Network:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_Network
+                multiplicity: "0..1"
+    Storage:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_Storage
+                multiplicity: "0..1"
+    FunctionAsAService:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_FunctionAsAService
+                multiplicity: "0..1"
+    ComputingGroup:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_ComputingGroup
+                multiplicity: "1"
diff --git a/mc_openapi/assets/doml_meta_v2.1.yaml b/mc_openapi/assets/doml_meta_v2.1.yaml
index a1c19170cc8f86926f8944678399945e04fbde50..cba1f52489abb62aa049084c03073473715d3b81 100644
--- a/mc_openapi/assets/doml_meta_v2.1.yaml
+++ b/mc_openapi/assets/doml_meta_v2.1.yaml
@@ -84,10 +84,10 @@ application:
         associations:
             exposedInterfaces:
                 class: application_SoftwareInterface
-                mutiplicity: "0..*"
+                multiplicity: "0..*"
             consumedInterfaces:
                 class: application_SoftwareInterface
-                mutiplicity: "0..*"
+                multiplicity: "0..*"
     SaaS:
         superclass: application_ApplicationComponent
         attributes:
@@ -97,7 +97,7 @@ application:
         associations:
             exposedInterfaces:
                 class: application_SoftwareInterface
-                mutiplicity: "0..*"
+                multiplicity: "0..*"
     SoftwareInterface:
         superclass: application_ApplicationComponent
         attributes:
@@ -212,7 +212,7 @@ infrastructure:
                 class: infrastructure_ComputingNode
                 multiplicity: "0..1"
             iface:
-                class: infrastructure_NewtorkInterface
+                class: infrastructure_NetworkInterface
                 multiplicity: "0..1"
     Container:
         superclass: infrastructure_ComputingNode
diff --git a/mc_openapi/assets/doml_meta_v2.2.yaml b/mc_openapi/assets/doml_meta_v2.2.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d42e5e06140201f8e6451706edd92db024a1a69f
--- /dev/null
+++ b/mc_openapi/assets/doml_meta_v2.2.yaml
@@ -0,0 +1,532 @@
+commons:
+    DOMLElement:
+        attributes:
+            name:
+                type: String
+                multiplicity: "0..1"
+            description:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            annotations:
+                class: commons_Property
+                multiplicity: "0..*"
+    Property:
+        attributes:
+            key:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            reference:
+                class: commons_DOMLElement
+                multiplicity: "0..1"
+    IProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: Integer
+                multiplicity: "0..1"
+    SProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: String
+                multiplicity: "0..1"
+    FProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: String
+                multiplicity: "0..1"
+    BProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: Boolean
+                multiplicity: "0..1"
+    Configuration:
+        superclass: commons_DOMLElement
+        associations:
+            deployments:
+                class: commons_Deployment
+                multiplicity: "0..*"
+    Credentials:
+        abstract: true
+        superclass: commons_DOMLElement
+    DeployableElement:
+        abstract: true
+        superclass: commons_DOMLElement # It's not present in the ECore, but without it breaks.
+    Deployment:
+        associations:
+            component:
+                class: commons_DeployableElement
+                multiplicity: "1"
+            node:
+                class: infrastructure_InfrastructureElement
+                multiplicity: "1"
+    KeyPair:
+        superclass: commons_Credentials
+        attributes:
+            user:
+                type: String
+                multiplicity: "0..1"
+            keyfile:
+                type: String
+                multiplicity: "0..1"
+            algorithm:
+                type: String
+                multiplicity: "0..1"
+            bits:
+                type: Integer
+                multiplicity: "0..1"
+    UserPass:
+        superclass: commons_Credentials
+        attributes:
+            user:
+                type: String
+                multiplicity: "0..1"
+            password:
+                type: String
+                multiplicity: "0..1"
+    Source:
+        superclass: commons_DOMLElement
+        attributes:
+            entry:
+                type: String
+                multiplicity: "0..*"
+            backend:
+                type: String
+                multiplicity: "0..*"
+application:
+    ApplicationLayer:
+        superclass: commons_DOMLElement
+        associations:
+            components:
+                class: application_ApplicationComponent
+                multiplicity: "0..*"
+    ApplicationComponent:
+        superclass: commons_DOMLElement
+    SoftwareComponent:
+        superclass: application_ApplicationComponent # and commons_DeployableElement, but we can't handle multiple parent classes, can't we?
+        attributes:
+            isPersistent:
+                type: Boolean
+                multiplicity: "1"
+                default: false
+            licenseCost:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            exposedInterfaces:
+                class: application_SoftwareInterface
+                multiplicity: "0..*"
+            consumedInterfaces:
+                class: application_SoftwareInterface
+                multiplicity: "0..*"
+            src:
+                class: commons_Source
+                multiplicity: "0..1"
+    SaaS:
+        superclass: application_ApplicationComponent
+        attributes:
+            licenseCost:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            exposedInterfaces:
+                class: application_SoftwareInterface
+                multiplicity: "0..*"
+    SoftwareInterface:
+        superclass: application_ApplicationComponent
+        attributes:
+            endPoint:
+                type: String
+                multiplicity: "0..1"
+    DBMS:
+        superclass: application_SoftwareComponent
+    SaaSDBMS:
+        superclass: application_SaaS
+
+infrastructure:
+    InfrastructureLayer:
+        superclass: commons_DOMLElement
+        associations:
+            nodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+            generators:
+                class: infrastructure_ComputingNodeGenerator
+                multiplicity: "0..*"
+            storages:
+                class: infrastructure_Storage
+                multiplicity: "0..*"
+            faas:
+                class: infrastructure_FunctionAsAService
+                multiplicity: "0..*"
+            credentials:
+                class: commons_Credentials
+                multiplicity: "0..*"
+            groups:
+                class: infrastructure_ComputingGroup
+                multiplicity: "0..*"
+            securityGroups:
+                class: infrastructure_SecurityGroup
+                multiplicity: "0..*"
+            networks:
+                class: infrastructure_Network
+                multiplicity: "0..*"
+            rules:
+                class: infrastructure_MonitoringRule
+                multiplicity: "0..*"
+    MonitoringRule:
+        superclass: commons_DOMLElement
+        attributes:
+            condition:
+                type: String 
+                multiplicity: "1"
+            strategy:
+                type: String 
+                multiplicity: "1"
+            strategyConfigurationString:
+                type: String 
+                multiplicity: "0..1"
+    InfrastructureElement:
+        superclass: commons_DeployableElement
+    ComputingNode:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            architecture: 
+                type: String 
+                multiplicity: "0..1"
+            os: 
+                type: String 
+                multiplicity: "0..1"
+            memory_mb:
+                type: Integer 
+                multiplicity: "0..1"
+            memory_kb:  # Missing in official Ecore, added by parser
+                type: Integer 
+                multiplicity: "0..1"
+            storage: 
+                type: String 
+                multiplicity: "0..1"
+            cpu_count: 
+                type: Integer 
+                multiplicity: "0..1"
+            cost: 
+                type: Integer  # in cents 
+                multiplicity: "0..1"
+            disabledMonitorings:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+            location:
+                class: infrastructure_Location
+                multiplicity: "0..1"
+            credentials:
+                class: commons_Credentials
+                multiplicity: "0..1"
+            group:
+                class: infrastructure_ComputingGroup
+                multiplicity: "0..1"
+                inverse_of: infrastructure_ComputingGroup::groupedNodes
+    PhysicalComputingNode:
+        superclass: infrastructure_ComputingNode
+    VirtualMachine:
+        superclass: infrastructure_ComputingNode
+        attributes:
+            sizeDescription:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            generatedFrom:
+                class: infrastructure_VMImage
+                multiplicity: "0..1"
+    Location:
+        superclass: commons_DOMLElement
+        attributes:
+            region:
+                type: String
+                multiplicity: "0..1"
+            zone:
+                type: String
+                multiplicity: "0..1"
+    ContainerConfig:
+        superclass: commons_DOMLElement
+        attributes:
+            container_port:
+                type: Integer
+                multiplicity: "0..1"
+            vm_port:
+                type: Integer
+                multiplicity: "0..1"
+        associations:
+            host:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..1"
+            iface:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..1"
+    Container:
+        superclass: infrastructure_ComputingNode
+        associations:
+            generatedFrom:
+                class: infrastructure_ContainerImage
+                multiplicity: "0..1"
+            configs:
+                class: infrastructure_ContainerConfig
+                multiplicity: "0..*"
+    ComputingNodeGenerator:
+        superclass: commons_DOMLElement
+        attributes:
+            uri:
+                type: String
+                multiplicity: "0..1"
+            kind:
+                type: GeneratorKind  # enum { SCRIPT, IMAGE }
+    VMImage:
+        superclass: infrastructure_ComputingNodeGenerator
+        associations:
+            generatedVMs:
+                class: infrastructure_VirtualMachine
+                multiplicity: "0..*"
+                inverse_of: infrastructure_VirtualMachine::generatedFrom
+    ContainerImage:
+        superclass: infrastructure_ComputingNodeGenerator
+        associations:
+            generatedContainers:
+                class: infrastructure_Container
+                multiplicity: "0..*"
+                inverse_of: infrastructure_Container::generatedFrom
+    AutoScalingGroup:
+        superclass: infrastructure_ComputingGroup
+        attributes:
+            min:
+                type: Integer
+                multiplicity: "0..1"
+            max:
+                type: Integer
+                multiplicity: "0..1"
+            loadBalancer:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            machineDefinition:
+                class: infrastructure_VirtualMachine
+                multiplicity: "1"
+            securityGroup:
+                class: infrastructure_SecurityGroup
+                multiplicity: "0..1"
+    Storage:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            label:
+                type: String
+                multiplicity: "0..1"
+            size_gb:
+                type: Integer  # in GBs
+                multiplicity: "0..1"
+            cost: 
+                type: Integer  # in cents 
+                multiplicity: "0..1"
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+    FunctionAsAService:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            cost:
+                type: Integer  # in cents
+                multiplicity: "0..1"
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+    Network:
+        superclass: commons_DOMLElement
+        attributes:
+            protocol:
+                type: String
+                multiplicity: "0..1"
+            addressRange:
+                type: String
+                multiplicity: "0..1"
+            cidr:
+                type: Integer
+                multiplicity: "0..1"
+        associations:
+            connectedIfaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+                inverse_of: infrastructure_NetworkInterface::belongsTo
+            igws:
+                class: infrastructure_InternetGateway
+                multiplicity: "0..*"
+            subnets:
+                class: infrastructure_Subnet
+                multiplicity: "0..*"
+    Subnet:
+        superclass: infrastructure_Network
+        associations:
+            connectedTo:
+                class: infrastructure_Network
+                multiplicity: "0..1"
+    NetworkInterface:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            endPoint:
+                type: Integer
+                multiplicity: "0..1"
+            speed:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            belongsTo:
+                class: infrastructure_Network
+                multiplicity: "0..1" # This should be "1", but it would break InternetGateway
+            associated:
+                class: infrastructure_SecurityGroup
+                multiplicity: "0..1" # TODO: try putting this to 1 and see why it fails
+    InternetGateway:
+        superclass: infrastructure_NetworkInterface
+    ComputingGroup:
+        superclass: commons_DOMLElement
+        associations:
+            groupedNodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+                inverse_of: infrastructure_ComputingNode::group
+    SecurityGroup:
+        superclass: commons_DOMLElement
+        associations:
+            rules:
+                class: infrastructure_Rule
+                multiplicity: "0..*"
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+                inverse_of: infrastructure_NetworkInterface::associated
+    Rule:
+        superclass: commons_DOMLElement
+        attributes:
+            kind:
+                type: String
+                multiplicity: "1"
+            protocol:
+                type: String
+                multiplicity: "1"
+            fromPort:
+                type: Integer
+                multiplicity: "1"
+            toPort:
+                type: Integer
+                multiplicity: "1"
+            cidr:
+                type: String
+                multiplicity: "0..*"
+    SwarmRole:
+        superclass: commons_DOMLElement
+        attributes:
+            kind:
+                type: String
+                multiplicity: "1"
+        associations:
+            nodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+    Swarm:
+        superclass: infrastructure_ComputingGroup
+        associations:
+            roles:
+                class: infrastructure_SwarmRole
+                multiplicity: "0..*"
+    ExtInfrastructureElement:
+        superclass: infrastructure_InfrastructureElement
+
+concrete:
+    ConcreteInfrastructure:
+        superclass: commons_DOMLElement
+        associations:
+            providers:
+                class: concrete_RuntimeProvider
+                multiplicity: "0..*"
+    ConcreteElement:
+        superclass: commons_DOMLElement
+        attributes:
+            configurationScript:
+                type: String
+                multiplicity: "0..1"
+            preexisting:
+                multiplicity: "1"
+                type: Boolean
+                default: false
+    RuntimeProvider:
+        superclass: commons_DOMLElement
+        associations:
+            vms:
+                class: concrete_VirtualMachine
+                multiplicity: "0..*"
+            vmImages:
+                class: concrete_VMImage
+                multiplicity: "0..*"
+            containerImages:
+                class: concrete_ContainerImage
+                multiplicity: "0..*"
+            networks:
+                class: concrete_Network
+                multiplicity: "0..*"
+            storages:
+                class: concrete_Storage
+                multiplicity: "0..*"
+            faas:
+                class: concrete_FunctionAsAService
+                multiplicity: "0..*"
+            group:
+                class: concrete_ComputingGroup
+                multiplicity: "0..*"
+    VirtualMachine:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_VirtualMachine
+                multiplicity: "0..1"
+    VMImage:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_VMImage
+                multiplicity: "0..1"
+    ContainerImage:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_ContainerImage
+                multiplicity: "0..1"
+    Network:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_Network
+                multiplicity: "0..1"
+    Storage:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_Storage
+                multiplicity: "0..1"
+    FunctionAsAService:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_FunctionAsAService
+                multiplicity: "0..1"
+    ComputingGroup:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_ComputingGroup
+                multiplicity: "1"
diff --git a/mc_openapi/assets/doml_v2.1.1.ecore b/mc_openapi/assets/doml_v2.1.1.ecore
new file mode 100644
index 0000000000000000000000000000000000000000..a60a074bc835051b98255dfb978200656e955ef9
--- /dev/null
+++ b/mc_openapi/assets/doml_v2.1.1.ecore
@@ -0,0 +1,419 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="doml" nsURI="http://www.piacere-project.eu/doml" nsPrefix="doml">
+  <eAnnotations source="emf.gen">
+    <details key="basePackage" value="eu.piacere.doml"/>
+    <details key="fileExtensions" value="domlx"/>
+    <details key="complianceLevel" value="JDK80"/>
+  </eAnnotations>
+  <eSubpackages name="commons" nsURI="http://www.piacere-project.eu/doml/commons"
+      nsPrefix="commons">
+    <eClassifiers xsi:type="ecore:EClass" name="DOMLModel" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="version" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
+          defaultValueLiteral="2.1.1"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="application" eType="#//application/ApplicationLayer"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="infrastructure" eType="#//infrastructure/InfrastructureLayer"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="concretizations" upperBound="-1"
+          eType="#//concrete/ConcreteInfrastructure" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="optimization" eType="#//optimization/OptimizationLayer"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="configurations" upperBound="-1"
+          eType="#//commons/Configuration" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="activeConfiguration"
+          eType="#//commons/Configuration"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="activeInfrastructure"
+          eType="#//concrete/ConcreteInfrastructure"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="functionalRequirements"
+          upperBound="-1" eType="#//commons/Requirement" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Property" abstract="true">
+      <eOperations name="getValue" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EJavaObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="key" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="reference" eType="#//commons/DOMLElement"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="IProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="FProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtensionElement" abstract="true">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="metaclassName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DOMLElement" abstract="true">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="annotations" upperBound="-1"
+          eType="#//commons/Property" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="contributesTo" upperBound="-1"
+          eType="#//commons/Requirement" eOpposite="#//commons/Requirement/predicatesOn"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Configuration" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="deployments" upperBound="-1"
+          eType="#//commons/Deployment" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeployableElement" abstract="true"/>
+    <eClassifiers xsi:type="ecore:EClass" name="Deployment">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="component" lowerBound="1"
+          eType="#//commons/DeployableElement"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="node" lowerBound="1"
+          eType="#//infrastructure/InfrastructureElement"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Requirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="predicatesOn" upperBound="-1"
+          eType="#//commons/DOMLElement" eOpposite="#//commons/DOMLElement/contributesTo"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="RangedRequirement" eSuperTypes="#//commons/Requirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="EnumeratedRequirement" eSuperTypes="#//commons/Requirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentRequirement" abstract="true"
+        eSuperTypes="#//commons/Requirement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeTypeRequirement" eSuperTypes="#//commons/DeploymentRequirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="validTypes" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeWithPropertyRequirement"
+        eSuperTypes="#//commons/DeploymentRequirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentToSpecificNodeRequirement"
+        eSuperTypes="#//commons/DeploymentRequirement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="validElements" upperBound="-1"
+          eType="#//infrastructure/InfrastructureElement"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Credentials" abstract="true" eSuperTypes="#//commons/DOMLElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="KeyPair" eSuperTypes="#//commons/Credentials">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="user" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="keyfile" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="algorithm" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="bits" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="UserPass" eSuperTypes="#//commons/Credentials">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="username" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="password" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Source" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="engine" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="uri" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="entry" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="backend" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="credential" eType="#//commons/Credentials"
+          containment="true"/>
+    </eClassifiers>
+  </eSubpackages>
+  <eSubpackages name="application" nsURI="http://www.piacere-project.eu/doml/application"
+      nsPrefix="app">
+    <eClassifiers xsi:type="ecore:EClass" name="ApplicationLayer" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="components" upperBound="-1"
+          eType="#//application/ApplicationComponent" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ApplicationComponent" abstract="true"
+        eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="SoftwareComponent" eSuperTypes="#//application/ApplicationComponent">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="isPersistent" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"
+          defaultValueLiteral="false"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1"
+          eType="#//application/SoftwareInterface" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="consumedInterfaces" upperBound="-1"
+          eType="#//application/SoftwareInterface"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="src" eType="#//commons/Source"
+          containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DBMS" eSuperTypes="#//application/SoftwareComponent"/>
+    <eClassifiers xsi:type="ecore:EClass" name="SaaS" eSuperTypes="#//application/ApplicationComponent">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1"
+          eType="#//application/SoftwareInterface" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SaaSDBMS" eSuperTypes="#//application/SaaS"/>
+    <eClassifiers xsi:type="ecore:EClass" name="SoftwareInterface" eSuperTypes="#//application/ApplicationComponent">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtApplicationComponent" eSuperTypes="#//application/ApplicationComponent #//commons/ExtensionElement"/>
+  </eSubpackages>
+  <eSubpackages name="infrastructure" nsURI="http://www.piacere-project.eu/doml/infrastructure"
+      nsPrefix="infra">
+    <eClassifiers xsi:type="ecore:EClass" name="InfrastructureLayer" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1"
+          eType="#//infrastructure/ComputingNode" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generators" upperBound="-1"
+          eType="#//infrastructure/ComputingNodeGenerator" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1"
+          eType="#//infrastructure/Storage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1"
+          eType="#//infrastructure/FunctionAsAService" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" upperBound="-1"
+          eType="#//commons/Credentials" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="groups" upperBound="-1"
+          eType="#//infrastructure/ComputingGroup" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroups" upperBound="-1"
+          eType="#//infrastructure/SecurityGroup" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1"
+          eType="#//infrastructure/Network" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1"
+          eType="#//infrastructure/MonitoringRule" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="MonitoringRule" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="condition" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategy" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategyConfigurationString"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingGroup" abstract="true" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="groupedNodes" upperBound="-1"
+          eType="#//infrastructure/ComputingNode" eOpposite="#//infrastructure/ComputingNode/group"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="AutoScalingGroup" eSuperTypes="#//infrastructure/ComputingGroup">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="machineDefinition" lowerBound="1"
+          eType="#//infrastructure/VirtualMachine" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"
+          defaultValueLiteral="1"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"
+          defaultValueLiteral="1"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroup" eType="#//infrastructure/SecurityGroup"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="loadBalancer" eType="#//infrastructure/LoadBalancerKind"
+          defaultValueLiteral="DEFAULT"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="LoadBalancerKind">
+      <eLiterals name="DEFAULT"/>
+      <eLiterals name="INTERNAL" value="1"/>
+      <eLiterals name="EXTERNAL" value="2"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Rule" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RuleKind"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="fromPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="toPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cidr" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="RuleKind">
+      <eLiterals name="EGRESS"/>
+      <eLiterals name="INGRESS" value="1"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SecurityGroup" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1"
+          eType="#//infrastructure/Rule" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/associated"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="AvailabilityGroup" eSuperTypes="#//infrastructure/ComputingGroup"/>
+    <eClassifiers xsi:type="ecore:EClass" name="InfrastructureElement" abstract="true"
+        eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingNode" abstract="true" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="architecture" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="os" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="memory_mb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="storage" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cpu_count" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="location" eType="#//infrastructure/Location"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" eType="#//commons/Credentials"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="group" eType="#//infrastructure/ComputingGroup"
+          eOpposite="#//infrastructure/ComputingGroup/groupedNodes"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="disabledMonitorings"
+          upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingNodeGenerator" abstract="true"
+        eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="uri" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/GeneratorKind"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="GeneratorKind">
+      <eLiterals name="SCRIPT"/>
+      <eLiterals name="IMAGE" value="1"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedVMs" upperBound="-1"
+          eType="#//infrastructure/VirtualMachine" eOpposite="#//infrastructure/VirtualMachine/generatedFrom"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedContainers"
+          upperBound="-1" eType="#//infrastructure/Container" eOpposite="#//infrastructure/Container/generatedFrom"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="PhysicalComputingNode" eSuperTypes="#//infrastructure/ComputingNode"/>
+    <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//infrastructure/ComputingNode">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="sizeDescription" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/VMImage"
+          eOpposite="#//infrastructure/VMImage/generatedVMs"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Location" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="region" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="zone" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerConfig" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="container_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="vm_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="host" eType="#//infrastructure/ComputingNode"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="iface" eType="#//infrastructure/NetworkInterface"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Container" eSuperTypes="#//infrastructure/ComputingNode">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/ContainerImage"
+          eOpposite="#//infrastructure/ContainerImage/generatedContainers"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="configs" upperBound="-1"
+          eType="#//infrastructure/ContainerConfig" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="addressRange" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="connectedIfaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/belongsTo"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="igws" upperBound="-1"
+          eType="#//infrastructure/InternetGateway" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="subnets" upperBound="-1"
+          eType="#//infrastructure/Subnet" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Subnet" eSuperTypes="#//infrastructure/Network">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="connectedTo" upperBound="-1"
+          eType="#//infrastructure/Subnet"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="NetworkInterface" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="speed" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="belongsTo" eType="#//infrastructure/Network"
+          eOpposite="#//infrastructure/Network/connectedIfaces"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="associated" eType="#//infrastructure/SecurityGroup"
+          eOpposite="#//infrastructure/SecurityGroup/ifaces"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="InternetGateway" eSuperTypes="#//infrastructure/NetworkInterface"/>
+    <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="label" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="size_gb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="RoleKind">
+      <eLiterals name="NONE"/>
+      <eLiterals name="MANAGER" value="1"/>
+      <eLiterals name="WORKER" value="2"/>
+      <eLiterals name="MASTER" value="3"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SwarmRole" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RoleKind"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1"
+          eType="#//infrastructure/ComputingNode" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Swarm" eSuperTypes="#//infrastructure/ComputingGroup">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="roles" upperBound="-1"
+          eType="#//infrastructure/SwarmRole" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtInfrastructureElement" eSuperTypes="#//infrastructure/InfrastructureElement #//commons/ExtensionElement"/>
+  </eSubpackages>
+  <eSubpackages name="concrete" nsURI="http://www.piacere-project.eu/doml/concrete"
+      nsPrefix="concrete">
+    <eClassifiers xsi:type="ecore:EClass" name="ConcreteInfrastructure" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="providers" upperBound="-1"
+          eType="#//concrete/RuntimeProvider" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="RuntimeProvider" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="vms" upperBound="-1"
+          eType="#//concrete/VirtualMachine" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="vmImages" upperBound="-1"
+          eType="#//concrete/VMImage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="containerImages" upperBound="-1"
+          eType="#//concrete/ContainerImage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1"
+          eType="#//concrete/Network" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1"
+          eType="#//concrete/Storage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1"
+          eType="#//concrete/FunctionAsAService" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="group" upperBound="-1"
+          eType="#//concrete/ComputingGroup" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ConcreteElement" abstract="true" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="configurationScript"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="preexisting" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"
+          defaultValueLiteral="false"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VirtualMachine"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VMImage"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ContainerImage"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Network"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Storage"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/FunctionAsAService"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingGroup" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ComputingGroup"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtConcreteElement" eSuperTypes="#//concrete/ConcreteElement #//commons/ExtensionElement"/>
+  </eSubpackages>
+  <eSubpackages name="optimization" nsURI="http://www.piacere-project.eu/doml/optimization"
+      nsPrefix="optimization">
+    <eClassifiers xsi:type="ecore:EClass" name="OptimizationLayer" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="startingHint" eType="#//commons/Configuration"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="solutions" upperBound="-1"
+          eType="#//optimization/OptimizationSolution" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" upperBound="-1"
+          eType="#//optimization/OptimizationObjective" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nonfunctionalRequirements"
+          upperBound="-1" eType="#//commons/Requirement" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ObjectiveValue">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="availability" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="performance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="OptimizationSolution" eSuperTypes="#//commons/Configuration">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" eType="#//optimization/ObjectiveValue"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="decisions" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="OptimizationObjective" abstract="true"
+        eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
+          defaultValueLiteral="Max"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="CountObjective" eSuperTypes="#//optimization/OptimizationObjective"/>
+    <eClassifiers xsi:type="ecore:EClass" name="MeasurableObjective" eSuperTypes="#//optimization/OptimizationObjective"/>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtOptimizationObjective" eSuperTypes="#//optimization/OptimizationObjective #//commons/ExtensionElement"/>
+  </eSubpackages>
+</ecore:EPackage>
diff --git a/mc_openapi/assets/doml_v2.2.ecore b/mc_openapi/assets/doml_v2.2.ecore
new file mode 100644
index 0000000000000000000000000000000000000000..a294cdef5b4ac189c94d5e7088cfb79db4aaf7ae
--- /dev/null
+++ b/mc_openapi/assets/doml_v2.2.ecore
@@ -0,0 +1,415 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="doml" nsURI="http://www.piacere-project.eu/doml" nsPrefix="doml">
+  <eAnnotations source="emf.gen">
+    <details key="basePackage" value="eu.piacere.doml"/>
+    <details key="fileExtensions" value="domlx"/>
+    <details key="complianceLevel" value="JDK80"/>
+  </eAnnotations>
+  <eSubpackages name="commons" nsURI="http://www.piacere-project.eu/doml/commons"
+      nsPrefix="commons">
+    <eClassifiers xsi:type="ecore:EClass" name="DOMLModel" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="version" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
+          defaultValueLiteral="2.2"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="application" eType="#//application/ApplicationLayer"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="infrastructure" eType="#//infrastructure/InfrastructureLayer"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="concretizations" upperBound="-1"
+          eType="#//concrete/ConcreteInfrastructure" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="optimization" eType="#//optimization/OptimizationLayer"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="configurations" upperBound="-1"
+          eType="#//commons/Configuration" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="activeConfiguration"
+          eType="#//commons/Configuration"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="activeInfrastructure"
+          eType="#//concrete/ConcreteInfrastructure"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="functionalRequirements"
+          upperBound="-1" eType="#//commons/Requirement" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Property" abstract="true">
+      <eOperations name="getValue" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EJavaObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="key" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="reference" eType="#//commons/DOMLElement"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="IProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="FProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtensionElement" abstract="true">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="metaclassName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DOMLElement" abstract="true">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="annotations" upperBound="-1"
+          eType="#//commons/Property" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="contributesTo" upperBound="-1"
+          eType="#//commons/Requirement" eOpposite="#//commons/Requirement/predicatesOn"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Configuration" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="deployments" upperBound="-1"
+          eType="#//commons/Deployment" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeployableElement" abstract="true"/>
+    <eClassifiers xsi:type="ecore:EClass" name="Deployment">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="component" lowerBound="1"
+          eType="#//commons/DeployableElement"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="node" lowerBound="1"
+          eType="#//infrastructure/InfrastructureElement"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Requirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="predicatesOn" upperBound="-1"
+          eType="#//commons/DOMLElement" eOpposite="#//commons/DOMLElement/contributesTo"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="RangedRequirement" eSuperTypes="#//commons/Requirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="EnumeratedRequirement" eSuperTypes="#//commons/Requirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentRequirement" abstract="true"
+        eSuperTypes="#//commons/Requirement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeTypeRequirement" eSuperTypes="#//commons/DeploymentRequirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="validTypes" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeWithPropertyRequirement"
+        eSuperTypes="#//commons/DeploymentRequirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentToSpecificNodeRequirement"
+        eSuperTypes="#//commons/DeploymentRequirement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="validElements" upperBound="-1"
+          eType="#//infrastructure/InfrastructureElement"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Credentials" abstract="true" eSuperTypes="#//commons/DOMLElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="KeyPair" eSuperTypes="#//commons/Credentials">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="user" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="keyfile" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="algorithm" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="bits" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="UserPass" eSuperTypes="#//commons/Credentials">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="username" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="password" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Source" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="entry" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="backend" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+  </eSubpackages>
+  <eSubpackages name="application" nsURI="http://www.piacere-project.eu/doml/application"
+      nsPrefix="app">
+    <eClassifiers xsi:type="ecore:EClass" name="ApplicationLayer" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="components" upperBound="-1"
+          eType="#//application/ApplicationComponent" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ApplicationComponent" abstract="true"
+        eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="SoftwareComponent" eSuperTypes="#//application/ApplicationComponent">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="isPersistent" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"
+          defaultValueLiteral="false"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1"
+          eType="#//application/SoftwareInterface" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="consumedInterfaces" upperBound="-1"
+          eType="#//application/SoftwareInterface"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="src" eType="#//commons/Source"
+          containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DBMS" eSuperTypes="#//application/SoftwareComponent"/>
+    <eClassifiers xsi:type="ecore:EClass" name="SaaS" eSuperTypes="#//application/ApplicationComponent">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1"
+          eType="#//application/SoftwareInterface" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SaaSDBMS" eSuperTypes="#//application/SaaS"/>
+    <eClassifiers xsi:type="ecore:EClass" name="SoftwareInterface" eSuperTypes="#//application/ApplicationComponent">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtApplicationComponent" eSuperTypes="#//application/ApplicationComponent #//commons/ExtensionElement"/>
+  </eSubpackages>
+  <eSubpackages name="infrastructure" nsURI="http://www.piacere-project.eu/doml/infrastructure"
+      nsPrefix="infra">
+    <eClassifiers xsi:type="ecore:EClass" name="InfrastructureLayer" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1"
+          eType="#//infrastructure/ComputingNode" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generators" upperBound="-1"
+          eType="#//infrastructure/ComputingNodeGenerator" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1"
+          eType="#//infrastructure/Storage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1"
+          eType="#//infrastructure/FunctionAsAService" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" upperBound="-1"
+          eType="#//commons/Credentials" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="groups" upperBound="-1"
+          eType="#//infrastructure/ComputingGroup" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroups" upperBound="-1"
+          eType="#//infrastructure/SecurityGroup" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1"
+          eType="#//infrastructure/Network" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1"
+          eType="#//infrastructure/MonitoringRule" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="MonitoringRule" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="condition" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategy" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategyConfigurationString"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingGroup" abstract="true" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="groupedNodes" upperBound="-1"
+          eType="#//infrastructure/ComputingNode" eOpposite="#//infrastructure/ComputingNode/group"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="AutoScalingGroup" eSuperTypes="#//infrastructure/ComputingGroup">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="machineDefinition" lowerBound="1"
+          eType="#//infrastructure/VirtualMachine" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"
+          defaultValueLiteral="1"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"
+          defaultValueLiteral="1"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroup" eType="#//infrastructure/SecurityGroup"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="loadBalancer" eType="#//infrastructure/LoadBalancerKind"
+          defaultValueLiteral="DEFAULT"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="LoadBalancerKind">
+      <eLiterals name="DEFAULT"/>
+      <eLiterals name="INTERNAL" value="1"/>
+      <eLiterals name="EXTERNAL" value="2"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Rule" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RuleKind"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="fromPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="toPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cidr" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="RuleKind">
+      <eLiterals name="EGRESS"/>
+      <eLiterals name="INGRESS" value="1"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SecurityGroup" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1"
+          eType="#//infrastructure/Rule" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/associated"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="AvailabilityGroup" eSuperTypes="#//infrastructure/ComputingGroup"/>
+    <eClassifiers xsi:type="ecore:EClass" name="InfrastructureElement" abstract="true"
+        eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingNode" abstract="true" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="architecture" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="os" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="memory_mb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="storage" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cpu_count" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="location" eType="#//infrastructure/Location"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" eType="#//commons/Credentials"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="group" eType="#//infrastructure/ComputingGroup"
+          eOpposite="#//infrastructure/ComputingGroup/groupedNodes"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="disabledMonitorings"
+          upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingNodeGenerator" abstract="true"
+        eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="uri" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/GeneratorKind"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="GeneratorKind">
+      <eLiterals name="SCRIPT"/>
+      <eLiterals name="IMAGE" value="1"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedVMs" upperBound="-1"
+          eType="#//infrastructure/VirtualMachine" eOpposite="#//infrastructure/VirtualMachine/generatedFrom"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedContainers"
+          upperBound="-1" eType="#//infrastructure/Container" eOpposite="#//infrastructure/Container/generatedFrom"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="PhysicalComputingNode" eSuperTypes="#//infrastructure/ComputingNode"/>
+    <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//infrastructure/ComputingNode">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="sizeDescription" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/VMImage"
+          eOpposite="#//infrastructure/VMImage/generatedVMs"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Location" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="region" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="zone" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerConfig" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="container_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="vm_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="host" eType="#//infrastructure/ComputingNode"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="iface" eType="#//infrastructure/NetworkInterface"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Container" eSuperTypes="#//infrastructure/ComputingNode">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/ContainerImage"
+          eOpposite="#//infrastructure/ContainerImage/generatedContainers"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="configs" upperBound="-1"
+          eType="#//infrastructure/ContainerConfig" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="addressRange" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="connectedIfaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/belongsTo"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="igws" upperBound="-1"
+          eType="#//infrastructure/InternetGateway" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="subnets" upperBound="-1"
+          eType="#//infrastructure/Subnet" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Subnet" eSuperTypes="#//infrastructure/Network">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="connectedTo" upperBound="-1"
+          eType="#//infrastructure/Subnet"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="NetworkInterface" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="speed" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="belongsTo" eType="#//infrastructure/Network"
+          eOpposite="#//infrastructure/Network/connectedIfaces"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="associated" eType="#//infrastructure/SecurityGroup"
+          eOpposite="#//infrastructure/SecurityGroup/ifaces"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="InternetGateway" eSuperTypes="#//infrastructure/NetworkInterface"/>
+    <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="label" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="size_gb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="RoleKind">
+      <eLiterals name="NONE"/>
+      <eLiterals name="MANAGER" value="1"/>
+      <eLiterals name="WORKER" value="2"/>
+      <eLiterals name="MASTER" value="3"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SwarmRole" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RoleKind"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1"
+          eType="#//infrastructure/ComputingNode" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Swarm" eSuperTypes="#//infrastructure/ComputingGroup">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="roles" upperBound="-1"
+          eType="#//infrastructure/SwarmRole" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtInfrastructureElement" eSuperTypes="#//infrastructure/InfrastructureElement #//commons/ExtensionElement"/>
+  </eSubpackages>
+  <eSubpackages name="concrete" nsURI="http://www.piacere-project.eu/doml/concrete"
+      nsPrefix="concrete">
+    <eClassifiers xsi:type="ecore:EClass" name="ConcreteInfrastructure" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="providers" upperBound="-1"
+          eType="#//concrete/RuntimeProvider" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="RuntimeProvider" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="vms" upperBound="-1"
+          eType="#//concrete/VirtualMachine" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="vmImages" upperBound="-1"
+          eType="#//concrete/VMImage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="containerImages" upperBound="-1"
+          eType="#//concrete/ContainerImage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1"
+          eType="#//concrete/Network" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1"
+          eType="#//concrete/Storage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1"
+          eType="#//concrete/FunctionAsAService" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="group" upperBound="-1"
+          eType="#//concrete/ComputingGroup" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ConcreteElement" abstract="true" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="configurationScript"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="preexisting" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"
+          defaultValueLiteral="false"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VirtualMachine"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VMImage"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ContainerImage"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Network"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Storage"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/FunctionAsAService"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingGroup" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ComputingGroup"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtConcreteElement" eSuperTypes="#//concrete/ConcreteElement #//commons/ExtensionElement"/>
+  </eSubpackages>
+  <eSubpackages name="optimization" nsURI="http://www.piacere-project.eu/doml/optimization"
+      nsPrefix="optimization">
+    <eClassifiers xsi:type="ecore:EClass" name="OptimizationLayer" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="startingHint" eType="#//commons/Configuration"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="solutions" upperBound="-1"
+          eType="#//optimization/OptimizationSolution" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" upperBound="-1"
+          eType="#//optimization/OptimizationObjective" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nonfunctionalRequirements"
+          upperBound="-1" eType="#//commons/Requirement" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ObjectiveValue">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="availability" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="performance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="OptimizationSolution" eSuperTypes="#//commons/Configuration">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" eType="#//optimization/ObjectiveValue"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="decisions" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="OptimizationObjective" abstract="true"
+        eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
+          defaultValueLiteral="Max"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="CountObjective" eSuperTypes="#//optimization/OptimizationObjective"/>
+    <eClassifiers xsi:type="ecore:EClass" name="MeasurableObjective" eSuperTypes="#//optimization/OptimizationObjective"/>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtOptimizationObjective" eSuperTypes="#//optimization/OptimizationObjective #//commons/ExtensionElement"/>
+  </eSubpackages>
+</ecore:EPackage>
diff --git a/mc_openapi/doml_mc/common_reqs.py b/mc_openapi/doml_mc/common_reqs.py
index cc12e7e79b3f1e828e50c1a5ae33812d7e4d2814..d64a0bdaed3298d9d2bff4a7c159a339ec2ad82f 100644
--- a/mc_openapi/doml_mc/common_reqs.py
+++ b/mc_openapi/doml_mc/common_reqs.py
@@ -1,15 +1,11 @@
+from re import M
 from typing import Optional
 
-from z3 import (
-    Const, Consts, ExprRef,
-    Exists, And, Or, Not,
-    Solver, ModelRef
-)
+from z3 import And, Const, Consts, Exists, ExprRef, ModelRef, Not, Or, Solver
 
-from .imc import (
-    SMTEncoding, SMTSorts, Requirement, RequirementStore
-)
-from .intermediate_model import IntermediateModel, DOMLVersion
+from .error_desc_helper import get_user_friendly_name
+from .imc import Requirement, RequirementStore, SMTEncoding, SMTSorts
+from .intermediate_model import DOMLVersion, IntermediateModel
 
 
 def get_consts(smtsorts: SMTSorts, consts: list[str]) -> list[ExprRef]:
@@ -30,7 +26,7 @@ def vm_iface(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
         )
     )
 
-
+# All software packages can see the interfaces they need through a common network.
 def software_package_iface_net(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
     asc_consumer, asc_exposer, siface, net, net_iface, cnode, cdeployment, enode, edeployment, vm = get_consts(
         smtsorts,
@@ -153,6 +149,7 @@ def software_package_iface_net_v2_1(smtenc: SMTEncoding, smtsorts: SMTSorts) ->
     )
 
 
+# There are no duplicated interfaces.
 def iface_uniq(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
     endPointAttr = smtenc.attributes["infrastructure_NetworkInterface::endPoint"]
     ni1, ni2 = get_consts(smtsorts, ["ni1", "ni2"])
@@ -163,7 +160,7 @@ def iface_uniq(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
         ni1 != ni2,
     )
 
-
+# All software components have been deployed to some node.
 def all_SoftwareComponents_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
     sc, deployment, ielem = get_consts(smtsorts, ["sc", "deployment", "ielem"])
     return And(
@@ -179,7 +176,7 @@ def all_SoftwareComponents_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) ->
         )
     )
 
-
+# All abstract infrastructure elements are mapped to an element in the active concretization.
 def all_infrastructure_elements_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
     def checkOneClass(ielem, concr, provider, celem, ielemClass, providerAssoc, celemAssoc):
         return And(
@@ -227,7 +224,7 @@ def all_infrastructure_elements_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts
         )
     )
 
-
+# All elements in the active concretization are mapped to some abstract infrastructure element.
 def all_concrete_map_something(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
     def checkOneClass(ielem, provider, celem, providerAssoc, celemAssoc):
         return And(
@@ -283,87 +280,150 @@ def all_concrete_map_something(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprR
         )
     )
 
+# def sw_components_have_source_code_property(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+#     sw_comp, prop = get_consts(smtsorts, ["sw_comp prop"])
 
-# Error Descriptions
+#     big_x = smtsorts.attr_data_sort.str(smtenc.str_symbols["source_code"])
 
-def get_user_friendly_name(
-    intermediate_model: IntermediateModel,
-    model: ModelRef,
-    const: ExprRef
-) -> Optional[str]:
-    z3_elem = model[const]
-    if z3_elem is not None:
-        im_elem = intermediate_model.get(str(z3_elem))
-        if im_elem is not None:
-            return im_elem.user_friendly_name
-    return None
+#     return And(
+#         smtenc.element_class_fun(sw_comp) == smtenc.classes["application_SoftwareComponent"],
+#         Not(
+#             Exists([prop], And(
+#                 smtenc.element_class_fun(prop) == smtenc.classes["commons_SProperty"],
+#                 smtenc.attribute_rel(prop, smtenc.attributes["commons_Property::key"], big_x),
+#                 smtenc.association_rel(sw_comp, smtenc.associations["commons_DOMLElement::annotations"], prop)
+#             ))
+#         )
+#     )
 
+def security_group_must_have_iface(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    sg, iface = get_consts(smtsorts, ["sg iface"])
+    return And(
+        smtenc.element_class_fun(sg) == smtenc.classes["infrastructure_SecurityGroup"],
+        Not(Exists([iface], 
+            smtenc.association_rel(iface, smtenc.associations["infrastructure_NetworkInterface::associated"], sg)
+        ))
+    )
+
+# TODO: Check if HTTP should be disabled too
+def external_services_must_have_https(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    saas, sw_iface, sw_comp, deployment, ielem, net_iface, sec_group, rule = get_consts(smtsorts, 
+        ["saas, sw_iface, sw_comp, deployment, ielem, net_iface, sec_group, rule"])
+    return And(
+        smtenc.element_class_fun(saas) == smtenc.classes["application_SaaS"],
+        smtenc.element_class_fun(sec_group) == smtenc.classes["infrastructure_SecurityGroup"],
+        Not(Exists([sw_iface, sw_comp, deployment, ielem, net_iface, rule],
+            And(
+                smtenc.association_rel(saas, smtenc.associations["application_SaaS::exposedInterfaces"], sw_iface),
+                smtenc.association_rel(sw_comp, smtenc.associations["application_SoftwareComponent::consumedInterfaces"], sw_iface),
+                smtenc.association_rel(deployment, smtenc.associations["commons_Deployment::component"], sw_comp),
+                smtenc.association_rel(deployment, smtenc.associations["commons_Deployment::node"], ielem),
+                smtenc.association_rel(ielem, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface),
+                smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::associated"], sec_group),
+                smtenc.association_rel(sec_group, smtenc.associations["infrastructure_SecurityGroup::rules"], rule),
+                smtenc.attribute_rel(rule, smtenc.attributes["infrastructure_Rule::fromPort"], smtsorts.attr_data_sort.int(443)),
+                smtenc.attribute_rel(rule, smtenc.attributes["infrastructure_Rule::toPort"], smtsorts.attr_data_sort.int(443)),
+                smtenc.attribute_rel(rule, smtenc.attributes["infrastructure_Rule::kind"], smtsorts.attr_data_sort.str(smtenc.str_symbols["INGRESS"]))
+            )
+        ))
+    )
+
+# Error Descriptions
 
 def ed_vm_iface(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
-    vm = Const("vm", smtsorts.element_sort)
-    vm_name = get_user_friendly_name(intermediate_model, solver.model(), vm)
-    if vm_name:
-        return f"Virtual machine {vm_name} is connected to no network interface."
-    else:
+    try:
+        vm = Const("vm", smtsorts.element_sort)
+        vm_name = get_user_friendly_name(intermediate_model, solver.model(), vm)
+        if vm_name:
+            return f"Virtual machine {vm_name} is connected to no network interface."
+    except:
         return "A virtual machine is connected to no network interface."
 
 
 def ed_software_package_iface_net(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
-    asc_consumer, asc_exposer, siface = get_consts(
-        smtsorts,
-        ["asc_consumer", "asc_exposer", "siface"]
-    )
-    model = solver.model()
-    asc_consumer_name = get_user_friendly_name(intermediate_model, model, asc_consumer)
-    asc_exposer_name = get_user_friendly_name(intermediate_model, model, asc_exposer)
-    siface_name = get_user_friendly_name(intermediate_model, model, siface)
-    if asc_consumer_name and asc_exposer_name and siface_name:
-        return (
-            f"Software components '{asc_consumer_name}' and '{asc_exposer_name}' "
-            f"are supposed to communicate through interface '{siface_name}', "
-            "but they are deployed to nodes that cannot communicate through a common network."
+    try:
+        asc_consumer, asc_exposer, siface = get_consts(
+            smtsorts,
+            ["asc_consumer", "asc_exposer", "siface"]
         )
-    else:
+        model = solver.model()
+        asc_consumer_name = get_user_friendly_name(intermediate_model, model, asc_consumer)
+        asc_exposer_name = get_user_friendly_name(intermediate_model, model, asc_exposer)
+        siface_name = get_user_friendly_name(intermediate_model, model, siface)
+        if asc_consumer_name and asc_exposer_name and siface_name:
+            return (
+                f"Software components '{asc_consumer_name}' and '{asc_exposer_name}' "
+                f"are supposed to communicate through interface '{siface_name}', "
+                "but they are deployed to nodes that cannot communicate through a common network."
+            )
+    except:
         return "A software package is deployed on a node that has no access to an interface it consumes."
 
 
 def ed_iface_uniq(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
-    ni1, ni2 = get_consts(smtsorts, ["ni1", "ni2"])
-    model = solver.model()
-    ni1_name = get_user_friendly_name(intermediate_model, model, ni1)
-    ni2_name = get_user_friendly_name(intermediate_model, model, ni2)
-    if ni1_name and ni2_name:
-        return f"Network interfaces '{ni1_name}' and '{ni2_name}' share the same IP address."
-    else:
+    try:
+        ni1, ni2 = get_consts(smtsorts, ["ni1", "ni2"])
+        model = solver.model()
+        ni1_name = get_user_friendly_name(intermediate_model, model, ni1)
+        ni2_name = get_user_friendly_name(intermediate_model, model, ni2)
+        if ni1_name and ni2_name:
+            return f"Network interfaces '{ni1_name}' and '{ni2_name}' share the same IP address."
+    except:
         return "Two network interfaces share the same IP address."
 
 
 def ed_all_SoftwareComponents_deployed(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
-    sc = Const("sc", smtsorts.element_sort)
-    sc_name = get_user_friendly_name(intermediate_model, solver.model(), sc)
-    if sc_name:
-        return f"Software component '{sc_name}' is not deployed to any abstract infrastructure node."
-    else:
+    try:
+        sc = Const("sc", smtsorts.element_sort)
+        sc_name = get_user_friendly_name(intermediate_model, solver.model(), sc)
+        if sc_name:
+            return f"Software component '{sc_name}' is not deployed to any abstract infrastructure node."
+    except:
         return "A software component is not deployed to any abstract infrastructure node."
 
 
 def ed_all_infrastructure_elements_deployed(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
-    ielem = Const("ielem", smtsorts.element_sort)
-    ielem_name = get_user_friendly_name(intermediate_model, solver.model(), ielem)
-    if ielem_name:
-        return f"Abstract infrastructure element '{ielem_name}' has not been mapped to any element in the active concretization."
-    else:
+    try:
+        ielem = Const("ielem", smtsorts.element_sort)
+        ielem_name = get_user_friendly_name(intermediate_model, solver.model(), ielem)
+        if ielem_name:
+            return f"Abstract infrastructure element '{ielem_name}' has not been mapped to any element in the active concretization."
+    except:
         return "An abstract infrastructure element has not been mapped to any element in the active concretization."
 
 
 def ed_all_concrete_map_something(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
-    celem = Const("celem", smtsorts.element_sort)
-    celem_name = get_user_friendly_name(intermediate_model, solver.model(), celem)
-    if celem_name:
-        return f"Concrete infrastructure element '{celem_name}' is mapped to no abstract infrastructure element."
-    else:
+    try:
+        celem = Const("celem", smtsorts.element_sort)
+        celem_name = get_user_friendly_name(intermediate_model, solver.model(), celem)
+        if celem_name:
+            return f"Concrete infrastructure element '{celem_name}' is mapped to no abstract infrastructure element."
+    except:
         return "A concrete infrastructure element is mapped to no abstract infrastructure element."
 
+def ed_security_group_must_have_iface(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
+    try:
+        sg = Const("sg", smtsorts.element_sort)
+        sg_name = get_user_friendly_name(intermediate_model, solver.model(), sg)
+        if  sg_name:
+            return f"Security group '{sg_name}' is not associated with any network interface."
+    except:
+        return "A network interface doesn't belong to any security group, or a security group is not associated with any network interface."
+
+def ed_external_services_must_have_https(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
+    try:
+        saas = Const("saas", smtsorts.element_sort)
+        saas_name = get_user_friendly_name(intermediate_model, solver.model(), saas)
+
+        sec_group = Const("sec_group", smtsorts.element_sort)
+        sec_group_name = get_user_friendly_name(intermediate_model, solver.model(), sec_group)
+
+        if saas_name:
+            return f"A Security Group doesn't have a rule to access external service (SaaS) named '{saas_name}' through HTTPS (port 443)."
+        if sec_group:
+            return f"Security Group {sec_group_name} doesn't have a rule to access external service (SaaS) through HTTPS (port 443)."
+    except:
+        return "A Security Group doesn't have a rule to access an external service (SaaS) through HTTPS (port 443)."
 
 RequirementLists = {
     DOMLVersion.V1_0: [
@@ -380,7 +440,9 @@ RequirementLists = {
         (iface_uniq, "iface_uniq", "There are no duplicated interfaces.", ed_iface_uniq),
         (all_SoftwareComponents_deployed, "all_SoftwareComponents_deployed", "All software components have been deployed to some node.", ed_all_SoftwareComponents_deployed),
         (all_infrastructure_elements_deployed, "all_infrastructure_elements_deployed", "All abstract infrastructure elements are mapped to an element in the active concretization.", ed_all_infrastructure_elements_deployed),
-        (all_concrete_map_something, "all_concrete_map_something", "All elements in the active concretization are mapped to some abstract infrastructure element.", ed_all_concrete_map_something)
+        (all_concrete_map_something, "all_concrete_map_something", "All elements in the active concretization are mapped to some abstract infrastructure element.", ed_all_concrete_map_something),
+        (security_group_must_have_iface, "security_group_must_have_iface", "All security group should be a associated to a network interface", ed_security_group_must_have_iface),
+        (external_services_must_have_https, "external_services_must_have_https", "All external SaaS should be accessed through HTTPS.", ed_external_services_must_have_https)
     ],
     DOMLVersion.V2_1: [
         (vm_iface, "vm_iface", "All virtual machines must be connected to at least one network interface.", ed_vm_iface),
@@ -390,7 +452,15 @@ RequirementLists = {
         (all_infrastructure_elements_deployed, "all_infrastructure_elements_deployed", "All abstract infrastructure elements are mapped to an element in the active concretization.", ed_all_infrastructure_elements_deployed),
         (all_concrete_map_something, "all_concrete_map_something", "All elements in the active concretization are mapped to some abstract infrastructure element.", ed_all_concrete_map_something)
     ],
+    DOMLVersion.V2_2: [
+        (vm_iface, "vm_iface", "All virtual machines must be connected to at least one network interface.", ed_vm_iface),
+        (software_package_iface_net_v2_1, "software_package_iface_net", "All software packages can see the interfaces they need through a common network.", ed_software_package_iface_net),
+        (iface_uniq, "iface_uniq", "There are no duplicated interfaces.", ed_iface_uniq),
+        (all_SoftwareComponents_deployed, "all_SoftwareComponents_deployed", "All software components have been deployed to some node.", ed_all_SoftwareComponents_deployed),
+        (all_infrastructure_elements_deployed, "all_infrastructure_elements_deployed", "All abstract infrastructure elements are mapped to an element in the active concretization.", ed_all_infrastructure_elements_deployed),
+        (all_concrete_map_something, "all_concrete_map_something", "All elements in the active concretization are mapped to some abstract infrastructure element.", ed_all_concrete_map_something)
+    ],
 }
 
 
-CommonRequirements = {ver: RequirementStore([Requirement(*rt) for rt in reqs]) for ver, reqs in RequirementLists.items()}
+CommonRequirements = {ver: RequirementStore([Requirement(*rt, flipped=True) for rt in reqs]) for ver, reqs in RequirementLists.items()}
diff --git a/mc_openapi/doml_mc/consistency_reqs.py b/mc_openapi/doml_mc/consistency_reqs.py
index 3b2bcdcf7afe02b7a8c056d74b6430a8b0c78e8d..a562c2ff08cf41a137a4228e1b654419c15c61de 100644
--- a/mc_openapi/doml_mc/consistency_reqs.py
+++ b/mc_openapi/doml_mc/consistency_reqs.py
@@ -8,7 +8,7 @@ from .intermediate_model.metamodel import get_subclasses_dict
 from .imc import (
     SMTEncoding, SMTSorts, Requirement, RequirementStore
 )
-from .z3encoding.utils import Iff
+from .utils import Iff
 
 
 def subclass_cond(smtenc: SMTEncoding, subclasses: set[str], elem: ExprRef) -> ExprRef:
@@ -41,8 +41,8 @@ def get_attribute_type_reqs(mm: MetaModel) -> RequirementStore:
                     tgt_type_cond = smtsorts.attr_data_sort.is_ss(attr_val)  # type: ignore
                 else:  # mm_attr.type == "GeneratorKind"
                     tgt_type_cond = Or(
-                        attr_val == smtsorts.attr_data_sort.ss(smtenc.str_symbols["IMAGE"]),  # type: ignore
-                        attr_val == smtsorts.attr_data_sort.ss(smtenc.str_symbols["SCRIPT"]),  # type: ignore
+                        attr_val == smtsorts.attr_data_sort.str(smtenc.str_symbols["IMAGE"]),  # type: ignore
+                        attr_val == smtsorts.attr_data_sort.str(smtenc.str_symbols["SCRIPT"]),  # type: ignore
                     )
                 return And(
                     smtenc.attribute_rel(elem, smtenc.attributes[f"{cname}::{mm_attr.name}"], attr_val),
@@ -58,6 +58,7 @@ def get_attribute_type_reqs(mm: MetaModel) -> RequirementStore:
                     f"attribute_st_types {cname}::{mm_attr.name}",
                     f"Attribute {mm_attr.name} from class {cname} must have type {mm_attr.type}.",
                     lambda _s, _m, _i: f"Attribute {mm_attr.name} from class {cname} has a type different from {mm_attr.type}.",
+                    flipped=True
                 )
             )
     return RequirementStore(reqs)
@@ -100,6 +101,7 @@ def get_attribute_multiplicity_reqs(mm: MetaModel) -> RequirementStore:
                         f"attribute_mult_lb {cname}::{mm_attr.name}",
                         f"Attribute {mm_attr.name} from class {cname} must have at least one value.",
                         lambda _s, _m, _i: f"Mandatory attribute {mm_attr.name} from class {cname} has no value.",
+                        flipped=True
                     )
                 )
             if ub == "1":
@@ -109,6 +111,7 @@ def get_attribute_multiplicity_reqs(mm: MetaModel) -> RequirementStore:
                         f"attribute_mult_ub {cname}::{mm_attr.name}",
                         f"Attribute {mm_attr.name} from class {cname} must have at most one value.",
                         lambda _s, _m, _i: f"Attribute {mm_attr.name} from class {cname} has more than one value.",
+                        flipped=True
                     )
                 )
     return RequirementStore(reqs)
@@ -141,6 +144,7 @@ def get_association_type_reqs(mm: MetaModel) -> RequirementStore:
                     f"association_st_classes {cname}::{mm_assoc.name}",
                     f"Association {mm_assoc.name} from class {cname} must target class {mm_assoc.class_}.",
                     lambda _s, _m, _i: f"Association {mm_assoc.name} from class {cname} has a class different from {mm_assoc.class_}.",
+                    flipped=True
                 )
             )
     return RequirementStore(reqs)
@@ -180,6 +184,7 @@ def get_association_multiplicity_reqs(mm: MetaModel) -> RequirementStore:
                         f"association_mult_lb {cname}::{mm_assoc.name}",
                         f"Association {mm_assoc.name} from class {cname} must have at least one target.",
                         lambda _s, _m, _i: f"Mandatory association {mm_assoc.name} is missing from an element of class {cname}.",
+                        flipped=True
                     )
                 )
             if ub == "1":
@@ -189,6 +194,7 @@ def get_association_multiplicity_reqs(mm: MetaModel) -> RequirementStore:
                         f"association_mult_ub {cname}::{mm_assoc.name}",
                         f"Association {mm_assoc.name} from class {cname} must have at most one target.",
                         lambda _s, _m, _i: f"Association {mm_assoc.name} has more than one target in an element of class {cname}.",
+                        flipped=True
                     )
                 )
     return RequirementStore(reqs)
@@ -213,6 +219,7 @@ def get_inverse_association_reqs(inv_assoc: list[tuple[str, str]]) -> Requiremen
                 f"association_inverse {an1} {an2}",
                 f"Association {an1} must be the inverse of {an2}.",
                 lambda _s, _m, _i: f"Association {an1} is not the inverse of {an2}.",
+                flipped=True
             )
         )
     return RequirementStore(reqs)
@@ -247,8 +254,8 @@ def assert_attribute_rel_constraints(
                 tgt_type_cond = smtsorts.attr_data_sort.is_ss(ad)  # type: ignore
             else:  # mm_attr.type == "GeneratorKind"
                 tgt_type_cond = Or(
-                    ad == smtsorts.attr_data_sort.ss(smtenc.str_symbols["IMAGE"]),  # type: ignore
-                    ad == smtsorts.attr_data_sort.ss(smtenc.str_symbols["SCRIPT"]),  # type: ignore
+                    ad == smtsorts.attr_data_sort.str(smtenc.str_symbols["IMAGE"]),  # type: ignore
+                    ad == smtsorts.attr_data_sort.str(smtenc.str_symbols["SCRIPT"]),  # type: ignore
                 )
             assn = ForAll(
                 [es, ad],
diff --git a/mc_openapi/doml_mc/domlr_parser/__init__.py b/mc_openapi/doml_mc/domlr_parser/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/mc_openapi/doml_mc/domlr_parser/exceptions.py b/mc_openapi/doml_mc/domlr_parser/exceptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..a37ed1f8d1f9c41ebe72a6d86359e16aa18eef0d
--- /dev/null
+++ b/mc_openapi/doml_mc/domlr_parser/exceptions.py
@@ -0,0 +1,20 @@
+class RequirementException(Exception):
+    message: str
+    def __repr__(self) -> str:
+        return self.message
+
+class RequirementMissingKeyException(RequirementException):
+    def __init__(self, key_type: str, key: str, close_matches: list[str], *args: object) -> None:
+        super().__init__(*args)
+        fix_syntax = lambda x: x.replace("_", ".", 1).replace("::", "->")
+        key = fix_syntax(key)
+        close_matches = list(map(fix_syntax, close_matches))
+        self.message = f"Error: no {key_type} found named '{key}'.\n"
+        if close_matches:
+            self.message += "Perhaps you meant...\n"
+            self.message += "".join([f"- '{match}'\n" for match in close_matches])
+
+class RequirementBadSyntaxException(RequirementException):
+    def __init__(self, line: int, col: int, message: str, *args: object) -> None:
+        super().__init__(*args)
+        self.message = f"Syntax Error at Ln {line}, Col {col}:\n{message}"
diff --git a/mc_openapi/doml_mc/domlr_parser/exceptions.yaml b/mc_openapi/doml_mc/domlr_parser/exceptions.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f04cf3429d4ab3fcd5c414ac9d8661a63c4a8454
--- /dev/null
+++ b/mc_openapi/doml_mc/domlr_parser/exceptions.yaml
@@ -0,0 +1,43 @@
+TOKENS:
+  FLIP_EXPR: |
+    a declaration of a requirement.
+      To declare a requirement use:
+      • '+' to declare a requirement
+      • '-' to declare a requirement in negation form, which means
+        that if it's satisfied, then the DOML does not respect the 
+        requirements.
+
+  ESCAPED_STRING: a string. Strings are enclosed by double quotes '"'.
+  BOOL: a boolean value. It can be 'true' or 'false'.
+  NUMBER: a number. It must be an integer.
+  VALUE: a value constant. Values must start with an uppercase letter.
+  CONST: a logic variable. Variables must start with a lowercase letter.
+
+  IS: |
+    a statement such as:
+    • 'is', 'is not' followed by a class or a variable
+    • 'has' followed by an relationship name and then a variable or value
+
+  NOT: a 'not' before an expression or a quantifier.
+  OR: a logical connective such as 'or' between expressions.
+  AND: a logical connective such as 'and' between expressions.
+  IFF: a logical connective such as 'iff' between expressions.
+  IMPLIES: a logical connective such as 'implies' between expressions.
+
+  COMMA: a ',' separating bounded variables after an 'exists'/'forall'
+
+  LPAR: a '(' after which an expression begins.
+  RPAR: a ')' closing a previous '('.
+
+  RELATIONSHIP: |
+    a valid relationship name.
+      Relationships consists of 'package.class->relationship', with no spaces around '.' and '->'.
+
+
+  EXISTS: a 'exists' quantifier. 
+  FORALL: a 'forall' quantifier.
+
+  CLASS_PREFIX: a 'class' followed by a class name
+  ERR_DESC_SYMBOL: a 'error:' to separate the logic expression from the error message.
+HINTS:
+  DOT: If you're trying to use a class, did you put 'class' before the class name?
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/domlr_parser/grammar.lark b/mc_openapi/doml_mc/domlr_parser/grammar.lark
new file mode 100644
index 0000000000000000000000000000000000000000..1e7709a7978063f96999cf99cd7fbe020bfae8a0
--- /dev/null
+++ b/mc_openapi/doml_mc/domlr_parser/grammar.lark
@@ -0,0 +1,72 @@
+requirements    : requirement (requirement)*
+
+requirement     : FLIP_EXPR req_name expression "error:" error_desc
+
+req_name        : ESCAPED_STRING
+error_desc      : ESCAPED_STRING
+
+?expression     : iff_expr
+
+?iff_expr       : (implies_expr "iff")? implies_expr
+
+?implies_expr   : (and_expr "implies")? and_expr
+
+?and_expr       : (or_expr "and")* or_expr
+
+?or_expr        : (not_expr "or")* not_expr
+
+?not_expr       : "not" not_expr -> negation
+                | quantification
+
+?quantification : "exists" bound_consts "(" expression ")" -> exists
+                | "forall" bound_consts "(" expression ")" -> forall
+                | "(" expression ")"
+                | property
+
+?property       : CONST "has" RELATIONSHIP CONST                            -> rel_assoc_expr
+                | CONST "has" RELATIONSHIP COMPARISON_OP value              -> rel_attr_value_expr
+                | CONST "has" RELATIONSHIP COMPARISON_OP CONST RELATIONSHIP -> rel_attr_elem_expr
+                | const_or_class "is" const_or_class                        -> equality
+                | const_or_class "is not" const_or_class                    -> inequality
+
+
+bound_consts    : [CONST ("," CONST)*]
+
+const_or_class  : "class" CLASS
+                | CONST
+
+value           : ESCAPED_STRING
+                | NUMBER
+                | BOOL
+
+FLIP_EXPR       : "+"
+                | "-"
+
+COMPARISON_OP   : ">" | ">="
+                | "<" | "<="
+                | "==" | "!="
+
+BOOL            : ":true"
+                | ":false"
+
+// regex: /[a-zA-Z]+_[a-zA-Z]+::[a-zA-Z]+/
+RELATIONSHIP: /[^\W\d_]+\.[^\W\d_]+\.([^\W\d]|_)+/
+
+CLASS: /[^\W\d_]+\.[^\W\d_]+/
+
+// Const must start with lowercase letter
+CONST: (LCASE_LETTER) ("_"|LETTER|DIGIT)*
+
+// Comment: python/sh style
+COMMENT: /#[^\n]*/
+
+%import common.ESCAPED_STRING
+%import common.NEWLINE
+%import common.LETTER
+%import common.DIGIT
+%import common.NUMBER
+%import common.LCASE_LETTER
+%import common.UCASE_LETTER
+%import common.WS
+%ignore WS
+%ignore COMMENT
diff --git a/mc_openapi/doml_mc/domlr_parser/parser.ipynb b/mc_openapi/doml_mc/domlr_parser/parser.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..2343825b84444eadb1b9a0902abed80dd57f1a64
--- /dev/null
+++ b/mc_openapi/doml_mc/domlr_parser/parser.ipynb
@@ -0,0 +1,350 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Parser Prototype"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from lark import Lark\n",
+    "\n",
+    "with open(\"grammar.lark\") as grammar_file:\n",
+    "    grammar = grammar_file.read()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# vm, iface = get_consts(smtsorts, [\"vm\", \"iface\"])\n",
+    "# return And(\n",
+    "#     smtenc.element_class_fun(vm) == smtenc.classes[\"abstract_VirtualMachine\"],\n",
+    "#     Not(\n",
+    "#         Exists(\n",
+    "#             [iface],\n",
+    "#             ENCODINGS.association_rel(vm, smtenc.associations[\"abstract_ComputingNode::ifaces\"], iface)\n",
+    "#         )\n",
+    "#     )\n",
+    "# )\n",
+    "\n",
+    "expr_to_parse = r\"\"\"\n",
+    "+   \"example requirement to test\"\n",
+    "    # Expr to parse\n",
+    "    not vm is class abstract.VirtualMachine\n",
+    "    and\n",
+    "    vm is not class abstract.Storage\n",
+    "    iff\n",
+    "    not exists iface, apple (\n",
+    "        (vm has abstract.ComputingNode.ifaces iface)\n",
+    "        or\n",
+    "        (vm has abstract.ComputingNode.os Os1)\n",
+    "        and\n",
+    "        (vm has abstract.ComputingNode.memory_mb 1024)\n",
+    "        and\n",
+    "        (vm has abstract.ComputingNode.architecture \"linux\")\n",
+    "        and\n",
+    "        (vm has application.SoftwareComponent.isPersistent !True)\n",
+    "    )\n",
+    "    ---\n",
+    "    \"Virtual Machine {vm} has no iface\"\n",
+    "\n",
+    "+   \"example requirement to test\"\n",
+    "    # Expr to parse\n",
+    "    not vm is class abstract.VirtualMachine\n",
+    "    and\n",
+    "    vm is not class abstract.Storage\n",
+    "    iff\n",
+    "    not exists iface, apple (\n",
+    "        (vm has abstract.ComputingNode.ifaces iface)\n",
+    "        or\n",
+    "        (vm has abstract.ComputingNode.os Os1)\n",
+    "        and\n",
+    "        (\n",
+    "            vm has abstract.ComputingNode.memory_mb Mem\n",
+    "            and\n",
+    "            Mem > 256\n",
+    "        )\n",
+    "    )\n",
+    "    ---\n",
+    "    \"Virtual Machine {vm} has no iface\"\n",
+    "\"\"\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "requirements\n",
+      "  requirement\n",
+      "    +\n",
+      "    req_name\t\"example requirement to test\"\n",
+      "    iff_expr\n",
+      "      and_expr\n",
+      "        negation\n",
+      "          equality\n",
+      "            const_or_class\tvm\n",
+      "            const_or_class\tabstract.VirtualMachine\n",
+      "        inequality\n",
+      "          const_or_class\tvm\n",
+      "          const_or_class\tabstract.Storage\n",
+      "      negation\n",
+      "        exists\n",
+      "          bound_consts\n",
+      "            iface\n",
+      "            apple\n",
+      "          and_expr\n",
+      "            or_expr\n",
+      "              relationship_expr\n",
+      "                vm\n",
+      "                abstract.ComputingNode.ifaces\n",
+      "                iface\n",
+      "              relationship_expr\n",
+      "                vm\n",
+      "                abstract.ComputingNode.os\n",
+      "                value\tOs1\n",
+      "            relationship_expr\n",
+      "              vm\n",
+      "              abstract.ComputingNode.memory_mb\n",
+      "              value\t1024\n",
+      "            relationship_expr\n",
+      "              vm\n",
+      "              abstract.ComputingNode.architecture\n",
+      "              value\t\"linux\"\n",
+      "            relationship_expr\n",
+      "              vm\n",
+      "              application.SoftwareComponent.isPersistent\n",
+      "              value\t!True\n",
+      "    ---\n",
+      "    error_desc\t\"Virtual Machine {vm} has no iface\"\n",
+      "  requirement\n",
+      "    +\n",
+      "    req_name\t\"example requirement to test\"\n",
+      "    iff_expr\n",
+      "      and_expr\n",
+      "        negation\n",
+      "          equality\n",
+      "            const_or_class\tvm\n",
+      "            const_or_class\tabstract.VirtualMachine\n",
+      "        inequality\n",
+      "          const_or_class\tvm\n",
+      "          const_or_class\tabstract.Storage\n",
+      "      negation\n",
+      "        exists\n",
+      "          bound_consts\n",
+      "            iface\n",
+      "            apple\n",
+      "          and_expr\n",
+      "            or_expr\n",
+      "              relationship_expr\n",
+      "                vm\n",
+      "                abstract.ComputingNode.ifaces\n",
+      "                iface\n",
+      "              relationship_expr\n",
+      "                vm\n",
+      "                abstract.ComputingNode.os\n",
+      "                value\tOs1\n",
+      "            and_expr\n",
+      "              relationship_expr\n",
+      "                vm\n",
+      "                abstract.ComputingNode.memory_mb\n",
+      "                value\tMem\n",
+      "              comparison\n",
+      "                value\tMem\n",
+      "                >\n",
+      "                value\t256\n",
+      "    ---\n",
+      "    error_desc\t\"Virtual Machine {vm} has no iface\"\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "parser = Lark(grammar, start=\"requirements\")\n",
+    "tree = parser.parse(expr_to_parse)\n",
+    "\n",
+    "print(tree.pretty())"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We need the `ModelChecker` to import `SMTEncodings` and `SMTSorts` in order to create our Z3 constants programmatically.\n",
+    "\n",
+    "Now the model checker should expose the *intermediate model checker* which should provide us with those two collections."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from mc_openapi.doml_mc import ModelChecker, DOMLVersion\n",
+    "from mc_openapi.doml_mc.imc import IntermediateModelChecker\n",
+    "\n",
+    "# Import DOMLX as bytes\n",
+    "doml_document_path = \"../../../tests/doml/faas.domlx\"\n",
+    "with open(doml_document_path, \"rb\") as xmif:\n",
+    "    doml_xmi = xmif.read()\n",
+    "\n",
+    "model_checker = ModelChecker(doml_xmi, DOMLVersion.V2_0)\n",
+    "\n",
+    "intermediate_model_checker = IntermediateModelChecker(\n",
+    "    model_checker.metamodel,\n",
+    "    model_checker.inv_assoc,\n",
+    "    model_checker.intermediate_model\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The parser will now produce a Z3 expression to evaluate."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[Requirement(assert_callable=<function DSLTransformer.iff_expr.<locals>.<lambda> at 0x7fe654129900>,\n",
+      "             assert_name='example_requirement_to_test',\n",
+      "             description='example requirement to test',\n",
+      "             error_description=<function DSLTransformer.requirement.<locals>.<lambda> at 0x7fe6541295a0>,\n",
+      "             flipped=False),\n",
+      " Requirement(assert_callable=<function DSLTransformer.iff_expr.<locals>.<lambda> at 0x7fe65412ad40>,\n",
+      "             assert_name='example_requirement_to_test',\n",
+      "             description='example requirement to test',\n",
+      "             error_description=<function DSLTransformer.requirement.<locals>.<lambda> at 0x7fe65412aef0>,\n",
+      "             flipped=False)]\n"
+     ]
+    }
+   ],
+   "source": [
+    "from pprint import pprint\n",
+    "from z3 import Not, And, Or, Xor, Implies, Exists, ForAll\n",
+    "\n",
+    "from mc_openapi.doml_mc.dsl_parser.parser import Parser\n",
+    "\n",
+    "parser = Parser(grammar)\n",
+    "\n",
+    "reqs_store, user_value_strings = parser.parse(expr_to_parse)\n",
+    "\n",
+    "pprint(reqs_store.get_all_requirements())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "intermediate_model_checker.instantiate_solver(user_value_strings)\n",
+    "ENCODINGS =  intermediate_model_checker.smt_encoding\n",
+    "SORTS = intermediate_model_checker.smt_sorts\n",
+    "\n",
+    "assert ENCODINGS and SORTS"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "And(Not(elem_class(vm) == infrastructure_VirtualMachine),\n",
+      "    elem_class(vm) != infrastructure_Storage) ==\n",
+      "Not(Exists([iface, apple],\n",
+      "           And(Or(association(vm,\n",
+      "                              infrastructure_ComputingNode::ifaces,\n",
+      "                              iface),\n",
+      "                  attribute(vm,\n",
+      "                            infrastructure_ComputingNode::os,\n",
+      "                            Os1)),\n",
+      "               attribute(vm,\n",
+      "                         infrastructure_ComputingNode::memory_mb,\n",
+      "                         int(1024)),\n",
+      "               attribute(vm,\n",
+      "                         infrastructure_ComputingNode::architecture,\n",
+      "                         str(ss_50__linux_)),\n",
+      "               attribute(vm,\n",
+      "                         application_SoftwareComponent::isPersistent,\n",
+      "                         bool(True)))))\n",
+      "And(Not(elem_class(vm) == infrastructure_VirtualMachine),\n",
+      "    elem_class(vm) != infrastructure_Storage) ==\n",
+      "Not(Exists([iface, apple],\n",
+      "           And(Or(association(vm,\n",
+      "                              infrastructure_ComputingNode::ifaces,\n",
+      "                              iface),\n",
+      "                  attribute(vm,\n",
+      "                            infrastructure_ComputingNode::os,\n",
+      "                            Os1)),\n",
+      "               And(attribute(vm,\n",
+      "                             infrastructure_ComputingNode::memory_mb,\n",
+      "                             Mem),\n",
+      "                   get_int(Mem) > get_int(int(256))))))\n"
+     ]
+    }
+   ],
+   "source": [
+    "for req in reqs_store.get_all_requirements():\n",
+    "    print(req.assert_callable(ENCODINGS, SORTS))"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3.10.7 ('.venv': poetry)",
+   "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.10.7"
+  },
+  "orig_nbformat": 4,
+  "vscode": {
+   "interpreter": {
+    "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16"
+   }
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/mc_openapi/doml_mc/domlr_parser/parser.py b/mc_openapi/doml_mc/domlr_parser/parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..c2f751a5470835ba679b479a2fc6f81efa6a3492
--- /dev/null
+++ b/mc_openapi/doml_mc/domlr_parser/parser.py
@@ -0,0 +1,615 @@
+import os
+import re
+from typing import Callable
+
+import yaml
+from lark import Lark, Transformer, UnexpectedCharacters, UnexpectedEOF
+from mc_openapi.doml_mc.domlr_parser.exceptions import RequirementBadSyntaxException
+from mc_openapi.doml_mc.domlr_parser.utils import (RefHandler, StringValuesCache, SynthesisRefHandler,
+                                                 VarStore)
+from mc_openapi.doml_mc.error_desc_helper import get_user_friendly_name
+from mc_openapi.doml_mc.imc import (Requirement, RequirementStore, SMTEncoding,
+                                    SMTSorts)
+from mc_openapi.doml_mc.intermediate_model import IntermediateModel
+from z3 import And, Exists, ExprRef, ForAll, Implies, Not, Or, Solver, Xor, simplify
+from doml_synthesis import State
+
+class ParserData:
+    def __init__(self) -> None:
+        # TODO: Replace with files api?
+        grammar_path = os.path.join(os.path.dirname(__file__), "grammar.lark")
+        exceptions_path = os.path.join(os.path.dirname(__file__), "exceptions.yaml")
+        with open(grammar_path, "r") as grammar:
+            self.grammar = grammar.read()
+        with open(exceptions_path, "r") as exceptions:
+            self.exceptions = yaml.safe_load(exceptions)
+
+PARSER_DATA = ParserData()
+
+class Parser:
+    def __init__(self, transformer, grammar: str = PARSER_DATA.grammar):
+        self.parser = Lark(grammar, start="requirements", parser="lalr")
+        self.transformer = transformer
+
+    def parse(self, input: str, for_synthesis: bool = False):
+        """Parse the input string containing the DOMLR requirements and
+           returns a tuple with:
+           - RequirementStore with the parsed requirements inside
+           - A list of strings to be added to the string constant EnumSort
+        """
+        try:
+            self.tree = self.parser.parse(input)
+
+            const_store = VarStore()
+            user_values_cache = StringValuesCache()
+
+            transformer = self.transformer(const_store, user_values_cache)
+
+            if not for_synthesis:
+                return (
+                    RequirementStore(transformer.transform(self.tree)), 
+                    user_values_cache.get_list()
+                )
+            else:
+                reqs = transformer.transform(self.tree)
+
+                # This function has to return state or it will break the
+                # synthesis solver
+                def user_reqs(state: State):
+                    for (req, id, negated) in reqs:
+                        state.solver.assert_and_track(
+                            req(state) if not negated else Not(req(state)), f'Requirement {id}')
+                    return state
+
+                return user_reqs, user_values_cache.get_list()
+
+        except UnexpectedEOF as e:
+            msg =  "Unexpected End of File:\n"
+            msg += "Did you forget the `error:` message at the end of a requirement?"
+            raise Exception(msg)
+
+        except UnexpectedCharacters as e:
+            msg = _get_error_desc_for_unexpected_characters(e, input)
+            raise RequirementBadSyntaxException(e.line, e.column, msg)
+       
+        
+
+class DOMLRTransformer(Transformer):
+    # These callbacks will be called when a rule with the same name
+    # is matched. It starts from the leaves.
+    def __init__(self, 
+        const_store: VarStore, 
+        user_values_cache: StringValuesCache,
+        visit_tokens: bool = True
+    ) -> None:
+        super().__init__(visit_tokens)
+        self.const_store = const_store
+        self.user_values_cache = user_values_cache
+
+    def __default__(self, data, children, meta):
+        return children
+
+    # start
+    def requirements(self, args) -> list[Requirement]:
+        return args
+
+    def requirement(self, args) -> Requirement:
+        flip_expr: bool = args[0].value == "-"
+        name: str = args[1]
+        expr: Callable[[SMTEncoding, SMTSorts], ExprRef] = args[2]
+        errd: Callable[[Solver, SMTSorts, IntermediateModel, int], str] = args[3]
+        index = self.const_store.get_index_and_push()
+        return Requirement(
+            expr,
+            name.lower().replace(" ", "_"),
+            name,
+            lambda solver, sorts, model: errd(
+                solver, sorts, model, 
+                index, 
+                name
+            ),
+            flipped=flip_expr
+        )
+
+    def req_name(self, args) -> str:
+        return str(args[0].value.replace('"', ''))
+
+    # Requirement requirement expression
+
+    def bound_consts(self, args):
+        const_names = list(map(lambda arg: arg.value, args))
+        for name in const_names:
+            self.const_store.use(name)
+            self.const_store.quantify(name)
+        return lambda _, sorts: RefHandler.get_consts(const_names, sorts)
+
+    def negation(self, args):
+        return lambda enc, sorts: Not(args[0](enc, sorts))
+
+    def iff_expr(self, args):
+        return lambda enc, sorts: args[0](enc, sorts) == args[1](enc, sorts)
+    
+    def implies_expr(self, args):
+        return lambda enc, sorts: Implies(args[0](enc, sorts), args[1](enc, sorts))
+
+    def and_expr(self, args):
+        return lambda enc, sorts: And([arg(enc, sorts) for arg in args])
+
+    def or_expr(self, args):
+        return lambda enc, sorts: Or([arg(enc, sorts) for arg in args])
+
+    def exists(self, args):
+        return lambda enc, sorts: Exists(args[0](enc, sorts), args[1](enc, sorts))
+
+    def forall(self, args):
+        return lambda enc, sorts: ForAll(args[0](enc, sorts), args[1](enc, sorts))
+
+    def rel_assoc_expr(self, args):
+        """An ASSOCIATION relationship"""
+        rel_name = args[1].value
+        self.const_store.use(args[0].value)
+        self.const_store.use(args[2].value)
+
+        def _gen_rel_elem_expr(enc: SMTEncoding, sorts: SMTSorts):
+            rel, rel_type = RefHandler.get_relationship(enc, rel_name)
+
+            assert rel_type == RefHandler.ASSOCIATION
+
+            return RefHandler.get_association_rel(
+                enc,
+                RefHandler.get_const(args[0].value, sorts),
+                rel,
+                RefHandler.get_const(args[2].value, sorts)
+            )
+        return _gen_rel_elem_expr
+
+    def rel_attr_value_expr(self, args):
+        """An ATTRIBUTE relationship with a rhs that is a value"""
+
+        rel_name = args[1].value
+        def _gen_rel_attr_value_expr(enc: SMTEncoding, sorts: SMTSorts):
+            elem = RefHandler.get_const(args[0].value, sorts)
+            rel, rel_type = RefHandler.get_relationship(enc, rel_name)
+            assert rel_type == RefHandler.ATTRIBUTE
+
+            rhs_value, rhs_value_type = args[3]
+            rhs_value = rhs_value(enc, sorts)
+            op = args[2].value
+
+            if rhs_value_type == RefHandler.INTEGER:
+
+                lhs_value = RefHandler.get_value("x", sorts)
+
+                return And(
+                    RefHandler.get_attribute_rel(enc, 
+                        elem,
+                        rel,
+                        lhs_value
+                    ),
+                    self.compare_int(sorts, op, lhs_value, rhs_value)
+                )
+            elif rhs_value_type == RefHandler.STRING or rhs_value_type == RefHandler.BOOLEAN:
+                expr = RefHandler.get_attribute_rel(enc,
+                    elem,
+                    rel,
+                    rhs_value
+                )
+                if op == "==":
+                    return expr
+                elif op == "!=":
+                    return Not(expr)
+                else:
+                    raise f'Invalid compare operator "{op}". It must be "==" or "!=".'
+            
+
+        return _gen_rel_attr_value_expr
+
+    def rel_attr_elem_expr(self, args):
+        """An ATTRIBUTE relationship with a rhs that is another element"""
+
+        rel1_name = args[1].value
+        rel2_name = args[4].value
+        op = args[2].value
+
+        def _gen_rel_attr_elem_expr(enc: SMTEncoding, sorts: SMTSorts):
+            elem1 = RefHandler.get_const(args[0].value, sorts)
+            elem2 = RefHandler.get_const(args[3].value, sorts)
+            rel1, rel1_type = RefHandler.get_relationship(enc, rel1_name)
+            rel2, rel2_type = RefHandler.get_relationship(enc, rel2_name)
+
+            assert rel1_type == RefHandler.ATTRIBUTE
+            assert rel2_type == RefHandler.ATTRIBUTE
+
+            rhs_value = RefHandler.get_value("x", sorts)
+
+            expr = And(
+                RefHandler.get_attribute_rel(enc,
+                    elem1,
+                    rel1,
+                    rhs_value
+                ),
+                RefHandler.get_attribute_rel(enc,
+                    elem2,
+                    rel2,
+                    rhs_value
+                )
+            )
+            if op == "==":
+                return expr
+            elif op == "!=":
+                return Not(expr)
+            else:
+                rhs1_value = RefHandler.get_value("rhs1", sorts)
+                rhs2_value = RefHandler.get_value("rhs2", sorts)
+                expr = And(
+                    RefHandler.get_attribute_rel(enc,
+                        elem1,
+                        rel1,
+                        rhs1_value
+                    ),
+                    RefHandler.get_attribute_rel(enc,
+                        elem2,
+                        rel2,
+                        rhs2_value
+                    ),
+                    self.compare_int(sorts, op, rhs1_value, rhs2_value)
+                )
+                print(
+                    "Warning: Comparing attributes of two elements with {op} is experimental!\n",
+                    "Assumption: the attribute is an Integer."
+                )
+                return expr            
+
+        return _gen_rel_attr_elem_expr
+
+    def _get_equality_sides(self, arg1, arg2):
+        # We track use of const in const_or_class
+        if arg1.type == "CONST" and arg2.type == "CONST":
+            return (
+                lambda _, sorts: RefHandler.get_const(arg1.value, sorts),
+                lambda _, sorts: RefHandler.get_const(arg2.value, sorts)
+            )
+
+        if arg1.type == "CLASS":
+            arg1_ret = lambda enc, _: RefHandler.get_class(enc, arg1.value)
+        else:
+            arg1_ret = lambda enc, sorts: RefHandler.get_element_class(enc, RefHandler.get_const(arg1.value, sorts))
+
+        if arg2.type == "CLASS":
+            arg2_ret = lambda enc, _: RefHandler.get_class(enc, arg2.value)
+        else:
+            arg2_ret = lambda enc, sorts: RefHandler.get_element_class(enc, RefHandler.get_const(arg2.value, sorts))
+
+        return (arg1_ret, arg2_ret)
+
+    def equality(self, args):
+        a, b = self._get_equality_sides(args[0], args[1])
+        return lambda enc, sorts: a(enc, sorts) == b(enc, sorts)
+
+    def inequality(self, args):
+        a, b = self._get_equality_sides(args[0], args[1])
+        return lambda enc, sorts: a(enc, sorts) != b(enc, sorts)
+
+    def const_or_class(self, args):
+        if args[0].type == "CONST":
+            self.const_store.use(args[0].value)
+        return args[0]
+    
+    def compare_int(self, sorts: SMTSorts, op: str, a, b):
+        # To extract the `int` contained in the attr_data_sort,
+        # we need to call its `get_int` method on the `DatatypeRef`
+        get_int = sorts.attr_data_sort.get_int
+
+        a = get_int(a)
+        b = get_int(b)
+
+        if op == ">":
+            return a > b
+        if op == ">=":
+            return a >= b
+        if op == "<":
+            return a < b
+        if op == "<=":
+            return a <= b
+        if op == "==":
+            return a == b
+        if op == "!=":
+            return a != b
+        raise f"Invalid Compare Operator Symbol: {op}"
+
+
+    def value(self, args):  
+        type = args[0].type
+        value = args[0].value
+
+        if type == "ESCAPED_STRING":
+            value = value.replace('"', '')
+            self.user_values_cache.add(value)
+            return lambda enc, sorts: RefHandler.get_str(value, enc, sorts), RefHandler.STRING
+        elif type == "NUMBER":
+            return lambda _, sorts: RefHandler.get_int(value, sorts), RefHandler.INTEGER
+        elif type == "BOOL":
+            return lambda _, sorts: RefHandler.get_bool(value, sorts), RefHandler.BOOLEAN
+        # elif type == "VALUE":
+        #     return lambda _, sorts: RefHandler.get_value(value, sorts), RefHandler.VALUE_REF
+
+    def error_desc(self, args):
+        def err_callback(
+            solver: Solver,
+            sorts: SMTSorts,
+            intermediate_model: IntermediateModel,
+            index: int,
+            requirement_desc: str
+        ) -> str:
+            msg: str = f"[Requirement \"{requirement_desc}\"]"
+            msg += "\n\t" + args[0].value.replace('"', '')
+            # Get list of free variables
+            consts_name = self.const_store.get_free_vars(index)
+            consts = RefHandler.get_consts(consts_name, sorts)
+            notes = ""
+            try:
+                model = solver.model()
+                for const in consts:
+                    name = get_user_friendly_name(intermediate_model, model, const)
+                    msg = msg.replace("{" + str(const) + "}", f"'{name}'")
+            except:
+                notes += "\n\t- model not found: it's not possible to show which element is causing the issue"
+
+            # tell the user which variables are not free
+            unused_free_vars = re.findall(r"{[^{}]*}", msg)
+            if unused_free_vars:
+                notes += "\n\t- The following variables are not free and should be removed from the error description:"
+                notes += "\n\t" + " ".join(unused_free_vars)
+
+            return msg + ("\n\n\tNOTES:" + notes if notes else "")
+        return err_callback
+
+class SynthesisDOMLRTransformer(Transformer):
+    # These callbacks will be called when a rule with the same name
+    # is matched. It starts from the leaves.
+    def __init__(self, 
+        const_store: VarStore, 
+        user_values_cache: StringValuesCache,
+        visit_tokens: bool = True
+    ) -> None:
+        super().__init__(visit_tokens)
+        self.const_store = const_store
+        self.user_values_cache = user_values_cache
+
+    def __default__(self, data, children, meta):
+        return children
+
+    # start
+    def requirements(self, args) -> list[tuple]:
+        return args
+
+    def requirement(self, args) -> tuple:
+        flip_expr: bool = args[0].value == "-"
+        name: str = args[1]
+        expr: Callable[[State], ExprRef] = args[2]
+        return (
+            expr,
+            name.lower().replace(" ", "_"), # id
+            flip_expr
+        )
+
+    def req_name(self, args) -> str:
+        return str(args[0].value.replace('"', ''))
+
+    # Requirement requirement expression
+
+    def bound_consts(self, args):
+        const_names = list(map(lambda arg: arg.value, args))
+        for name in const_names:
+            self.const_store.use(name)
+            self.const_store.quantify(name)
+        return lambda state: SynthesisRefHandler.get_consts(const_names, state)
+
+    def negation(self, args):
+        return lambda state: Not(args[0](state))
+
+    def iff_expr(self, args):
+        return lambda state: args[0](state) == args[1](state)
+    
+    def implies_expr(self, args):
+        return lambda state: Implies(args[0](state), args[1](state))
+
+    def and_expr(self, args):
+        return lambda state: And([arg(state) for arg in args])
+
+    def or_expr(self, args):
+        return lambda state: Or([arg(state) for arg in args])
+
+    def exists(self, args):
+        return lambda state: Exists(args[0](state), args[1](state))
+
+    def forall(self, args):
+        return lambda state: ForAll(args[0](state), args[1](state))
+
+    def rel_assoc_expr(self, args):
+        """An ASSOCIATION relationship"""
+        rel_name = args[1].value
+        self.const_store.use(args[0].value)
+        self.const_store.use(args[2].value)
+
+        def _gen_rel_elem_expr(state: State):
+            rel = SynthesisRefHandler.get_assoc(state, rel_name)
+
+            return state.rels.AssocRel(
+                SynthesisRefHandler.get_const(args[0].value, state),
+                rel.ref,
+                SynthesisRefHandler.get_const(args[2].value, state)
+            )
+        return _gen_rel_elem_expr
+
+    def rel_attr_value_expr(self, args):
+        """An ATTRIBUTE relationship with a rhs that is a value
+        
+           CONST "has" RELATIONSHIP COMPARISON_OP value
+           0           1            2             3
+        """
+
+        rel_name = args[1].value
+        def _gen_rel_attr_value_expr(state: State):
+            elem = SynthesisRefHandler.get_const(args[0].value, state)
+            rel = SynthesisRefHandler.get_attr(state, rel_name)
+
+            rhs_value, rhs_value_type = args[3]
+            rhs_value = rhs_value(state)
+            op = args[2].value
+
+            if rhs_value_type == SynthesisRefHandler.INTEGER and rel.type == 'Integer':
+                lhs_value = state.rels.int.AttrValueRel(elem, rel.ref)
+                return And(
+                    self.compare(op, lhs_value, rhs_value),
+                    state.rels.int.AttrSynthRel(elem, rel.ref)
+                )
+            elif op != "==" and op != "!=":
+                raise "You can only use == and != to compare Strings and Booleans!"
+            elif rhs_value_type == SynthesisRefHandler.STRING:
+                lhs_value = state.rels.str.AttrValueRel(elem, rel.ref) 
+                
+                return And(
+                    lhs_value == rhs_value if op == "==" else lhs_value != rhs_value,
+                    state.rels.str.AttrSynthRel(elem, rel.ref)
+                )
+            elif rhs_value_type == SynthesisRefHandler.BOOLEAN:
+                lhs_value = state.rels.bool.AttrValueRel(elem, rel.ref)  
+                return And(
+                    lhs_value == rhs_value if op == "==" else lhs_value != rhs_value,
+                    state.rels.bool.AttrSynthRel(elem, rel.ref)
+                )
+            else:
+                raise f'Invalid value {rhs_value} during parsing for synthesis.'
+            
+
+        return _gen_rel_attr_value_expr
+
+    def rel_attr_elem_expr(self, args):
+        """An ATTRIBUTE relationship with a rhs that is another element
+           CONST "has" RELATIONSHIP COMPARISON_OP CONST RELATIONSHIP
+           0           1            2             3     4
+        """
+
+        rel1_name = args[1].value
+        rel2_name = args[4].value
+        op = args[2].value
+
+        def _gen_rel_attr_elem_expr(state: State):
+            elem1 = SynthesisRefHandler.get_const(args[0].value, state)
+            elem2 = SynthesisRefHandler.get_const(args[3].value, state)
+            rel1 = SynthesisRefHandler.get_attr(state, rel1_name)
+            rel2 = SynthesisRefHandler.get_attr(state, rel2_name)
+
+            if rel1.type == rel2.type == 'Integer':
+                return And(
+                    state.rels.int.AttrSynthRel(elem1, rel1.ref),
+                    state.rels.int.AttrSynthRel(elem2, rel2.ref),
+                    self.compare(
+                        op, 
+                        state.rels.int.AttrValueRel(elem1, rel1.ref), 
+                        state.rels.int.AttrValueRel(elem2, rel2.ref)
+                    )
+                )
+            if rel1.type == rel2.type == 'Boolean':
+                return And(
+                    state.rels.bool.AttrSynthRel(elem1, rel1.ref),
+                    state.rels.bool.AttrSynthRel(elem2, rel2.ref),
+                    self.compare(
+                        op, 
+                        state.rels.bool.AttrValueRel(elem1, rel1.ref), 
+                        state.rels.bool.AttrValueRel(elem2, rel2.ref)
+                    )
+                )
+            if rel1.type == rel2.type == 'String':
+                return And(
+                    state.rels.str.AttrSynthRel(elem1, rel1.ref),
+                    state.rels.str.AttrSynthRel(elem2, rel2.ref),
+                    self.compare(
+                        op, 
+                        state.rels.str.AttrValueRel(elem1, rel1.ref), 
+                        state.rels.str.AttrValueRel(elem2, rel2.ref)
+                    )
+                )
+            raise f'Attribute relationships {rel1_name} ({rel1.type}) and {rel2_name} ({rel2.type}) have mismatch type.'
+
+        return _gen_rel_attr_elem_expr
+
+    def _get_equality_sides(self, arg1, arg2):
+        # We track use of const in const_or_class
+        if arg1.type == "CONST" and arg2.type == "CONST":
+            return (
+                lambda state: SynthesisRefHandler.get_const(arg1.value, state),
+                lambda state: SynthesisRefHandler.get_const(arg2.value, state)
+            )
+
+        if arg1.type == "CLASS":
+            arg1_ret = lambda state: SynthesisRefHandler.get_class(state, arg1.value)
+        else:
+            arg1_ret = lambda state: SynthesisRefHandler.get_element_class(state, SynthesisRefHandler.get_const(arg1.value, state))
+
+        if arg2.type == "CLASS":
+            arg2_ret = lambda state: SynthesisRefHandler.get_class(state, arg2.value)
+        else:
+            arg2_ret = lambda state: SynthesisRefHandler.get_element_class(state, SynthesisRefHandler.get_const(arg2.value, state))
+
+        return (arg1_ret, arg2_ret)
+
+    def equality(self, args):
+        a, b = self._get_equality_sides(args[0], args[1])
+        return lambda state: a(state) == b(state)
+
+    def inequality(self, args):
+        a, b = self._get_equality_sides(args[0], args[1])
+        return lambda state: a(state) != b(state)
+
+    def const_or_class(self, args):
+        if args[0].type == "CONST":
+            self.const_store.use(args[0].value)
+        return args[0]
+    
+    def compare(self, op: str, a, b):
+
+        if op == ">":
+            return a > b
+        if op == ">=":
+            return a >= b
+        if op == "<":
+            return a < b
+        if op == "<=":
+            return a <= b
+        if op == "==":
+            return a == b
+        if op == "!=":
+            return a != b
+        raise f"Invalid Compare Operator Symbol: {op}"
+
+
+    def value(self, args):  
+        type = args[0].type
+        value = args[0].value
+
+        if type == "ESCAPED_STRING":
+            value = value.replace('"', '')
+            self.user_values_cache.add(value)
+            return lambda state: SynthesisRefHandler.get_str(value, state), SynthesisRefHandler.STRING
+        elif type == "NUMBER":
+            return lambda _: value, SynthesisRefHandler.INTEGER
+        elif type == "BOOL":
+            return lambda _: SynthesisRefHandler.get_bool(value), SynthesisRefHandler.BOOLEAN 
+
+def _get_error_desc_for_unexpected_characters(e: UnexpectedCharacters, input: str):
+    # Error description
+    msg = "Syntax Error:\n\n"
+    msg += e.get_context(input)
+    msg += "Expected one of the following:\n"
+    for val in e.allowed:
+        val = PARSER_DATA.exceptions["TOKENS"].get(val, "")
+        msg += (f"• {val}\n")
+    # Suggestion that might be useful
+    if e.char == ".":
+        msg += "HINTS:\n"
+        msg += PARSER_DATA.exceptions["HINTS"]["DOT"]
+    # Print line highlighting the error
+
+    return msg
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/domlr_parser/utils.py b/mc_openapi/doml_mc/domlr_parser/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..b52a2ae01a01ce7472fb18276a0f4fb0b0c6ab57
--- /dev/null
+++ b/mc_openapi/doml_mc/domlr_parser/utils.py
@@ -0,0 +1,166 @@
+from difflib import get_close_matches
+
+from mc_openapi.doml_mc.domlr_parser.exceptions import \
+    RequirementMissingKeyException
+from mc_openapi.doml_mc.imc import SMTEncoding, SMTSorts
+from z3 import Const, DatatypeRef, ExprRef, FuncDeclRef, SortRef, Ints, And
+from doml_synthesis import State, AssocRel, AttrRel
+
+class StringValuesCache:
+    def __init__(self) -> None:
+        self.values: set[str] = set()
+
+    def add(self, value: str):
+        self.values.add(value)
+    
+    def get_list(self):
+        return list(self.values)
+
+class VarStore:
+    """This class provides a way to instance a Z3 variable only the first time
+       it's called, and subsequent uses of that variable simply retrieve it
+       from the store.
+    """
+
+    def __init__(self):
+        self.expressions: list[dict[str, bool]] = []
+        self.curr_vars: dict[str, bool] = dict()
+        self.curr_index: int = 0
+
+    def use(self, name: str):
+        self.curr_vars[name] = self.curr_vars.get(name, False)
+
+    def quantify(self, name: str):
+        self.curr_vars[name] = True
+    
+    def get_index_and_push(self):
+        self.expressions.append(self.curr_vars)
+        self.curr_vars = dict()
+
+        self.curr_index += 1
+        return self.curr_index - 1
+
+    def get_free_vars(self, index: int) -> list[ExprRef]:
+        vars = self.expressions[index]
+        if not vars: 
+            return []
+        free_vars = [key for key, val in vars.items() if not val]
+        return free_vars
+
+
+class RefHandler:
+    """A utility class that provides simplified ways to create Z3 Refs.
+    """
+
+    def get_consts(names: list[str], sorts: SMTSorts):
+        return [Const(name, sorts.element_sort) for name in names]
+
+    def get_const(name: str, sorts: SMTSorts):
+        return Const(name, sorts.element_sort)
+
+    def get_value(name: str, sorts: SMTSorts):
+        return Const(name, sorts.attr_data_sort)
+
+    def get_int(value: str, sorts: SMTSorts):
+        return sorts.attr_data_sort.int(int(value))
+
+    def get_bool(value: str, sorts: SMTSorts):
+        return sorts.attr_data_sort.bool(value == "!True")
+
+    def get_str(value: str, enc: SMTEncoding, sorts: SMTSorts):
+        return sorts.attr_data_sort.str(enc.str_symbols[value])
+
+    def get_element_class(enc: SMTEncoding, const: ExprRef) -> FuncDeclRef:
+        return enc.element_class_fun(const)
+
+    def get_class(enc: SMTEncoding, class_name: str) -> DatatypeRef:
+        class_name = _convert_rel_str(class_name)
+        _class = enc.classes.get(class_name, None)
+        if _class is not None:
+            return _class
+        else:
+            close_matches = get_close_matches(class_name, enc.classes.keys())
+            raise RequirementMissingKeyException("class", class_name, close_matches)
+
+    ASSOCIATION = 0
+    ATTRIBUTE = 1
+
+    INTEGER = 2
+    BOOLEAN = 3
+    STRING = 4
+
+    def get_relationship(enc: SMTEncoding, rel_name: str) -> tuple[DatatypeRef, int]:
+        rel_name = _convert_rel_str(rel_name)
+        rel = enc.associations.get(rel_name, None)
+        if rel is not None:
+            return rel, RefHandler.ASSOCIATION
+        else:
+            rel = enc.attributes.get(rel_name, None)
+            if rel is not None:
+                return rel, RefHandler.ATTRIBUTE
+            else:
+                close_matches = get_close_matches(rel_name, list(enc.associations.keys()) + list(enc.attributes.keys()))
+                raise RequirementMissingKeyException("relationship", rel_name, close_matches)
+
+    def get_association_rel(enc: SMTEncoding, a: ExprRef, rel: DatatypeRef, b: ExprRef) -> DatatypeRef:
+        return enc.association_rel(a, rel, b)
+
+    def get_attribute_rel(enc: SMTEncoding, a: ExprRef, rel: DatatypeRef, b: ExprRef) -> DatatypeRef:
+        return enc.attribute_rel(a, rel, b)
+
+class SynthesisRefHandler:
+    """A utility class that provides simplified ways to create Z3 Refs.
+    To be used when parsing requirements for synthesis
+    """
+
+    INTEGER = 2
+    BOOLEAN = 3
+    STRING = 4
+
+    def get_consts(names: list[str], state: State):
+        return [Const(name, state.sorts.Elem) for name in names]
+
+    def get_const(name: str, state: State):
+        return Const(name, state.sorts.Elem)
+
+    def get_bool(value: str):
+        return value == "!True"
+
+    def get_str(value: str, state: State):
+        return state.data.Strings[value]
+
+    def get_element_class(state: State, const: ExprRef) -> FuncDeclRef:
+        return state.rels.ElemClass(const)
+
+    def get_class(state: State, class_name: str) -> DatatypeRef:
+        class_name = _convert_rel_str(class_name)
+        _class = state.data.Classes.get(class_name, None)
+        if _class is not None:
+            return _class.ref
+        else:
+            close_matches = get_close_matches(class_name, state.data.Classes.keys())
+            raise RequirementMissingKeyException("class", class_name, close_matches)
+
+    def get_assoc(state: State, rel_name: str) -> AssocRel:
+        rel_name = _convert_rel_str(rel_name)
+        rel = state.data.Assocs.get(rel_name, None)
+        if rel is not None:
+            return rel
+        else: 
+            raise f"Association {rel_name} not present in the metamodel!"
+
+    def get_attr(state: State, rel_name: str) -> AttrRel:
+            rel_name = _convert_rel_str(rel_name)
+            rel = state.data.Attrs.get(rel_name, None)
+            if rel is not None:
+                return rel
+            else: 
+                raise f"Attribute {rel_name} not present in the metamodel!"
+
+def _convert_rel_str(rel: str) -> str:
+    tokens = rel.replace("abstract", "infrastructure").split(".") 
+    if len(tokens) == 2:
+        return tokens[0] + "_" + tokens[1]
+    if len(tokens) == 3:
+        return tokens[0] + "_" + tokens[1] + "::" + tokens[2]
+    raise f"Bad relationship name: {rel}"
diff --git a/mc_openapi/doml_mc/error_desc_helper.py b/mc_openapi/doml_mc/error_desc_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..abf13dd44346a26b4469b2840480ea8f603affa7
--- /dev/null
+++ b/mc_openapi/doml_mc/error_desc_helper.py
@@ -0,0 +1,15 @@
+from z3 import ExprRef, ModelRef
+from typing import Optional
+from mc_openapi.doml_mc.intermediate_model import IntermediateModel
+
+def get_user_friendly_name(
+    intermediate_model: IntermediateModel,
+    model: ModelRef,
+    const: ExprRef
+) -> Optional[str]:
+    z3_elem = model[const]
+    if z3_elem is not None:
+        im_elem = intermediate_model.get(str(z3_elem))
+        if im_elem is not None:
+            return im_elem.user_friendly_name
+    return None
diff --git a/mc_openapi/doml_mc/imc.py b/mc_openapi/doml_mc/imc.py
index fb3ca02f46f7b0099d07fc62d5fea19709ef8bc0..09f4d6a40d6e85d80dc21787b391766d6cc49ef0 100644
--- a/mc_openapi/doml_mc/imc.py
+++ b/mc_openapi/doml_mc/imc.py
@@ -1,26 +1,21 @@
 from collections.abc import Callable
 from dataclasses import dataclass
 
-from z3 import (
-    Context, FuncDeclRef, Solver, ExprRef, SortRef, DatatypeSortRef, sat
-)
+from z3 import (Context, DatatypeSortRef, ExprRef, FuncDeclRef, Solver,
+                SortRef, sat)
 
 from .intermediate_model.doml_element import IntermediateModel
-from .z3encoding.im_encoding import (
-    assert_im_associations_q, assert_im_attributes,
-    def_elem_class_f_and_assert_classes,
-    mk_elem_sort_dict, mk_stringsym_sort_dict
-)
-from .z3encoding.metamodel_encoding import (
-    def_association_rel,
-    def_attribute_rel,
-    mk_association_sort_dict,
-    mk_attribute_sort_dict, mk_class_sort_dict
-)
-from .z3encoding.types import Refs
-from .z3encoding.utils import mk_adata_sort
 from .mc_result import MCResult, MCResults
-
+from .z3encoding.im_encoding import (assert_im_associations,
+                                     assert_im_attributes,
+                                     def_elem_class_f_and_assert_classes, mk_attr_data_sort,
+                                     mk_elem_sort_dict, mk_stringsym_sort_dict)
+from .z3encoding.metamodel_encoding import (def_association_rel,
+                                            def_attribute_rel,
+                                            mk_association_sort_dict,
+                                            mk_attribute_sort_dict,
+                                            mk_class_sort_dict)
+from .z3encoding.types import Refs
 
 @dataclass
 class SMTEncoding:
@@ -50,10 +45,10 @@ class Requirement:
     assert_name: str
     description: str
     error_description: Callable[[Solver, SMTSorts, IntermediateModel], str]
-
+    flipped: bool = False
 
 class RequirementStore:
-    def __init__(self, requirements: list[Requirement]):
+    def __init__(self, requirements: list[Requirement] = []):
         self.requirements = requirements
         pass
 
@@ -72,75 +67,80 @@ class RequirementStore:
 
 class IntermediateModelChecker:
     def __init__(self, metamodel, inv_assoc, intermediate_model: IntermediateModel):
-        def instantiate_solver():
-            self.z3Context = Context()
-            self.solver = Solver(ctx=self.z3Context)
-
-            class_sort, class_ = mk_class_sort_dict(self.metamodel, self.z3Context)
-            assoc_sort, assoc = mk_association_sort_dict(self.metamodel, self.z3Context)
-            attr_sort, attr = mk_attribute_sort_dict(self.metamodel, self.z3Context)
-            elem_sort, elem = mk_elem_sort_dict(self.intermediate_model, self.z3Context)
-            ss_sort, ss = mk_stringsym_sort_dict(self.intermediate_model, self.metamodel, self.z3Context)
-            AData = mk_adata_sort(ss_sort, self.z3Context)
-            elem_class_f = def_elem_class_f_and_assert_classes(
-                self.intermediate_model,
-                self.solver,
-                elem_sort,
-                elem,
-                class_sort,
-                class_
-            )
-            attr_rel = def_attribute_rel(
-                attr_sort,
-                elem_sort,
-                AData
-            )
-            assert_im_attributes(
-                attr_rel,
-                self.solver,
-                self.intermediate_model,
-                self.metamodel,
-                elem,
-                attr_sort,
-                attr,
-                AData,
-                ss
-            )
-            assoc_rel = def_association_rel(
-                assoc_sort,
-                elem_sort
-            )
-            assert_im_associations_q(
-                assoc_rel,
-                self.solver,
-                {k: v for k, v in self.intermediate_model.items()},
-                elem,
-                assoc_sort,
-                assoc,
-            )
-            self.smt_encoding = SMTEncoding(
-                class_,
-                assoc,
-                attr,
-                elem,
-                ss,
-                elem_class_f,
-                attr_rel,
-                assoc_rel
-            )
-            self.smt_sorts = SMTSorts(
-                class_sort,
-                assoc_sort,
-                attr_sort,
-                elem_sort,
-                ss_sort,
-                AData
-            )
-
         self.metamodel = metamodel
         self.inv_assoc = inv_assoc
         self.intermediate_model = intermediate_model
-        instantiate_solver()
+        self.instantiate_solver()
+
+    def instantiate_solver(self, user_string_values=[]):
+        self.z3Context = Context()
+        self.solver = Solver(ctx=self.z3Context)
+
+        class_sort, class_ = mk_class_sort_dict(self.metamodel, self.z3Context)
+        assoc_sort, assoc = mk_association_sort_dict(self.metamodel, self.z3Context)
+        attr_sort, attr = mk_attribute_sort_dict(self.metamodel, self.z3Context)
+        elem_sort, elem = mk_elem_sort_dict(self.intermediate_model, self.z3Context)
+        str_sort, str = mk_stringsym_sort_dict(
+            self.intermediate_model,
+            self.metamodel,
+            self.z3Context,
+            user_string_values
+        )
+        attr_data_sort = mk_attr_data_sort(str_sort, self.z3Context)
+        elem_class_f = def_elem_class_f_and_assert_classes(
+            self.intermediate_model,
+            self.solver,
+            elem_sort,
+            elem,
+            class_sort,
+            class_
+        )
+        attr_rel = def_attribute_rel(
+            attr_sort,
+            elem_sort,
+            attr_data_sort
+        )
+        assert_im_attributes(
+            attr_rel,
+            self.solver,
+            self.intermediate_model,
+            self.metamodel,
+            elem,
+            attr_sort,
+            attr,
+            attr_data_sort,
+            str
+        )
+        assoc_rel = def_association_rel(
+            assoc_sort,
+            elem_sort
+        )
+        assert_im_associations(
+            assoc_rel,
+            self.solver,
+            {k: v for k, v in self.intermediate_model.items()},
+            elem,
+            assoc_sort,
+            assoc,
+        )
+        self.smt_encoding = SMTEncoding(
+            class_,
+            assoc,
+            attr,
+            elem,
+            str,
+            elem_class_f,
+            attr_rel,
+            assoc_rel
+        )
+        self.smt_sorts = SMTSorts(
+            class_sort,
+            assoc_sort,
+            attr_sort,
+            elem_sort,
+            str_sort,
+            attr_data_sort
+        )
 
     def check_requirements(self, reqs: RequirementStore, timeout: int = 0) -> MCResults:
         self.solver.set(timeout=(timeout * 1000))
@@ -154,9 +154,10 @@ class IntermediateModelChecker:
             )
             res = self.solver.check()
             results.append((
-                MCResult.from_z3result(res, flipped=True),
+                MCResult.from_z3result(res, flipped=req.flipped),
                 req.error_description(self.solver, self.smt_sorts, self.intermediate_model)
-                if res == sat else ""
+                # if res == sat else "" # not needed since we're try/catching model() errors 
+                # in each requirement now
             ))
             self.solver.pop()
 
diff --git a/mc_openapi/doml_mc/intermediate_model/metamodel.py b/mc_openapi/doml_mc/intermediate_model/metamodel.py
index 4b4fe8b052a021b7c854dfbdd10eef61146b310b..a10a505687e64ce3ede5de1bd5a10501f464e7d3 100644
--- a/mc_openapi/doml_mc/intermediate_model/metamodel.py
+++ b/mc_openapi/doml_mc/intermediate_model/metamodel.py
@@ -1,19 +1,19 @@
+import importlib.resources as ilres
 from dataclasses import dataclass
-from typing import cast, Literal, Optional, Union
 from enum import Enum
+from typing import Literal, Optional, Union, cast
 
-import importlib.resources as ilres
-import yaml
 import networkx as nx
+import yaml
 
 from ... import assets
-from .._utils import merge_dicts
-
+from ..utils import merge_dicts
 
 class DOMLVersion(Enum):
     V1_0 = "v1.0"
     V2_0 = "v2.0"
     V2_1 = "v2.1"
+    V2_2 = "v2.2"
 
 
 Multiplicity = tuple[Literal["0", "1"], Literal["1", "*"]]
@@ -53,6 +53,7 @@ class DOMLAssociation:
 MetaModel = dict[str, DOMLClass]
 InverseAssociation = list[tuple[str, str]]
 
+MetaModelDocs: dict[DOMLVersion, dict] = {}
 MetaModels: dict[DOMLVersion, MetaModel] = {}
 InverseAssociations: dict[DOMLVersion, InverseAssociation] = {}
 
@@ -152,9 +153,12 @@ def parse_inverse_associations(doc: dict) -> list[tuple[str, str]]:
 
 
 def init_metamodels():
-    global MetaModels, InverseAssociations
+    global MetaModelDocs, MetaModels, InverseAssociations
     for ver in DOMLVersion:
-        mmdoc = yaml.load(ilres.read_text(assets, f"doml_meta_{ver.value}.yaml"), yaml.Loader)
+        source = ilres.files(assets).joinpath(f"doml_meta_{ver.value}.yaml")
+        
+        mmdoc = yaml.load(source.read_text()  , yaml.Loader)
+        MetaModelDocs[ver] = mmdoc
         MetaModels[ver] = parse_metamodel(mmdoc)
         InverseAssociations[ver] = parse_inverse_associations(mmdoc)
 
@@ -208,6 +212,7 @@ def _find_attribute_class(
     if aname in c.attributes:
         return c
     elif c.superclass is None:
+        print(c)
         raise AttributeNotFound(
             f"Attribute {aname} not found in subclasses of {cname}."
         )
diff --git a/mc_openapi/doml_mc/mc.py b/mc_openapi/doml_mc/mc.py
index 5e5b721cce98883cb5406648532386c0d130f494..48be8aa743af9e25070475d397e9c55790012432 100644
--- a/mc_openapi/doml_mc/mc.py
+++ b/mc_openapi/doml_mc/mc.py
@@ -1,23 +1,19 @@
-from typing import Optional
-from joblib import parallel_backend, Parallel, delayed
 from multiprocessing import TimeoutError
+from typing import Optional
+
+from joblib import Parallel, delayed, parallel_backend
 
-from .intermediate_model.metamodel import (
-    DOMLVersion,
-    MetaModels,
-    InverseAssociations
-)
-from .xmi_parser.doml_model import parse_doml_model
-from .mc_result import MCResult, MCResults
-from .imc import RequirementStore, IntermediateModelChecker
 from .common_reqs import CommonRequirements
-from .consistency_reqs import (
-    get_attribute_type_reqs,
-    get_attribute_multiplicity_reqs,
-    get_association_type_reqs,
-    get_association_multiplicity_reqs,
-    get_inverse_association_reqs
-)
+from .consistency_reqs import (get_association_multiplicity_reqs,
+                               get_association_type_reqs,
+                               get_attribute_multiplicity_reqs,
+                               get_attribute_type_reqs,
+                               get_inverse_association_reqs)
+from .imc import IntermediateModelChecker, RequirementStore
+from .intermediate_model.metamodel import (DOMLVersion, InverseAssociations,
+                                           MetaModels)
+from .mc_result import MCResult, MCResults
+from .xmi_parser.doml_model import parse_doml_model
 
 
 class ModelChecker:
@@ -26,9 +22,21 @@ class ModelChecker:
         self.metamodel = MetaModels[self.doml_version]
         self.inv_assoc = InverseAssociations[self.doml_version]
 
-    def check_common_requirements(self, threads: int = 1, consistency_checks: bool = False, timeout: Optional[int] = None) -> MCResults:
+    def check_requirements(
+        self,
+        threads: int = 1,
+        user_requirements: Optional[RequirementStore] = None,
+        user_str_values: list[str] = [],
+        skip_common_requirements: bool = False,
+        consistency_checks: bool = False,
+        timeout: Optional[int] = None
+    ) -> MCResults:
         assert self.metamodel and self.inv_assoc
-        req_store = CommonRequirements[self.doml_version]
+        req_store = RequirementStore([])
+        
+        if not skip_common_requirements:
+            req_store += CommonRequirements[self.doml_version]
+
         if consistency_checks:
             req_store = req_store \
                 + get_attribute_type_reqs(self.metamodel) \
@@ -36,31 +44,38 @@ class ModelChecker:
                 + get_association_type_reqs(self.metamodel) \
                 + get_association_multiplicity_reqs(self.metamodel) \
                 + get_inverse_association_reqs(self.inv_assoc)
+        
+        if user_requirements:
+            req_store += user_requirements
 
         def worker(rfrom: int, rto: int):
             imc = IntermediateModelChecker(self.metamodel, self.inv_assoc, self.intermediate_model)
             rs = RequirementStore(req_store.get_all_requirements()[rfrom:rto])
+            imc.instantiate_solver(user_str_values)
             return imc.check_requirements(rs)
 
-        if threads <= 1:
-            imc = IntermediateModelChecker(self.metamodel, self.inv_assoc, self.intermediate_model)
-            reqs = imc.check_requirements(req_store, timeout=(0 if timeout is None else timeout))
-            return reqs
-        else:
-            def split_reqs(n_reqs: int, n_split: int):
-                slice_size = n_reqs // n_split
-                rto = 0
-                while rto < n_reqs:
-                    rfrom = rto
-                    rto = min(rfrom + slice_size, n_reqs)
-                    yield rfrom, rto
+        def split_reqs(n_reqs: int, n_split: int):
+            slice_size = max(n_reqs // n_split, 1)
+
+            rto = 0
+            while rto < n_reqs:
+                rfrom = rto
+                rto = min(rfrom + slice_size, n_reqs)
+                yield rfrom, rto
+
+        
+
+        try:
+            with parallel_backend('loky', n_jobs=threads):
+                results = Parallel(timeout=timeout)(delayed(worker)(rfrom, rto) for rfrom, rto in split_reqs(len(req_store), threads))
+
+            # Uncomment for ease of debug
+            # results =[ worker(0, len(req_store) )]
+
+            ret = MCResults([])
+            for res in results:
+                ret.add_results(res)
 
-            try:
-                with parallel_backend('loky', n_jobs=threads):
-                    results = Parallel(timeout=timeout)(delayed(worker)(rfrom, rto) for rfrom, rto in split_reqs(len(req_store), threads))
-                ret = MCResults([])
-                for res in results:
-                    ret.add_results(res)
-                return ret
-            except TimeoutError:
-                return MCResults([(MCResult.dontknow, "")])
+            return ret
+        except TimeoutError:
+            return MCResults([(MCResult.dontknow, "")])
diff --git a/mc_openapi/doml_mc/mc_result.py b/mc_openapi/doml_mc/mc_result.py
index 78309c1d17958bdd972ce802ec46ac494ea30d5f..ae785f4f9f4563f65b4162116f408daca5228197 100644
--- a/mc_openapi/doml_mc/mc_result.py
+++ b/mc_openapi/doml_mc/mc_result.py
@@ -9,6 +9,10 @@ class MCResult(Enum):
 
     @staticmethod
     def from_z3result(z3res: CheckSatResult, flipped: bool = False) -> "MCResult":
+        """Returns an Enum which is either sat, unsat or dontknow.
+        If flipped is true, then the sat and unsat are swapped: it's useful when
+        we are evaluating an expression in negative form.
+        """
         if flipped:
             if z3res == sat:
                 return MCResult.unsat
@@ -25,7 +29,7 @@ class MCResult(Enum):
 
 
 class MCResults:
-    dontknow_msg = "Timed out: unable to check some requirements."
+    DONTKNOW_MSG = "Timed out: unable to check some requirements."
 
     def __init__(self, results: list[tuple[MCResult, str]]):
         self.results = results
@@ -35,12 +39,12 @@ class MCResults:
         some_dontknow = any(res == MCResult.dontknow for res, _ in self.results)
 
         if some_unsat:
-            err_msg = " ".join(msg for res, msg in self.results if res == MCResult.unsat)
+            err_msg = "\n\n".join([msg for res, msg in self.results if res == MCResult.unsat])
             if some_dontknow:
-                err_msg = err_msg + MCResults.dontknow_msg
+                err_msg = err_msg + MCResults.DONTKNOW_MSG
             return MCResult.unsat, err_msg
         elif some_dontknow:
-            return MCResult.dontknow, MCResults.dontknow_msg
+            return MCResult.dontknow, MCResults.DONTKNOW_MSG
         else:
             return MCResult.sat, "All requirements satisfied."
 
diff --git a/mc_openapi/doml_mc/synthesis_old/__init__.py b/mc_openapi/doml_mc/synthesis_old/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..5aa44e830cce8f8953cf82a58943221cf9cbb247
--- /dev/null
+++ b/mc_openapi/doml_mc/synthesis_old/__init__.py
@@ -0,0 +1,3 @@
+import warnings
+warnings.warn("the synthesis module is deprecated", DeprecationWarning,
+              stacklevel=2)
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/synthesis_old/positive_common_reqs.domlr b/mc_openapi/doml_mc/synthesis_old/positive_common_reqs.domlr
new file mode 100644
index 0000000000000000000000000000000000000000..b792c5c82e8493e6727b1802431a1cc981af1bee
--- /dev/null
+++ b/mc_openapi/doml_mc/synthesis_old/positive_common_reqs.domlr
@@ -0,0 +1,85 @@
++   "All VMs have iface"
+    forall vm (
+        vm is class abstract.VirtualMachine
+        implies
+        exists iface (
+            vm has abstract.ComputingNode.ifaces iface
+        )
+    )
+    ---
+    "X"
+
++   "Concretization of Software Interfaces"
+    forall asc_consumer, asc_exposer, siface (
+        (
+            asc_consumer has application.SoftwareComponent.exposedInterfaces siface
+            and
+            asc_exposer has application.SoftwareComponent.consumedInterfaces siface
+        )
+        implies
+        exists cdeployment, cnode, edeployment, enode, net (
+            cdeployment has commons.Deployment.component asc_consumer
+            and
+            cdeployment has commons.Deployment.node cnode
+            and
+            exists vm, net_iface (
+                (
+                    # asc_consumer is deployed on a component with an interface in network n
+                    node has abstract.ComputingNode.ifaces net_iface
+                    and
+                    net_iface has abstract.NetworkInterface.belongsTo net
+                )
+                or
+                (
+                    # asc_consumer is deployed on a component with an interface in network n
+                    cnode has abstract.Container.hosts vm
+                    and
+                    vm has abstract.ComputingNode.ifaces net_iface
+                    and
+                    net_iface has abstract.NetworkInterface.belongsTo net
+                )
+                or
+                (
+                    # asc_consumer is deployed on a VM in an AutoScalingGroup with an interface in network n
+                    cnode has abstract.AutoScalingGroup.machineDefinition vm
+                    and
+                    vm has abstract.ComputingNode.ifaces net_iface
+                    and
+                    net_iface has abstract.NetworkInterface.belongsTo net
+                )
+            )
+        )
+        and
+        edeployment has commons.Deployment.component asc_exposer
+        and
+        edeployment has commons.Deployment.node enode
+        and
+        exists vm, net_iface (
+            (
+                # asc_exposer is deployed on a component with an interface in network n
+                enode has abstract.ComputingNode.ifaces net_iface
+                and
+                net_iface has abstract.NetworkInterface.belongsTo net
+            )
+            or
+            (
+                # asc_exposer is deployed on a container hosted on a VM with an interface in network n
+                enode has abstract.Container.hosts vm
+                and
+                vm has abstract.ComputingNode.ifaces net_iface
+                and
+                net_iface has abstract.NetworkInterface.belongsTo net
+            )
+            or
+            (
+                # asc_exposer is deployed on a VM in an AutoScalingGroup with an interface in network n
+                enode has abstract.AutoScalingGroup.machineDefinition vm
+                and
+                vm has abstract.ComputingNode.ifaces net_iface
+                and
+                net_iface has abstract.NetworkInterface.belongsTo net
+            )
+        )
+    )
+    ---
+    "YY"
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/synthesis_old/synthesis.py b/mc_openapi/doml_mc/synthesis_old/synthesis.py
new file mode 100644
index 0000000000000000000000000000000000000000..ade0858b84ba6ac2144773f2477aeca7c8d2a6f1
--- /dev/null
+++ b/mc_openapi/doml_mc/synthesis_old/synthesis.py
@@ -0,0 +1,354 @@
+
+
+from dataclasses import dataclass
+from itertools import product
+from typing import Tuple
+
+from z3 import (DatatypeRef, DatatypeSortRef, Not, FuncDeclRef, Model, Solver, sat,
+                unsat)
+from mc_openapi.doml_mc.imc import Requirement, SMTEncoding, SMTSorts
+from mc_openapi.doml_mc.intermediate_model.doml_element import IntermediateModel
+
+from mc_openapi.doml_mc.intermediate_model.metamodel import (DOMLVersion, MetaModel,
+                                                             parse_metamodel)
+from mc_openapi.doml_mc.xmi_parser.doml_model import parse_doml_model
+from mc_openapi.doml_mc.z3encoding.im_encoding import (
+    assert_im_associations, assert_im_attributes,
+    def_elem_class_f_and_assert_classes, mk_attr_data_sort, mk_elem_sort_dict,
+    mk_stringsym_sort_dict)
+from mc_openapi.doml_mc.z3encoding.metamodel_encoding import (
+    def_association_rel, def_attribute_rel, mk_association_sort_dict,
+    mk_attribute_sort_dict, mk_class_sort_dict)
+from mc_openapi.doml_mc.z3encoding.types import Refs
+
+# Types
+Elem = Value = Tuple[str, DatatypeRef]
+AssocAndElems = Tuple[Elem, DatatypeRef, Elem]
+AttrAndValues = Tuple[Elem, DatatypeRef, Value]
+
+@dataclass
+class Context:
+    solver: Solver
+    class_sort: DatatypeSortRef
+    class_refs: Refs
+    assoc_sort: DatatypeSortRef
+    assoc_refs: Refs
+    attr_sort: DatatypeSortRef
+    attr_refs: Refs
+    str_sort: DatatypeSortRef
+    str_refs: Refs
+    elem_sort: DatatypeSortRef
+    elem_refs: Refs
+    
+    attr_data_sort: DatatypeSortRef
+
+    elem_class_fn: FuncDeclRef
+    attr_rel: FuncDeclRef
+    assoc_rel: FuncDeclRef
+
+    unbound_elems: list[str]
+    unbound_values: Refs
+
+class Synthesis:
+    def __init__(self,
+        metamodel: MetaModel,
+        intermediate_model: IntermediateModel,
+        verbose: bool = False
+    ) -> None:
+        """
+        Initialize the data required to synthetize a new DOML according to provided requirements.
+
+        :param metamodel_input_file: The result of parsing the YAML metamodel file
+        :param domlx_input_file: A XMI DOML file read as bytes containing the model to run through the tests.
+        :param doml_version: The DOML version as an Enum.
+        """
+        self.mm = metamodel
+        self.im = intermediate_model
+        self.verbose = verbose
+
+    def _init_context(
+        self,
+        ub_elem_n : int = 0,
+        ub_vals_n : int = 0,
+        reqs : list[Requirement] = [],
+        user_req_strings : list[str] = []
+    ) -> Context:
+        """Builds a Context object containing all the relationships sorts and refs.
+        """
+        solver = Solver()
+        
+        class_sort, class_refs = mk_class_sort_dict(self.mm, solver.ctx)
+        assoc_sort, assoc_refs = mk_association_sort_dict(self.mm, solver.ctx)
+        attr_sort, attr_refs = mk_attribute_sort_dict(self.mm, solver.ctx)
+        str_sort, str_refs = mk_stringsym_sort_dict(self.im, self.mm, solver.ctx, user_req_strings)
+        attr_data_sort = mk_attr_data_sort(str_sort, solver.ctx)
+
+        unbound_elems = [f"unbound_elem_{i}" for i in range(ub_elem_n)]
+
+        # Takes a list of strings and creates an Enum out of 'em
+        elem_sort, elem_refs = mk_elem_sort_dict(self.im, solver.ctx, unbound_elems)
+
+        unbound_values_names = [f"unbound_val_{i}" for i in range(ub_vals_n)]
+        unbound_values = {
+            name : attr_data_sort.placeholder for name in unbound_values_names
+        }
+        # Examples of values that can go in unbound_values:
+        # ctx["attr_data_sort"].int(42), # ok
+        # ctx["attr_data_sort"].bool(True), # ok
+        # ctx["attr_data_sort"].str("x"), # cant do: it accept a ctx["str"][<str_key>] as input
+        # Const("x", ctx["attr_data_sort"]) # cant do: it is a symbolic value that cannot be converted to a BoolRef expression
+
+        elem_class_fn = def_elem_class_f_and_assert_classes(
+            self.im,
+            solver,
+            elem_sort,
+            elem_refs,
+            class_sort,
+            class_refs
+        )
+        
+        # attr_rel :: (elem_sort, attr_sort, attr_data_sort) -> BoolRef
+        attr_rel = def_attribute_rel(
+            attr_sort,
+            elem_sort,
+            attr_data_sort
+        )
+
+        assert_im_attributes(
+            attr_rel,
+            solver,
+            self.im,
+            self.mm,
+            elem_refs,
+            attr_sort,
+            attr_refs,
+            attr_data_sort,
+            str_refs
+        )
+
+        # assoc_rel :: (elem_sort, assoc_sort, elem_sort) -> BoolRef
+        assoc_rel = def_association_rel(
+            assoc_sort,
+            elem_sort
+        )
+        
+        assert_im_associations(
+            assoc_rel,
+            solver,
+            {k: v for k, v in self.im.items() if k not in unbound_elems},
+            elem_refs,
+            assoc_sort,
+            assoc_refs,
+        )
+
+        context = Context(
+            solver,
+            class_sort, class_refs,
+            assoc_sort, assoc_refs,
+            attr_sort, attr_refs,
+            str_sort, str_refs,
+            elem_sort, elem_refs,
+            attr_data_sort,
+            elem_class_fn,
+            attr_rel,
+            assoc_rel,
+            unbound_elems,
+            unbound_values
+        )
+
+        
+        encodings = SMTEncoding(
+            class_refs,
+            assoc_refs,
+            attr_refs,
+            elem_refs,
+            str_refs,
+            elem_class_fn,
+            attr_rel,
+            assoc_rel
+        )
+        sorts = SMTSorts(
+            class_sort,
+            assoc_sort,
+            attr_sort,
+            elem_sort,
+            str_sort,
+            attr_data_sort
+        )
+
+        # Add requirements
+        # TODO: Investigate whether it's possible or a good idea
+        #       to handle each requirement individually, like in imc.py
+        for req in reqs:
+            req_fn = req.assert_callable(encodings, sorts)
+            req_name = req.assert_name
+            solver.assert_and_track(req_fn, req_name)
+
+        return context
+
+    def check(self,
+        ub_elems_n: int = 0, 
+        ub_vals_n: int = 0, 
+        reqs: list = [], 
+        curr_try: int = 0, 
+        max_tries: int = 10,
+        user_req_strings: list[str] = []
+    ) -> Context:
+        if curr_try > max_tries:
+            raise RuntimeError("Max tries exceeded.")
+
+        ctx = self._init_context(ub_elems_n, ub_vals_n, reqs, user_req_strings)
+
+        res = ctx.solver.check()
+
+        if res == sat:
+            if self.verbose:
+                print(f"<Sat>\tub_elems_n={ub_elems_n}, ubvals_n={ub_vals_n}")
+            return ctx
+        elif res == unsat:
+            if self.verbose:
+                print(f"<Unsat>\tub_elems_n={ub_elems_n}, ubvals_n={ub_vals_n}")
+            
+            # TODO: Choose which goes first in a smart way?
+            if ub_elems_n > ub_vals_n:
+                new_ub_vals_n = ub_vals_n * 2 if ub_vals_n >= 1 else 1
+                return self.check(ub_elems_n, new_ub_vals_n, reqs, curr_try + 1, max_tries)
+            elif ub_elems_n <= ub_vals_n:
+                new_ub_elems_n = ub_elems_n * 2 if ub_elems_n >= 1 else 1
+                return self.check(new_ub_elems_n, ub_vals_n, reqs, curr_try + 1, max_tries)
+        else: # res == dontknow
+            raise RuntimeError("It took too long to decide satifiability.")
+
+    def get_ub_elems_and_assoc(self, ctx: Context, model: Model) -> list[AssocAndElems]:
+        """Returns the associations between unbound elements."""
+        return [ ((elem_1_k, elem_1_v), a, (elem_2_k, elem_2_v)) 
+            for (elem_1_k, elem_1_v), a, (elem_2_k, elem_2_v) in product(ctx.elem_refs.items(), ctx.assoc_refs.values(), ctx.elem_refs.items()) 
+            if (elem_1_k in ctx.unbound_elems or elem_2_k in ctx.unbound_elems) and model.eval(ctx.assoc_rel(elem_1_v, a, elem_2_v))
+        ]
+
+    def get_ub_vals_and_attr(self, ctx: Context, model: Model) -> list[AttrAndValues]:
+        """Returns the attribute relationships between elements and attribute data/values."""
+        return [ ((elem_k, elem_v), a, (ubval_k, ubval_v))
+            for (elem_k, elem_v), a, (ubval_k, ubval_v) in product(ctx.elem_refs.items(), ctx.attr_refs.values(), ctx.unbound_values.items())
+            if model.eval(ctx.attr_rel(elem_v, a, ubval_v))
+        ]
+
+    def pretty_ub_elems_assoc(self, assoc_elems: list[AssocAndElems]) -> str:
+        """Returns a string containg a human-readable name of the elements and their association.
+        """
+        (elem_1_k, _), a, (elem_2_k, _) = assoc_elems
+        elem_1 = self.im.get(elem_1_k)
+        if elem_1:
+            elem_1_name = f"{elem_1.class_} ({elem_1.user_friendly_name})" if elem_1_k[0:4] == "elem" else f"<'{elem_1_k}' not found>"
+        else:
+            elem_1_name = elem_1_k
+        
+        elem_2 = self.im.get(elem_2_k)
+        if elem_2:
+            elem_2_name = f"{elem_2.class_} ({elem_2.user_friendly_name})" if elem_2_k[0:4] == "elem" else f"<'{elem_2_k}' not found>"
+        else:
+            elem_2_name = elem_2_k
+        
+        assoc_name = str(a)
+
+        return f"{elem_1_name:<50s} {assoc_name:<60s} {elem_2_name:<30s}"
+
+    def pretty_ub_vals_attr(self, attr_and_val: list[AttrAndValues]) -> str:
+        """Returns a string containg a human-readable name of the element, the value and the
+           attribute relationship.
+        """
+        (elem_k, _), a, (ubval_k, _) = attr_and_val
+
+        elem_1 = self.im.get(elem_k)
+        if elem_1:
+            elem_1_name = f"{elem_1.class_} ({elem_1.user_friendly_name})" if elem_k[0:4] == "elem" else f"<'{elem_k}' not found>"
+        else:
+            elem_1_name = elem_k
+
+        attr_name = str(a)
+
+        val_name = str(ubval_k)
+
+        return f"{elem_1_name:<50s} {attr_name:<60s} {val_name:<30s}"
+
+    def thin_ub_elems_and_assoc(self, ctx: Context, ub_elems_and_assoc: list[AssocAndElems]):
+        if not ub_elems_and_assoc:
+            return []
+
+        (_, elem_1_v), a, (_, elem_2_v) = assoc = ub_elems_and_assoc[0]
+        assoc_rel = ctx.assoc_rel(elem_1_v, a, elem_2_v)
+
+        # Add negated constraint
+        ctx.solver.push()
+
+        if self.verbose:
+            print(f"\tAdd constraint Not({self.pretty_ub_elems_assoc(assoc)})")
+        ctx.solver.add(Not(assoc_rel))
+        
+        res = ctx.solver.check()
+        
+        if res == sat:
+            if self.verbose:
+                print("SAT:\tAdding one more constraint and trying again")
+            # Get new ub_elems_and_assoc
+            model = ctx.solver.model()
+            thinned_ub_elems_and_assoc = self.get_ub_elems_and_assoc(ctx, model)
+            
+            # Print table showing the diff
+            from difflib import context_diff
+            uvar_as_text = lambda input: [self.pretty_ub_elems_assoc(assoc) for assoc in input]
+            if self.verbose:
+                print("\n".join([a for a in context_diff(uvar_as_text(ub_elems_and_assoc), uvar_as_text(thinned_ub_elems_and_assoc), lineterm="", fromfile='Before', tofile="After")]))
+
+            # Iterate
+            return self.thin_ub_elems_and_assoc(ctx, thinned_ub_elems_and_assoc)
+        else:
+            if self.verbose:
+                print("UNSAT\tLast constraint was the association we are looking for!")
+            ctx.solver.pop()
+            
+            if ub_elems_and_assoc[1:]:
+                if self.verbose:
+                    print("\tIterating over")
+                    print("\t\t" + "\n\t\t".join([self.pretty_ub_elems_assoc(assoc) for assoc in ub_elems_and_assoc[1:]]))
+            return [*set([assoc] + self.thin_ub_elems_and_assoc(ctx, ub_elems_and_assoc[1:]))]
+
+    def thin_ub_vals_and_attr(self, ctx: Context, ub_vals_and_attr: list[AttrAndValues]):
+        if not ub_vals_and_attr:
+            return []
+
+        (_, elem_v), a, (_, attr_v) = attr = ub_vals_and_attr[0]
+        attr_rel = ctx["attr_rel"](elem_v, a, attr_v)
+
+        # Add negated constraint
+        ctx.solver.push()
+        if self.verbose:
+            print(f"\tAdd constraint Not({self.pretty_ubvals_attrs(attr)})")
+        ctx.solver.add(Not(attr_rel))
+        
+        res = ctx.solver.check()
+        
+        if res == sat:
+            print("SAT:\tAdding one more constraint and trying again")
+            # Get new ub_elems_and_assoc
+            model = ctx.solver.model()
+            thinned_ub_vals_and_attr = self.get_ubvals_and_attr(ctx, model)
+            
+            # Print table showing the diff
+            from difflib import context_diff
+            uvar_as_text = lambda input: [self.pretty_ubvals_attrs(attr) for attr in input]
+            if self.verbose:
+                print("\n".join([a for a in context_diff(uvar_as_text(ub_vals_and_attr), uvar_as_text(thinned_ub_vals_and_attr), lineterm="", fromfile='Before', tofile="After")]))
+
+            # Iterate
+            return self.thin_ub_vals_and_attr(ctx, thinned_ub_vals_and_attr)
+        else:
+            if self.verbose:
+                print("UNSAT\tLast constraint was the attribute we are looking for!")
+            ctx.solver.pop()
+            
+            if ub_vals_and_attr[1:]:
+                if self.verbose:
+                    print("\tIterating over")
+                    print("\t\t" + "\n\t\t".join([self.pretty_ubvals_attrs(attr) for attr in ub_vals_and_attr[1:]]))
+            return [*set([attr] + self.thin_ub_vals_and_attr(ctx, ub_vals_and_attr[1:]))]
diff --git a/mc_openapi/doml_mc/synthesis_old/synthesis_common_reqs.py b/mc_openapi/doml_mc/synthesis_old/synthesis_common_reqs.py
new file mode 100644
index 0000000000000000000000000000000000000000..1607a9cb59d30a867f91af2a5e4f7a08b3e5e50b
--- /dev/null
+++ b/mc_openapi/doml_mc/synthesis_old/synthesis_common_reqs.py
@@ -0,0 +1,194 @@
+from z3 import (
+    Consts, ExprRef,
+    ForAll, Exists, Implies, And, Or
+)
+
+from mc_openapi.doml_mc.imc import (
+    SMTEncoding, SMTSorts, Requirement, RequirementStore
+)
+
+
+
+
+def get_consts(smtsorts: SMTSorts, consts: list[str]) -> list[ExprRef]:
+    return Consts(" ".join(consts), smtsorts.element_sort)
+
+
+def vm_iface(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    vm, iface = get_consts(smtsorts, ["vm", "iface"])
+    return ForAll(
+        [vm],
+        Implies(
+            smtenc.element_class_fun(vm) == smtenc.classes["infrastructure_VirtualMachine"],
+            Exists(
+                [iface],
+                And(
+                    smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], iface)
+                )
+            )
+        )
+    )
+
+
+def software_package_iface_net(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    asc_consumer, asc_exposer, siface, net, net_iface, cnode, cdeployment, enode, edeployment, vm, dc = get_consts(
+        smtsorts,
+        ["asc_consumer", "asc_exposer", "siface", "net", "net_iface", "cnode", "cdeployment", "enode", "edeployment", "vm", "dc"]
+    )
+    return ForAll(
+        [asc_consumer, asc_exposer, siface],
+        Implies(
+            And(
+                smtenc.association_rel(asc_consumer, smtenc.associations["application_SoftwareComponent::exposedInterfaces"], siface),
+                smtenc.association_rel(asc_exposer, smtenc.associations["application_SoftwareComponent::consumedInterfaces"], siface),
+            ),
+            Exists(
+                [cdeployment, cnode, edeployment, enode, net],
+                And(
+                    smtenc.association_rel(cdeployment, smtenc.associations["commons_Deployment::component"], asc_consumer),
+                    smtenc.association_rel(cdeployment, smtenc.associations["commons_Deployment::node"], cnode),
+                    Exists(
+                        [vm, net_iface],
+                        Or(
+                            And(  # asc_consumer is deployed on a component with an interface in network n
+                                smtenc.association_rel(cnode, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface),
+                                smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                            ),
+                            And(  # asc_consumer is deployed on a component with an interface in network n
+                                smtenc.association_rel(cnode, smtenc.associations["infrastructure_Container::hosts"], vm),
+                                smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface),
+                                smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                            ),
+                            And(  # asc_consumer is deployed on a VM in an AutoScalingGroup with an interface in network n
+                                smtenc.association_rel(cnode, smtenc.associations["infrastructure_AutoScalingGroup::machineDefinition"], vm),
+                                smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface),
+                                smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                            ),
+                        )
+                    ),
+                    smtenc.association_rel(edeployment, smtenc.associations["commons_Deployment::component"], asc_exposer),
+                    smtenc.association_rel(edeployment, smtenc.associations["commons_Deployment::node"], enode),
+                    Exists(
+                        [vm, net_iface],
+                        Or(
+                            And(  # asc_exposer is deployed on a component with an interface in network n
+                                smtenc.association_rel(enode, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface),
+                                smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                            ),
+                            And(  # asc_exposer is deployed on a container hosted on a VM with an interface in network n
+                                smtenc.association_rel(enode, smtenc.associations["infrastructure_Container::hosts"], vm),
+                                smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface),
+                                smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                            ),
+                            And(  # asc_exposer is deployed on a VM in an AutoScalingGroup with an interface in network n
+                                smtenc.association_rel(enode, smtenc.associations["infrastructure_AutoScalingGroup::machineDefinition"], vm),
+                                smtenc.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], net_iface),
+                                smtenc.association_rel(net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                            ),
+                        )
+                    )
+                )
+            )
+        )
+    )
+
+
+def iface_uniq(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    def any_iface(elem, iface):
+        ifaces_assocs = [
+            "infrastructure_ComputingNode::ifaces",
+            "infrastructure_Storage::ifaces",
+            "infrastructure_FunctionAsAService::ifaces"
+        ]
+        return Or(*(smtenc.association_rel(elem, smtenc.associations[assoc_name], iface) for assoc_name in ifaces_assocs))
+
+    e1, e2, ni = get_consts(smtsorts, ["e1", "e2", "i"])
+    return ForAll(
+        [e1, e2, ni],
+        Implies(
+            And(any_iface(e1, ni), any_iface(e2, ni)),
+            e1 == e2
+        )
+    )
+
+
+def all_SoftwareComponents_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    sc, deployment, ielem = get_consts(smtsorts, ["sc", "deployment", "ielem"])
+    return ForAll(
+        [sc],
+        Implies(
+            smtenc.element_class_fun(sc) == smtenc.classes["application_SoftwareComponent"],
+            Exists(
+                [deployment, ielem],
+                And(
+                    smtenc.association_rel(deployment, smtenc.associations["commons_Deployment::component"], sc),
+                    smtenc.association_rel(deployment, smtenc.associations["commons_Deployment::node"], ielem),
+                )
+            )
+        )
+    )
+
+
+def all_infrastructure_elements_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    def checkOneClass(ielem, concr, provider, celem, ielemClass, providerAssoc, celemAssoc):
+        return Implies(
+            smtenc.element_class_fun(ielem) == smtenc.classes[ielemClass],
+            Exists(
+                [provider, celem],
+                And(
+                    smtenc.association_rel(concr, smtenc.associations["concrete_ConcreteInfrastructure::providers"], provider),
+                    smtenc.association_rel(provider, smtenc.associations[providerAssoc], celem),
+                    smtenc.association_rel(celem, smtenc.associations[celemAssoc], ielem)
+                )
+            )
+        )
+
+    ielem, concr, provider, celem = get_consts(smtsorts, ["ielem", "concr", "provider", "celem"])
+    return Exists(
+        [concr],
+        And(
+            smtenc.element_class_fun(concr) == smtenc.classes["concrete_ConcreteInfrastructure"],
+            ForAll(
+                [ielem],
+                And(
+                    checkOneClass(
+                        ielem, concr, provider, celem,
+                        "infrastructure_VirtualMachine",
+                        "concrete_RuntimeProvider::vms",
+                        "concrete_VirtualMachine::maps"
+                    ),
+                    checkOneClass(
+                        ielem, concr, provider, celem,
+                        "infrastructure_Network",
+                        "concrete_RuntimeProvider::networks",
+                        "concrete_Network::maps"
+                    ),
+                    checkOneClass(
+                        ielem, concr, provider, celem,
+                        "infrastructure_Storage",
+                        "concrete_RuntimeProvider::storages",
+                        "concrete_Storage::maps"
+                    ),
+                    checkOneClass(
+                        ielem, concr, provider, celem,
+                        "infrastructure_FunctionAsAService",
+                        "concrete_RuntimeProvider::faas",
+                        "concrete_FunctionAsAService::maps"
+                    ),
+                )
+            )
+        )
+    )
+
+
+synthesis_default_req_store = RequirementStore(
+    [
+        Requirement(*rt) for rt in [
+            (vm_iface, "vm_iface", "All virtual machines must be connected to at least one network interface.", "A virtual machine is connected to no network interface."),
+            (software_package_iface_net, "software_package_iface_net", "All software packages can see the interfaces they need through a common network.", "A software package is deployed on a node that has no access to an interface it consumes."),
+            (iface_uniq, "iface_uniq", "There are no duplicated interfaces.", "There is a duplicated interface."),
+            (all_SoftwareComponents_deployed, "all_SoftwareComponents_deployed", "All software components have been deployed to some node.", "A software component has not been deployed to any node."),
+            (all_infrastructure_elements_deployed, "all_infrastructure_elements_deployed", "All abstract infrastructure elements are mapped to an element in the active concretization.", "An abstract infrastructure element has not been mapped to any element in the active concretization."),
+        ]
+    ]
+)
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/synthesis_old/xmi_gen.py b/mc_openapi/doml_mc/synthesis_old/xmi_gen.py
new file mode 100644
index 0000000000000000000000000000000000000000..14766b5b9be74da698d7c1ceebdd75e2b909c813
--- /dev/null
+++ b/mc_openapi/doml_mc/synthesis_old/xmi_gen.py
@@ -0,0 +1,89 @@
+import re
+from itertools import product
+
+from pyecore.ecore import EClass, EObject
+
+from mc_openapi.doml_mc.intermediate_model.doml_element import \
+    IntermediateModel
+from mc_openapi.doml_mc.intermediate_model.metamodel import DOMLVersion
+from mc_openapi.doml_mc.synthesis_old.synthesis import AssocAndElems
+from mc_openapi.doml_mc.xmi_parser.doml_model import get_rset
+
+import secrets
+import base64
+
+def _gen_random_suffix_hash(len: int = 6):
+    return base64.urlsafe_b64encode(secrets.token_bytes(len)).decode()
+
+def _convert_camelcase_to_snakecase(input: str):
+    return re.sub(r'(?<!^)(?=[A-Z])', '_', input).lower()
+
+def generate_xmi(root: EObject, new_assocs: list[AssocAndElems], im: IntermediateModel, doml_ver: DOMLVersion = DOMLVersion.V2_0):
+
+    def find_eclass(eclass_package: str, eclass_name: str):
+        """`eclass_package` is like `infrastructure`
+           `eclass_name` is like `VirtualMachine`
+        """
+        pkgs = [pkg for pkg 
+            in list(get_rset(doml_ver).metamodel_registry.values()) 
+            if pkg.name == eclass_package
+        ]
+        # `metamodel_registry` is a dict consisting of:
+        # - ecore
+        # - doml
+        # |- commons
+        # |- application
+        # |- infrastructure
+        # |- concrete
+        # |- optimization
+        return pkgs[0].getEClassifier(eclass_name)
+
+    def find_elem(elem_name: str):
+        ret = []
+        for elem in root.eAllContents():
+            try:
+                if elem.name == elem_name:
+                    ret.append(elem)
+            except:
+                pass
+        return ret[0]
+
+    print(find_eclass("infrastructure", "NetworkInterface"))
+
+    for ((e1_k, e1_v), assoc, (e2_k, e2_v)) in new_assocs:
+        if "unbound" not in e1_k:
+            # it's an existing element
+            e1 = im[e1_k]
+            e1_class = re.search("^.*_(.+?)$", e1.class_).group(1)
+            e1_name = e1.attributes["commons_DOMLElement::name"][0]
+            print(e1_class, e1_name)
+        # TODO: Should I handle the case where the first element is an unbound one?
+
+        e1_instance = find_elem(e1_name)
+
+        # Regex to split <package>_<class>::<name>
+        assoc_re = re.search("^(.+?)_(.+?)::(.+?)$", str(assoc))
+        assoc_package = assoc_re.group(1)
+        assoc_class = assoc_re.group(2)
+        assoc_name = assoc_re.group(3)
+        print(assoc_package, assoc_class, assoc_name)
+
+        if "unbound" not in e2_k:
+            # it's an existing element
+            e2 = im[e2_k]
+            e2_class = re.search("^.*_(.+?)$", e2.class_).group(1)
+            e2_name = e2.attributes["commons_DOMLElement::name"][0]
+            print(e2_class, e2_name)
+            # TODO: Add relationship between the two?
+        else:
+            e1_container = getattr(e1_instance, assoc_name)
+            e2_instance_type = e1_container.feature.eType
+            e2_instance_name = (
+                _convert_camelcase_to_snakecase(e1_container.feature.eType.name)
+                + "_" 
+                + _gen_random_suffix_hash())
+            e2_instance = e2_instance_type(name=e2_instance_name)
+            e1_container.append(e2_instance)
+            
+
+    return root
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/_utils.py b/mc_openapi/doml_mc/utils.py
similarity index 86%
rename from mc_openapi/doml_mc/_utils.py
rename to mc_openapi/doml_mc/utils.py
index 458c453bc55b6d4975d1cb4c61bd836f206177f6..ac0a3c7e1688c4ec5ece0f1a9c8b6968754b8a10 100644
--- a/mc_openapi/doml_mc/_utils.py
+++ b/mc_openapi/doml_mc/utils.py
@@ -1,10 +1,11 @@
 from typing import TypeVar
 from collections.abc import Iterable
 
-
 _K = TypeVar("_K")
 _V = TypeVar("_V")
 
-
 def merge_dicts(it: Iterable[dict[_K, _V]]) -> dict[_K, _V]:
     return dict(kv for d in it for kv in d.items())
+
+def Iff(a, b):
+    return a == b
diff --git a/mc_openapi/bytes_uri.py b/mc_openapi/doml_mc/xmi_parser/bytes_uri.py
similarity index 100%
rename from mc_openapi/bytes_uri.py
rename to mc_openapi/doml_mc/xmi_parser/bytes_uri.py
diff --git a/mc_openapi/doml_mc/xmi_parser/doml_model.py b/mc_openapi/doml_mc/xmi_parser/doml_model.py
index 6310d4ff5d4cc7782f72436179821d2b2eaf373f..0659bf67af5beadee8fe0fda9bb4cefc3cfeef1b 100644
--- a/mc_openapi/doml_mc/xmi_parser/doml_model.py
+++ b/mc_openapi/doml_mc/xmi_parser/doml_model.py
@@ -1,30 +1,34 @@
-from typing import Optional, Tuple
 import copy
 import importlib.resources as ilres
-from lxml import etree
+from typing import Optional, Tuple
 
-from mc_openapi import assets
-from mc_openapi.bytes_uri import BytesURI
+from lxml import etree
 from pyecore.ecore import EObject
 from pyecore.resources import ResourceSet
 
-from ..intermediate_model.doml_element import IntermediateModel, reciprocate_inverse_associations
-from ..intermediate_model.metamodel import DOMLVersion, MetaModels, InverseAssociations
+from mc_openapi import assets
+
+from ..intermediate_model.doml_element import (
+    IntermediateModel, reciprocate_inverse_associations)
+from ..intermediate_model.metamodel import (DOMLVersion, InverseAssociations,
+                                            MetaModels)
+from .bytes_uri import BytesURI
 from .ecore import ELayerParser
 from .special_parsers import SpecialParsers
 
-
 doml_rsets = {}
 def init_doml_rsets():  # noqa: E302
     global doml_rsets
     for ver in DOMLVersion:
         rset = ResourceSet()
+        source = ilres.files(assets).joinpath(f"doml_{ver.value}.ecore")
         resource = rset.get_resource(BytesURI(
-            "doml", bytes=ilres.read_binary(assets, f"doml_{ver.value}.ecore")
+            "doml", bytes=source.read_bytes()
         ))
         doml_metamodel = resource.contents[0]
 
         rset.metamodel_registry[doml_metamodel.nsURI] = doml_metamodel
+        # .ecore file is loaded in the rset as a metamodel
         for subp in doml_metamodel.eSubpackages:
             rset.metamodel_registry[subp.nsURI] = subp
 
@@ -56,16 +60,38 @@ def infer_domlx_version(raw_model: bytes) -> DOMLVersion:
                 else:
                     raise RuntimeError(f"Supplied with DOMLX model of unsupported version {v_str}")
         else:
-            return DOMLVersion.V2_0  # Should be DOMLVersion.V1_0, but we use V2_0 because the 2.0 IDE doesn't fill it
+            return DOMLVersion.V2_0  # Should be DOMLVersion.V1_0, but we use V2_0 because the 2.1 IDE doesn't fill it
     else:
-        raise RuntimeError("Supplied with malformed DOMLX model.")
+        raise RuntimeError(f"Supplied with malformed DOMLX model or unsupported DOML version.\nIn use version is: {DOMLVersion.V2_0}")
 
 
 def parse_doml_model(raw_model: bytes, doml_version: Optional[DOMLVersion]) -> Tuple[IntermediateModel, DOMLVersion]:
+    # if doml_version is None:
+    #     doml_version = infer_domlx_version(raw_model)
+
+    # Try every DOML version until one works!
     if doml_version is None:
-        doml_version = infer_domlx_version(raw_model)
 
-    model = parse_xmi_model(raw_model, doml_version)
+        doml_versions = [x for x in DOMLVersion]
+        print(doml_versions)
+
+        def get_model(raw_model, doml_version):
+            try:
+                dv = doml_versions.pop(0)
+                doml_version = dv
+                return parse_xmi_model(raw_model, dv), dv
+            except Exception as e:
+                print(f"Couldn't parse with DOML {dv.value}. Trying another version...")
+                if len(doml_versions) == 0:
+                    raise e
+                else:
+                    return get_model(raw_model, doml_version)
+
+        model, doml_version = get_model(raw_model, doml_version)
+    else: # if user specifies DOML version, respect that choice!
+        model = parse_xmi_model(raw_model, doml_version)
+
+    print(f"Using DOML {doml_version.value}")
 
     elp = ELayerParser(MetaModels[doml_version], SpecialParsers[doml_version])
     if model.application:
@@ -84,3 +110,23 @@ def parse_doml_model(raw_model: bytes, doml_version: Optional[DOMLVersion]) -> T
     reciprocate_inverse_associations(im, InverseAssociations[doml_version])
 
     return im, doml_version
+
+def get_pyecore_model(raw_model: bytes, doml_version: Optional[DOMLVersion]) -> EObject:
+    if doml_version is None:
+        doml_version = infer_domlx_version(raw_model)
+    # TODO: See if its better replaced by the get_model() in parse_doml_version() 
+    return parse_xmi_model(raw_model, doml_version)
+
+from typing import Optional
+
+def serialize_pyecore_model(root: EObject, doml_version: DOMLVersion = DOMLVersion.V2_0, path: Optional[str] = None):
+    from pyecore.resources import URI
+
+    # Get rset with metamodel
+    rset = get_rset(doml_version) 
+    # Create the resource where we'll save the updated model/DOMLX
+    res = rset.create_resource(URI("./output.domlx"))
+    # Append updated EObject
+    res.append(root)
+    # Serialize to file
+    res.save()
diff --git a/mc_openapi/doml_mc/xmi_parser/special_parsers.py b/mc_openapi/doml_mc/xmi_parser/special_parsers.py
index 4427aae18fb61baa51875aa87bf55376cca11382..2b700e9256ccbfddac29dcc3023b266a40eb93e7 100644
--- a/mc_openapi/doml_mc/xmi_parser/special_parsers.py
+++ b/mc_openapi/doml_mc/xmi_parser/special_parsers.py
@@ -60,6 +60,12 @@ def init_special_parsers():
             ("infrastructure_ComputingNode", "memory_mb"): parse_memory_mb,
             ("commons_FProperty", "value"): parse_fproperty,
         },
+        DOMLVersion.V2_2: {
+            ("infrastructure_Network", "addressRange"): parse_cidr,
+            ("infrastructure_NetworkInterface", "endPoint"): parse_iface_address,
+            ("infrastructure_ComputingNode", "memory_mb"): parse_memory_mb,
+            ("commons_FProperty", "value"): parse_fproperty,
+        },
     }
     for ver in DOMLVersion:
         SpecialParsers[ver] = SpecialParser(MetaModels[ver], attribute_parsers[ver])
diff --git a/mc_openapi/doml_mc/z3encoding/im_encoding.py b/mc_openapi/doml_mc/z3encoding/im_encoding.py
index 31948d9eb04de6e6300ab5ccac03a59c53b35968..533ca401735a8368d913977c4994def3c2437577 100644
--- a/mc_openapi/doml_mc/z3encoding/im_encoding.py
+++ b/mc_openapi/doml_mc/z3encoding/im_encoding.py
@@ -1,31 +1,16 @@
-from typing import Union
 from itertools import product
+from typing import Union
+
+from z3 import (And, BoolSort, Const, Context, Datatype, DatatypeRef,
+                DatatypeSortRef, ForAll, FuncDeclRef, Function, IntSort, Not,
+                Or, Solver, EnumSort)
 
-from z3 import (
-    And,
-    Const,
-    Context,
-    DatatypeRef,
-    DatatypeSortRef,
-    ForAll,
-    FuncDeclRef,
-    Function,
-    Not,
-    Or,
-    Solver,
-)
+from mc_openapi.doml_mc.z3encoding.metamodel_encoding import mk_enum_sort_dict
 
 from ..intermediate_model import IntermediateModel, MetaModel
 from ..intermediate_model.metamodel import get_mangled_attribute_defaults
-
 from .types import Refs, SortAndRefs
-from .utils import (
-    assert_relation_tuples,
-    Iff,
-    mk_enum_sort_dict,
-    mk_stringsym_sort_from_strings,
-)
-
+from ..utils import Iff
 
 def mk_elem_sort_dict(
     im: IntermediateModel,
@@ -61,41 +46,42 @@ def assert_im_attributes(
     solver: Solver,
     im: IntermediateModel,
     mm: MetaModel,
-    elem: Refs,
-    attr_sort: DatatypeSortRef,
-    attr: Refs,
-    AData: DatatypeSortRef,
-    ss: Refs,
+    elems: Refs,
+    attr_sort: DatatypeSortRef, # Relationship sort
+    attrs: Refs, # Relationship data
+    attr_data_sort: DatatypeSortRef, # Value sort
+    strings: Refs,
+    allow_placeholders: bool = False
 ) -> None:
     """
     ### Effects
     This procedure is effectful on `solver`.
     """
 
-    def encode_adata(v: Union[str, int, bool]) -> DatatypeRef:
+    def encode_attr_data(v: Union[str, int, bool]) -> DatatypeRef:
         if type(v) is str:
-            return AData.ss(ss[v])  # type: ignore
+            return attr_data_sort.str(strings[v])  # type: ignore
         elif type(v) is int:
-            return AData.int(v)  # type: ignore
+            return attr_data_sort.int(v)  # type: ignore
         else:  # type(v) is bool
-            return AData.bool(v)  # type: ignore
+            return attr_data_sort.bool(v)  # type: ignore
 
     a = Const("a", attr_sort)
-    d = Const("d", AData)
+    d = Const("d", attr_data_sort)
     for esn, im_es in im.items():
-        mangled_attrs = get_mangled_attribute_defaults(mm, im_es.class_) | im_es.attributes
-        if mangled_attrs:
+        attr_data = get_mangled_attribute_defaults(mm, im_es.class_) | im_es.attributes
+        if attr_data:
             assn = ForAll(
                 [a, d],
                 Iff(
-                    attr_rel(elem[esn], a, d),
+                    attr_rel(elems[esn], a, d),
                     Or(
                         *(
                             And(
-                                a == attr[aname],
-                                d == encode_adata(avalue),
+                                a == attrs[aname],
+                                d == encode_attr_data(avalue)
                             )
-                            for aname, avalues in mangled_attrs.items()
+                            for aname, avalues in attr_data.items()
                             for avalue in avalues
                         )
                     ),
@@ -104,43 +90,14 @@ def assert_im_attributes(
         else:
             assn = ForAll(
                 [a, d],
-                Not(attr_rel(elem[esn], a, d))
+                Not(attr_rel(elems[esn], a, d))
             )
         solver.assert_and_track(assn, f"attribute_values {esn}")
 
-
 def assert_im_associations(
     assoc_rel: FuncDeclRef,
     solver: Solver,
-    im: IntermediateModel,
-    mm: MetaModel,
-    elem: Refs,
-    assoc: Refs,
-) -> None:
-    """
-    ### Effects
-    This procedure is effectful on `solver`.
-    """
-    elem_names = set(im.keys())
-    assoc_mangled_names = {
-        f"{cname}::{aname}"
-        for cname, c in mm.items()
-        for aname in c.associations
-    }
-    rel_tpls = [
-        [esn, amn, etn]
-        for esn, amn, etn in product(
-            elem_names, assoc_mangled_names, elem_names
-        )
-        if etn in im[esn].associations.get(amn, set())
-    ]
-    assert_relation_tuples(assoc_rel, solver, rel_tpls, elem, assoc, elem)
-
-
-def assert_im_associations_q(
-    assoc_rel: FuncDeclRef,
-    solver: Solver,
-    im: IntermediateModel,
+    im: IntermediateModel, # Contains only bounded elements
     elem: Refs,
     assoc_sort: DatatypeSortRef,
     assoc: Refs,
@@ -150,29 +107,30 @@ def assert_im_associations_q(
     This procedure is effectful on `solver`.
     """
 
-    a = Const("a", assoc_sort)
-    for (esn, im_es), etn in product(im.items(), im):
+    assoc_ref = Const("a", assoc_sort)
+    for (elem_1_k, elem_1_v), elem_2_k in product(im.items(), im):
         assn = ForAll(
-            [a],
+            [assoc_ref],
             Iff(
-                assoc_rel(elem[esn], a, elem[etn]),
+                assoc_rel(elem[elem_1_k], assoc_ref, elem[elem_2_k]),
                 Or(
                     *(
-                        a == assoc[amn]
-                        for amn, etns in im_es.associations.items()
-                        if etn in etns
+                        assoc_ref == assoc[elem_1_assoc_k]
+                        for elem_1_assoc_k, elem_1_assoc_elems_k in elem_1_v.associations.items()
+                        if elem_2_k in elem_1_assoc_elems_k
                     ),
                     solver.ctx
                 ),
             ),
         )
-        solver.assert_and_track(assn, f"associations {esn} {etn}")
+        solver.assert_and_track(assn, f"associations {elem_1_k} {elem_2_k}")
 
 
 def mk_stringsym_sort_dict(
     im: IntermediateModel,
     mm: MetaModel,
-    z3ctx: Context
+    z3ctx: Context,
+    additional_strings: list[str] = []
 ) -> SortAndRefs:
     strings = (
         {
@@ -191,5 +149,36 @@ def mk_stringsym_sort_dict(
             if isinstance(v, str)
         }
         | {"SCRIPT", "IMAGE"}  # GeneratorKind values
+        | {"INGRESS", "EGRESS"} # TODO: Check if this fix is required
+        # It solves a KeyError when MC is run on openstack_template.domlx
+        | {
+            v
+            for v in additional_strings
+        }
     )
     return mk_stringsym_sort_from_strings(list(strings), z3ctx=z3ctx)
+
+def mk_attr_data_sort(
+    str_sort: DatatypeSortRef,
+    z3ctx: Context
+) -> DatatypeSortRef:
+    attr_data = Datatype("AttributeData", ctx=z3ctx)
+    attr_data.declare("placeholder")
+    attr_data.declare("int", ("get_int", IntSort(ctx=z3ctx)))
+    attr_data.declare("bool", ("get_bool", BoolSort(ctx=z3ctx)))
+    attr_data.declare("str", ("get_str", str_sort)) # str_sort is the one returned by the function above
+    return attr_data.create()
+
+def mk_stringsym_sort_from_strings(
+    strings: list[str],
+    z3ctx: Context
+) -> SortAndRefs:
+    str_list = [f"str_{i}_{symbolize(s)}" for i, s in enumerate(strings)]
+    string_sort, str_refs_dict = mk_enum_sort_dict("string", str_list, z3ctx=z3ctx)
+    string_sort_dict = {
+        s: str_refs_dict[str] for s, str in zip(strings, str_list)
+    }
+    return string_sort, string_sort_dict
+
+def symbolize(s: str) -> str:
+    return "".join([c.lower() if c.isalnum() else "_" for c in s[:16]])
diff --git a/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py b/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py
index 22c48484de3709b6526aa77c44d80da3aea07700..97af7a3b7860a171b652c6d724428cc035b651ae 100644
--- a/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py
+++ b/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py
@@ -4,12 +4,11 @@ from z3 import (
     DatatypeSortRef,
     FuncDeclRef,
     Function,
+    EnumSort
 )
 from ..intermediate_model import MetaModel
 
 from .types import SortAndRefs
-from .utils import mk_enum_sort_dict
-
 
 def mk_class_sort_dict(mm: MetaModel, z3ctx: Context) -> SortAndRefs:
     return mk_enum_sort_dict("Class", list(mm), z3ctx)
@@ -38,13 +37,18 @@ def mk_association_sort_dict(
     ]
     return mk_enum_sort_dict("Association", assocs, z3ctx)
 
+def mk_enum_sort_dict(name: str, values: list[str], z3ctx: Context) -> SortAndRefs:
+    """Makes a Z3 sort and a dict indexing sort values by their name"""
+
+    sort, datatype_refs = EnumSort(name, values, ctx=z3ctx)
+    return sort, dict(zip(values, datatype_refs))
 
 def def_attribute_rel(
     attr_sort: DatatypeSortRef,
     elem_sort: DatatypeSortRef,
-    AData: DatatypeSortRef
+    attr_data_sort: DatatypeSortRef
 ) -> FuncDeclRef:
-    return Function("attribute", elem_sort, attr_sort, AData, BoolSort(ctx=elem_sort.ctx))
+    return Function("attribute", elem_sort, attr_sort, attr_data_sort, BoolSort(ctx=elem_sort.ctx))
 
 
 def def_association_rel(
diff --git a/mc_openapi/doml_mc/z3encoding/utils.py b/mc_openapi/doml_mc/z3encoding/utils.py
deleted file mode 100644
index 04730494fc3687311d439f9bc06f1f73e16a9fc2..0000000000000000000000000000000000000000
--- a/mc_openapi/doml_mc/z3encoding/utils.py
+++ /dev/null
@@ -1,150 +0,0 @@
-from typing import cast
-from collections.abc import Sequence
-from itertools import product
-
-from z3 import (
-    BoolSort,
-    BoolVal,
-    Context,
-    Datatype,
-    DatatypeSortRef,
-    ExprRef,
-    EnumSort,
-    FuncDeclRef,
-    IntSort,
-    Solver,
-)
-
-from .types import Refs, SortAndRefs
-
-
-def mk_enum_sort_dict(name: str, values: list[str], z3ctx: Context) -> SortAndRefs:
-    """Makes a Z3 sort and a dict indexing sort values by their name"""
-
-    sort, dtrefs = EnumSort(name, values, ctx=z3ctx)
-    return sort, dict(zip(values, dtrefs))
-
-
-def assert_relation_tuples(
-    rel: FuncDeclRef,
-    solver: Solver,
-    rel_tpls: list[list[str]],
-    *sig_dicts: Refs,
-) -> None:
-    """
-    ### Parameters
-     - `rel` is a Z3 function with return type Bool representing a relation;
-     - `solver` is the Z3 solver on which to assert;
-     - `rel_tpls` is a list of lists of names of symbols which are related in
-       `rel`;
-     - `sig_dicts` are the domains of `rel`.
-
-    ### Effects
-    This procedure is effectful on `solver`.
-    """
-
-    # Length of tuples must me homogeneous and equal to the number of given
-    # domains.
-    if lengths := [len(tpl) for tpl in rel_tpls]:
-        assert min(lengths) == max(lengths)
-        assert lengths[0] == len(sig_dicts)
-
-    sym_tpls = [
-        cast(
-            list[ExprRef],
-            [dom[sym_name] for sym_name, dom in zip(doms_tpl, sig_dicts)],
-        )
-        + [BoolVal(doms_tpl in rel_tpls, ctx=solver.ctx)]
-        for doms_tpl in map(list, product(*sig_dicts))
-    ]
-
-    assert_function_tuples_raw(rel, solver, sym_tpls)
-
-
-def assert_function_tuples(
-    f: FuncDeclRef,
-    solver: Solver,
-    f_tpls: list[list[str]],
-    *sig_dicts: Refs,
-) -> None:
-    """
-    ### Parameters
-     - `f` is a Z3 function;
-     - `solver` is the Z3 solver on which to assert;
-     - `f_tpls` is a list of tuples of Z3 symbols. The first elements in each
-       tuple are the inputs of `f`, and the last element is its output;
-     - `sig_dicts` are the domains of `f`, the last one being its codomain.
-
-    ### Effects
-    This procedure is effectful on `solver`.
-    """
-
-    # Length of tuples must me homogeneous and equal to the number of given
-    # domains.
-    if lengths := [len(tpl) for tpl in f_tpls]:
-        assert min(lengths) == max(lengths)
-        assert lengths[0] == len(sig_dicts)
-
-    sym_tpls = [
-        [dom[sym_name] for sym_name, dom in zip(f_tpl, sig_dicts)]
-        for f_tpl in f_tpls
-    ]
-
-    assert_function_tuples_raw(f, solver, sym_tpls)
-
-
-def assert_function_tuples_raw(
-    f: FuncDeclRef,
-    solver: Solver,
-    f_tpls: Sequence[Sequence[ExprRef]],
-) -> None:
-    """
-    ### Parameters
-     - `f` is a Z3 function;
-     - `solver` is the Z3 solver on which to assert;
-     - `f_tpls` is a list of tuples of Z3 references or otherwise accepted
-       values. The first elements in each tuple are the inputs of `f`, and the
-       last element is its output;
-
-    ### Effects
-    This procedure is effectful on `solver`.
-    """
-    # Length of tuples must me homogeneous.
-    if lengths := [len(tpl) for tpl in f_tpls]:
-        assert min(lengths) == max(lengths)
-
-    for *xs, y in f_tpls:
-        solver.assert_and_track(
-            f(*xs) == y,
-            f"{f.name()} " + " ".join(str(x) for x in xs) + f" {y}",
-        )
-
-
-def mk_stringsym_sort_from_strings(
-    strings: list[str],
-    z3ctx: Context
-) -> SortAndRefs:
-    def symbolize(s: str) -> str:
-        return "".join([c.lower() if c.isalnum() else "_" for c in s[:16]])
-
-    ss_list = [f"ss_{i}_{symbolize(s)}" for i, s in enumerate(strings)]
-    stringsym_sort, ss_refs_dict = mk_enum_sort_dict("StringSym", ss_list, z3ctx=z3ctx)
-    stringsym_sort_dict = {
-        s: ss_refs_dict[ss] for s, ss in zip(strings, ss_list)
-    }
-    return stringsym_sort, stringsym_sort_dict
-
-
-def mk_adata_sort(
-    ss_sort: DatatypeSortRef,
-    z3ctx: Context
-) -> DatatypeSortRef:
-    AData = Datatype("AttributeData", ctx=z3ctx)
-    AData.declare("int", ("get_int", IntSort(ctx=z3ctx)))
-    AData.declare("bool", ("get_bool", BoolSort(ctx=z3ctx)))
-    AData.declare("ss", ("get_ss", ss_sort))
-    return AData.create()
-
-
-def Iff(a, b):
-    return a == b
diff --git a/mc_openapi/handlers.py b/mc_openapi/handlers.py
index 9c84b9b0ce668eef3d75feab2f0b55d24d152878..99b3d8521ad36bf1ccef906f9b1d960a2f2c4d7f 100644
--- a/mc_openapi/handlers.py
+++ b/mc_openapi/handlers.py
@@ -1,4 +1,9 @@
 import datetime
+from mc_openapi.doml_mc.domlr_parser.parser import DOMLRTransformer, Parser
+from mc_openapi.doml_mc.imc import RequirementStore
+
+from mc_openapi.doml_mc.intermediate_model.metamodel import DOMLVersion
+from mc_openapi.doml_mc.xmi_parser.doml_model import get_pyecore_model
 from .doml_mc import ModelChecker, MCResult
 
 
@@ -6,14 +11,37 @@ def make_error(user_msg, debug_msg=None):
     result = {"message": user_msg, "timestamp": datetime.datetime.now()}
     if debug_msg is not None:
         result["debug_message"] = debug_msg
+        print(f"ERROR [{datetime.datetime.now()}]: {debug_msg}")
     return result
 
 
-def post(body, requirement=None):
+def post(body):
     doml_xmi = body
     try:
+
         dmc = ModelChecker(doml_xmi)
-        results = dmc.check_common_requirements(threads=2, consistency_checks=False, timeout=50)
+
+        user_req_store = None
+        user_req_str_consts = []
+
+        # Add support for Requirements in DOML
+        if dmc.doml_version == DOMLVersion.V2_2:
+                domlr_parser = Parser(DOMLRTransformer)
+                model = get_pyecore_model(doml_xmi, DOMLVersion.V2_2)
+                func_reqs = model.functionalRequirements.items
+
+                user_req_store = RequirementStore()
+
+                for req in func_reqs:
+                    req_name: str = req.name
+                    req_text: str = req.description
+                    req_text = req_text.replace("```", "")
+                    doml_req_store, doml_req_str_consts = domlr_parser.parse(req_text)
+                    user_req_store += doml_req_store
+                    user_req_str_consts += doml_req_str_consts
+
+
+        results = dmc.check_requirements(threads=2, user_requirements=user_req_store, user_str_values=user_req_str_consts, consistency_checks=False, timeout=50)
         res, msg = results.summarize()
 
         if res == MCResult.sat:
@@ -22,5 +50,6 @@ def post(body, requirement=None):
             return {"result": res.name,
                     "description": msg}
 
+    # TODO: Make noteworthy exceptions to at least tell the user what is wrong
     except Exception as e:
         return make_error("The supplied DOMLX model is malformed or its DOML version is unsupported.", debug_msg=str(e)), 400
diff --git a/mc_openapi/notebooks/dict_reference.ipynb b/mc_openapi/notebooks/dict_reference.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..7307d91f12c97fa324e54f9ef42888f49b86d824
--- /dev/null
+++ b/mc_openapi/notebooks/dict_reference.ipynb
@@ -0,0 +1,251 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from pprint import pprint\n",
+    "\n",
+    "from mc_openapi.doml_mc import ModelChecker, DOMLVersion\n",
+    "\n",
+    "doml_document_path = \"../../tests/doml/v2.0/nginx-openstack_v2.0.domlx\"\n",
+    "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0_wrong_vm_iface.domlx\"\n",
+    "# doml_document_path = \"../../tests/doml/faas.domlx\"\n",
+    "with open(doml_document_path, \"rb\") as xmif:\n",
+    "    doc = xmif.read()\n",
+    "\n",
+    "model_checker = ModelChecker(doc, DOMLVersion.V2_0)\n",
+    "meta_model = model_checker.metamodel\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "SyntaxError",
+     "evalue": "f-string: unmatched '(' (2134446349.py, line 2)",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;36m  Cell \u001b[0;32mIn [13], line 2\u001b[0;36m\u001b[0m\n\u001b[0;31m    f\"{cname.replace(\"_\", \".\")}.{aname}\"\u001b[0m\n\u001b[0m                      ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m f-string: unmatched '('\n"
+     ]
+    }
+   ],
+   "source": [
+    "atts = [\n",
+    "    f\"{cname}::{aname}\"\n",
+    "    for cname, c in meta_model.items()\n",
+    "    for aname in c.attributes\n",
+    "]\n",
+    "\n",
+    "pprint(atts)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "['commons_DOMLElement.annotations',\n",
+      " 'commons_Property.reference',\n",
+      " 'commons_Configuration.deployments',\n",
+      " 'commons_Deployment.component',\n",
+      " 'commons_Deployment.node',\n",
+      " 'application_ApplicationLayer.components',\n",
+      " 'application_SoftwareComponent.exposedInterfaces',\n",
+      " 'application_SoftwareComponent.consumedInterfaces',\n",
+      " 'application_SaaS.exposedInterfaces',\n",
+      " 'infrastructure_InfrastructureLayer.nodes',\n",
+      " 'infrastructure_InfrastructureLayer.generators',\n",
+      " 'infrastructure_InfrastructureLayer.storages',\n",
+      " 'infrastructure_InfrastructureLayer.faas',\n",
+      " 'infrastructure_InfrastructureLayer.credentials',\n",
+      " 'infrastructure_InfrastructureLayer.groups',\n",
+      " 'infrastructure_InfrastructureLayer.securityGroups',\n",
+      " 'infrastructure_InfrastructureLayer.networks',\n",
+      " 'infrastructure_ComputingNode.ifaces',\n",
+      " 'infrastructure_ComputingNode.location',\n",
+      " 'infrastructure_ComputingNode.credentials',\n",
+      " 'infrastructure_ComputingNode.group',\n",
+      " 'infrastructure_VirtualMachine.generatedFrom',\n",
+      " 'infrastructure_Container.generatedFrom',\n",
+      " 'infrastructure_Container.hosts',\n",
+      " 'infrastructure_VMImage.generatedVMs',\n",
+      " 'infrastructure_ContainerImage.generatedContainers',\n",
+      " 'infrastructure_AutoScalingGroup.machineDefinition',\n",
+      " 'infrastructure_AutoScalingGroup.deploymentNetwork',\n",
+      " 'infrastructure_AutoScalingGroup.securityGroup',\n",
+      " 'infrastructure_Storage.ifaces',\n",
+      " 'infrastructure_FunctionAsAService.ifaces',\n",
+      " 'infrastructure_Network.connectedIfaces',\n",
+      " 'infrastructure_Network.igws',\n",
+      " 'infrastructure_Network.subnets',\n",
+      " 'infrastructure_Subnet.connectedTo',\n",
+      " 'infrastructure_NetworkInterface.belongsTo',\n",
+      " 'infrastructure_NetworkInterface.associated',\n",
+      " 'infrastructure_ComputingGroup.groupedNodes',\n",
+      " 'infrastructure_SecurityGroup.rules',\n",
+      " 'infrastructure_SecurityGroup.ifaces',\n",
+      " 'infrastructure_SwarmRole.nodes',\n",
+      " 'infrastructure_Swarm.roles',\n",
+      " 'concrete_ConcreteInfrastructure.providers',\n",
+      " 'concrete_RuntimeProvider.vms',\n",
+      " 'concrete_RuntimeProvider.vmImages',\n",
+      " 'concrete_RuntimeProvider.containerImages',\n",
+      " 'concrete_RuntimeProvider.networks',\n",
+      " 'concrete_RuntimeProvider.storages',\n",
+      " 'concrete_RuntimeProvider.faas',\n",
+      " 'concrete_RuntimeProvider.group',\n",
+      " 'concrete_VirtualMachine.maps',\n",
+      " 'concrete_VMImage.maps',\n",
+      " 'concrete_ContainerImage.maps',\n",
+      " 'concrete_Network.maps',\n",
+      " 'concrete_Storage.maps',\n",
+      " 'concrete_FunctionAsAService.maps',\n",
+      " 'concrete_ComputingGroup.maps']\n"
+     ]
+    }
+   ],
+   "source": [
+    "assocs = [\n",
+    "    f\"{cname}::{aname}\"\n",
+    "    for cname, c in meta_model.items()\n",
+    "    for aname in c.associations\n",
+    "]\n",
+    "\n",
+    "pprint(assocs)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "NameError",
+     "evalue": "name 'mm' is not defined",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
+      "Cell \u001b[0;32mIn [10], line 2\u001b[0m\n\u001b[1;32m      1\u001b[0m strings \u001b[39m=\u001b[39m [v\n\u001b[0;32m----> 2\u001b[0m             \u001b[39mfor\u001b[39;00m c \u001b[39min\u001b[39;00m mm\u001b[39m.\u001b[39mvalues()\n\u001b[1;32m      3\u001b[0m             \u001b[39mfor\u001b[39;00m a \u001b[39min\u001b[39;00m c\u001b[39m.\u001b[39mattributes\u001b[39m.\u001b[39mvalues()\n\u001b[1;32m      4\u001b[0m             \u001b[39mif\u001b[39;00m a\u001b[39m.\u001b[39mdefault \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mNone\u001b[39;00m\n\u001b[1;32m      5\u001b[0m             \u001b[39mfor\u001b[39;00m v \u001b[39min\u001b[39;00m a\u001b[39m.\u001b[39mdefault\n\u001b[1;32m      6\u001b[0m             \u001b[39mif\u001b[39;00m \u001b[39misinstance\u001b[39m(v, \u001b[39mstr\u001b[39m)]\n\u001b[1;32m      8\u001b[0m pprint(strings)\n",
+      "\u001b[0;31mNameError\u001b[0m: name 'mm' is not defined"
+     ]
+    }
+   ],
+   "source": [
+    "strings = [v\n",
+    "            for c in mm.values()\n",
+    "            for a in c.attributes.values()\n",
+    "            if a.default is not None\n",
+    "            for v in a.default\n",
+    "            if isinstance(v, str)]\n",
+    "\n",
+    "pprint(strings)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "['commons_DOMLElement',\n",
+      " 'commons_Property',\n",
+      " 'commons_IProperty',\n",
+      " 'commons_SProperty',\n",
+      " 'commons_FProperty',\n",
+      " 'commons_BProperty',\n",
+      " 'commons_Configuration',\n",
+      " 'commons_Deployment',\n",
+      " 'application_ApplicationLayer',\n",
+      " 'application_ApplicationComponent',\n",
+      " 'application_SoftwareComponent',\n",
+      " 'application_SaaS',\n",
+      " 'application_SoftwareInterface',\n",
+      " 'application_DBMS',\n",
+      " 'application_SaaSDBMS',\n",
+      " 'infrastructure_InfrastructureLayer',\n",
+      " 'infrastructure_InfrastructureElement',\n",
+      " 'infrastructure_ComputingNode',\n",
+      " 'infrastructure_PhysicalComputingNode',\n",
+      " 'infrastructure_VirtualMachine',\n",
+      " 'infrastructure_Location',\n",
+      " 'infrastructure_Container',\n",
+      " 'infrastructure_ComputingNodeGenerator',\n",
+      " 'infrastructure_VMImage',\n",
+      " 'infrastructure_ContainerImage',\n",
+      " 'infrastructure_AutoScalingGroup',\n",
+      " 'infrastructure_Storage',\n",
+      " 'infrastructure_FunctionAsAService',\n",
+      " 'infrastructure_Network',\n",
+      " 'infrastructure_Subnet',\n",
+      " 'infrastructure_NetworkInterface',\n",
+      " 'infrastructure_InternetGateway',\n",
+      " 'infrastructure_ComputingGroup',\n",
+      " 'infrastructure_SecurityGroup',\n",
+      " 'infrastructure_Rule',\n",
+      " 'infrastructure_Credentials',\n",
+      " 'infrastructure_KeyPair',\n",
+      " 'infrastructure_UserPass',\n",
+      " 'infrastructure_SwarmRole',\n",
+      " 'infrastructure_Swarm',\n",
+      " 'infrastructure_ExtInfrastructureElement',\n",
+      " 'concrete_ConcreteInfrastructure',\n",
+      " 'concrete_ConcreteElement',\n",
+      " 'concrete_RuntimeProvider',\n",
+      " 'concrete_VirtualMachine',\n",
+      " 'concrete_VMImage',\n",
+      " 'concrete_ContainerImage',\n",
+      " 'concrete_Network',\n",
+      " 'concrete_Storage',\n",
+      " 'concrete_FunctionAsAService',\n",
+      " 'concrete_ComputingGroup']\n"
+     ]
+    }
+   ],
+   "source": [
+    "keys = list(meta_model.keys())\n",
+    "\n",
+    "pprint(keys)"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3.11.0 ('.venv': poetry)",
+   "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.11.0"
+  },
+  "orig_nbformat": 4,
+  "vscode": {
+   "interpreter": {
+    "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16"
+   }
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/mc_openapi/doml_mc/example_faas.ipynb b/mc_openapi/notebooks/example_faas.ipynb
similarity index 98%
rename from mc_openapi/doml_mc/example_faas.ipynb
rename to mc_openapi/notebooks/example_faas.ipynb
index 642003e845d962002106eaf3b16ba442ca60c5d3..b377059a68a10a6b6c3adbaeb424bfd59e37f9f8 100644
--- a/mc_openapi/doml_mc/example_faas.ipynb
+++ b/mc_openapi/notebooks/example_faas.ipynb
@@ -108,8 +108,8 @@
     "assoc_sort, assoc = mk_association_sort_dict(mm, solver.ctx)\n",
     "attr_sort, attr = mk_attribute_sort_dict(mm, solver.ctx)\n",
     "elem_sort, elem = mk_elem_sort_dict(im, solver.ctx, unbound_elems)\n",
-    "ss_sort, ss = mk_stringsym_sort_dict(im, mm, solver.ctx)\n",
-    "AData = mk_adata_sort(ss_sort, solver.ctx)\n",
+    "str_sort, str = mk_stringsym_sort_dict(im, mm, solver.ctx)\n",
+    "AData = mk_adata_sort(str_sort, solver.ctx)\n",
     "elem_class_f = def_elem_class_f_and_assert_classes(\n",
     "    im,\n",
     "    solver,\n",
@@ -132,7 +132,7 @@
     "    attr_sort,\n",
     "    attr,\n",
     "    AData,\n",
-    "    ss\n",
+    "    str\n",
     ")\n",
     "assoc_rel = def_association_rel(\n",
     "    assoc_sort,\n",
@@ -205,7 +205,7 @@
     "print(\"Number of attributes (IM):\", n_attrs_im)\n",
     "n_assocs_im = sum(len(a) for e in im.values() for a in e.associations.values())\n",
     "print(\"Number of associations (IM):\", n_assocs_im)\n",
-    "print(\"Number of string symbols:\", len(ss))\n",
+    "print(\"Number of string symbols:\", len(str))\n",
     "print(\"Number of IM attribute assertions:\", n_elems)\n",
     "print(\"Number of IM association assertions:\", n_elems ** 2)"
    ]
@@ -340,13 +340,13 @@
     "    Implies(\n",
     "        And(\n",
     "            elem_class_f(softwareComponent) == class_[\"application_SoftwareComponent\"],\n",
-    "            # attr_rel(softwareComponent, attr[\"commons_DOMLElement::name\"], AData.ss(ss[\"web\"]))\n",
+    "            # attr_rel(softwareComponent, attr[\"commons_DOMLElement::name\"], ADatastr(str[\"web\"]))\n",
     "        ),\n",
     "        Exists(\n",
     "            [prop],\n",
     "            And(\n",
     "                elem_class_f(prop) == class_[\"commons_SProperty\"],\n",
-    "                attr_rel(prop, attr[\"commons_Property::key\"], AData.ss(ss[\"source_code\"])),\n",
+    "                attr_rel(prop, attr[\"commons_Property::key\"], ADatastr(str[\"source_code\"])),\n",
     "                assoc_rel(softwareComponent, assoc[\"commons_DOMLElement::annotations\"], prop)\n",
     "            )\n",
     "        )\n",
@@ -476,7 +476,7 @@
     "assn = ForAll(\n",
     "    [web],\n",
     "    Implies(\n",
-    "        attr_rel(web, attr[\"commons_DOMLElement::name\"], AData.ss(ss[\"web\"])),\n",
+    "        attr_rel(web, attr[\"commons_DOMLElement::name\"], ADatastr(str[\"web\"])),\n",
     "        Exists(  # web is deployed on a container hosting a VM with an interface in network n\n",
     "            [deployment, ielem1, ielem2, iface, rule],\n",
     "            And(\n",
@@ -488,7 +488,7 @@
     "                assoc_rel(sg, assoc[\"infrastructure_SecurityGroup::rules\"], rule),\n",
     "                attr_rel(rule, attr[\"infrastructure_Rule::fromPort\"], AData.int(443)),\n",
     "                attr_rel(rule, attr[\"infrastructure_Rule::toPort\"], AData.int(443)),\n",
-    "                attr_rel(rule, attr[\"infrastructure_Rule::kind\"], AData.ss(ss[\"INGRESS\"]))\n",
+    "                attr_rel(rule, attr[\"infrastructure_Rule::kind\"], ADatastr(str[\"INGRESS\"]))\n",
     "            ),\n",
     "        )\n",
     "    )\n",
diff --git a/mc_openapi/doml_mc/example_nginx.ipynb b/mc_openapi/notebooks/example_nginx.ipynb
similarity index 97%
rename from mc_openapi/doml_mc/example_nginx.ipynb
rename to mc_openapi/notebooks/example_nginx.ipynb
index 48fbd363bc85a58249393c5575ba6d2abcb05899..5d6213826f7166dc742f389feb62068f5d34c11d 100644
--- a/mc_openapi/doml_mc/example_nginx.ipynb
+++ b/mc_openapi/notebooks/example_nginx.ipynb
@@ -128,8 +128,8 @@
     "assoc_sort, assoc = mk_association_sort_dict(mm, solver.ctx)\n",
     "attr_sort, attr = mk_attribute_sort_dict(mm, solver.ctx)\n",
     "elem_sort, elem = mk_elem_sort_dict(im, solver.ctx, unbound_elems)\n",
-    "ss_sort, ss = mk_stringsym_sort_dict(im, mm, solver.ctx)\n",
-    "AData = mk_adata_sort(ss_sort, solver.ctx)\n",
+    "str_sort, str = mk_stringsym_sort_dict(im, mm, solver.ctx)\n",
+    "AData = mk_adata_sort(str_sort, solver.ctx)\n",
     "elem_class_f = def_elem_class_f_and_assert_classes(\n",
     "    im,\n",
     "    solver,\n",
@@ -152,7 +152,7 @@
     "    attr_sort,\n",
     "    attr,\n",
     "    AData,\n",
-    "    ss\n",
+    "    str\n",
     ")\n",
     "assoc_rel = def_association_rel(\n",
     "    assoc_sort,\n",
@@ -225,7 +225,7 @@
     "print(\"Number of attributes (IM):\", n_attrs_im)\n",
     "n_assocs_im = sum(len(a) for e in im.values() for a in e.associations.values())\n",
     "print(\"Number of associations (IM):\", n_assocs_im)\n",
-    "print(\"Number of string symbols:\", len(ss))\n",
+    "print(\"Number of string symbols:\", len(str))\n",
     "print(\"Number of IM attribute assertions:\", n_elems)\n",
     "print(\"Number of IM association assertions:\", n_elems ** 2)"
    ]
@@ -324,13 +324,13 @@
     "    Implies(\n",
     "        And(\n",
     "            elem_class_f(softwareComponent) == class_[\"application_SoftwareComponent\"],\n",
-    "            attr_rel(softwareComponent, attr[\"commons_DOMLElement::name\"], AData.ss(ss[\"nginx\"]))\n",
+    "            attr_rel(softwareComponent, attr[\"commons_DOMLElement::name\"], ADatastr(str[\"nginx\"]))\n",
     "        ),\n",
     "        Exists(\n",
     "            [prop],\n",
     "            And(\n",
     "                elem_class_f(prop) == class_[\"commons_SProperty\"],\n",
-    "                attr_rel(prop, attr[\"commons_Property::key\"], AData.ss(ss[\"source_code\"])),\n",
+    "                attr_rel(prop, attr[\"commons_Property::key\"], ADatastr(str[\"source_code\"])),\n",
     "                assoc_rel(softwareComponent, assoc[\"commons_DOMLElement::annotations\"], prop)\n",
     "            )\n",
     "        )\n",
diff --git a/mc_openapi/notebooks/find_missing_requirement.ipynb b/mc_openapi/notebooks/find_missing_requirement.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..8229d3b7ffdee975f835a143300012e2767a126c
--- /dev/null
+++ b/mc_openapi/notebooks/find_missing_requirement.ipynb
@@ -0,0 +1,500 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Finding Missing Requirements\n",
+    "\n",
+    "In this notebook, I try to put together an iterative way to:\n",
+    "1. Add *unbound variables* until the requirement is satisfied\n",
+    "2. Get the *relationships* of the unbound variables\n",
+    "3. Filter these relationships by adding one at a time as a negated constraint\n",
+    "   and check again the model.\n",
+    "4. When we find the one that makes the model unsat, it means we've found the right one.\n",
+    "\n",
+    "#### Goals\n",
+    "- Make the search of finding the correct relationship as fast as possible:\n",
+    "  usually relationships are quite a lot, and we need to iterate them at least a\n",
+    "  couple of times. We can add progressively only the relationships that remain\n",
+    "  after each pass, always one at a time and checking the model again."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from mc_openapi.doml_mc.intermediate_model.metamodel import parse_metamodel, parse_inverse_associations\n",
+    "from mc_openapi.doml_mc.xmi_parser.doml_model import parse_doml_model\n",
+    "from mc_openapi.doml_mc.xmi_parser.doml_model import parse_xmi_model\n",
+    "from mc_openapi.doml_mc import DOMLVersion\n",
+    "from z3 import Solver, Model, DatatypeSortRef, FuncDeclRef, Consts, Const, ForAll, Exists, Implies, And, Or, Not, Bools, sat, unsat\n",
+    "import yaml\n",
+    "\n",
+    "from mc_openapi.doml_mc.z3encoding.metamodel_encoding import (\n",
+    "    def_association_rel,\n",
+    "    def_attribute_rel,\n",
+    "    mk_association_sort_dict,\n",
+    "    mk_attribute_sort_dict,\n",
+    "    mk_class_sort_dict\n",
+    ")\n",
+    "from mc_openapi.doml_mc.z3encoding.im_encoding import (\n",
+    "    assert_im_associations,\n",
+    "    assert_im_attributes,\n",
+    "    def_elem_class_f_and_assert_classes,\n",
+    "    mk_elem_sort_dict,\n",
+    "    mk_stringsym_sort_dict,\n",
+    "    mk_attr_data_sort\n",
+    ")\n",
+    "from mc_openapi.doml_mc.z3encoding.types import Refs\n",
+    "\n",
+    "from itertools import product\n",
+    "from operator import itemgetter"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "with open(\"../assets/doml_meta_v2.0.yaml\") as mmf:\n",
+    "    mmdoc = yaml.load(mmf, yaml.Loader)\n",
+    "mm = parse_metamodel(mmdoc)\n",
+    "inv_assoc = parse_inverse_associations(mmdoc)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**You can change here the input DOML file**"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0.domlx\"\n",
+    "doml_document_path = \"../../tests/doml/v2.0/nginx-openstack_v2.0_wrong_vm_iface.domlx\"\n",
+    "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0_wrong_iface_uniq.domlx\"\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "with open(doml_document_path, \"rb\") as xmif:\n",
+    "    doc = xmif.read()\n",
+    "\n",
+    "im, _ = parse_doml_model(doc, DOMLVersion.V2_0)\n",
+    "doml_xmi = parse_xmi_model(doc, DOMLVersion.V2_0)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We need to initialize each time the Solver context before iterating,\n",
+    "since an unbound variable is an element, and elements are an EnumSort,\n",
+    "and EnumSorts cannot be modified and depend on the solver context.\n",
+    "\n",
+    "The following code is stuff that is already present in the `IntermediateModelChecker`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from typing import Dict\n",
+    "\n",
+    "Context = Dict"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def initialize_solver(\n",
+    "    unbound_elems_quantity: int = 0,\n",
+    "    requirements: list = []\n",
+    ") -> Context:\n",
+    "    ctx = dict()\n",
+    "    \n",
+    "    ctx[\"solver\"] = Solver()\n",
+    "\n",
+    "    ctx[\"class_sort\"], ctx[\"class_\"] = mk_class_sort_dict(mm, ctx[\"solver\"].ctx)\n",
+    "    ctx[\"assoc_sort\"], ctx[\"assoc\"] = mk_association_sort_dict(mm, ctx[\"solver\"].ctx)\n",
+    "    ctx[\"attr_sort\"], ctx[\"attr\"] = mk_attribute_sort_dict(mm, ctx[\"solver\"].ctx)\n",
+    "    ctx[\"str_sort\"], ctx[\"str\"] = mk_stringsym_sort_dict(im, mm, ctx[\"solver\"].ctx)\n",
+    "    ctx[\"attr_data_sort\"] = mk_attr_data_sort(ctx[\"str_sort\"], ctx[\"solver\"].ctx)\n",
+    "\n",
+    "    ctx[\"unbound_elems\"] = [f\"unbound{i}\" for i in range(unbound_elems_quantity)]\n",
+    "    ctx[\"elem_sort\"], ctx[\"elem\"] = mk_elem_sort_dict(im, ctx[\"solver\"].ctx, ctx[\"unbound_elems\"])\n",
+    "\n",
+    "    ctx[\"elem_class_f\"] = def_elem_class_f_and_assert_classes(\n",
+    "        im,\n",
+    "        ctx[\"solver\"],\n",
+    "        ctx[\"elem_sort\"],\n",
+    "        ctx[\"elem\"],\n",
+    "        ctx[\"class_sort\"],\n",
+    "        ctx[\"class_\"]\n",
+    "    )\n",
+    "    # attr_rel :: (elem_sort, attr_sort, attr_data_sort) -> BoolRef\n",
+    "    ctx[\"attr_rel\"] = def_attribute_rel(\n",
+    "        ctx[\"attr_sort\"],\n",
+    "        ctx[\"elem_sort\"],\n",
+    "        ctx[\"attr_data_sort\"]\n",
+    "    )\n",
+    "    assert_im_attributes(\n",
+    "        ctx[\"attr_rel\"],\n",
+    "        ctx[\"solver\"],\n",
+    "        im,\n",
+    "        mm,\n",
+    "        ctx[\"elem\"],\n",
+    "        ctx[\"attr_sort\"],\n",
+    "        ctx[\"attr\"],\n",
+    "        ctx[\"attr_data_sort\"],\n",
+    "        ctx[\"str\"]\n",
+    "    )\n",
+    "\n",
+    "    # assoc_rel :: (elem_sort, assoc_sort, elem_sort) -> BoolRef\n",
+    "    ctx[\"assoc_rel\"] = def_association_rel(\n",
+    "        ctx[\"assoc_sort\"],\n",
+    "        ctx[\"elem_sort\"]\n",
+    "    )\n",
+    "    assert_im_associations(\n",
+    "        ctx[\"assoc_rel\"],\n",
+    "        ctx[\"solver\"],\n",
+    "        {k: v for k, v in im.items() if k not in ctx[\"unbound_elems\"]},\n",
+    "        ctx[\"elem\"],\n",
+    "        ctx[\"assoc_sort\"],\n",
+    "        ctx[\"assoc\"],\n",
+    "    )\n",
+    "\n",
+    "    # Add requirements\n",
+    "    for req in requirements:\n",
+    "        req(ctx)\n",
+    "\n",
+    "    return ctx"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def req_every_vm_has_iface(ctx: Context):    \n",
+    "    vm, iface = Consts(\"vm iface\", ctx[\"elem_sort\"])\n",
+    "    vmIfaceAssertion = ForAll(\n",
+    "        [vm],\n",
+    "        Implies(\n",
+    "            ctx[\"elem_class_f\"](vm) == ctx[\"class_\"][\"infrastructure_VirtualMachine\"],\n",
+    "            Exists(\n",
+    "                [iface],\n",
+    "                And(\n",
+    "                    ctx[\"assoc_rel\"](vm, ctx[\"assoc\"][\"infrastructure_ComputingNode::ifaces\"], iface)\n",
+    "                )\n",
+    "            )\n",
+    "        )\n",
+    "    )\n",
+    "    ctx[\"solver\"].assert_and_track(vmIfaceAssertion, \"vm_iface\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def req_every_iface_has_a_secgroup(ctx):\n",
+    "    sg, iface = Consts(\"sg iface\", ctx[\"elem_sort\"])\n",
+    "    vmIfaceSecGroupAssertion = ForAll(\n",
+    "        [sg],\n",
+    "        Implies(\n",
+    "            ctx[\"elem_class_f\"](sg) == ctx[\"class_\"][\"infrastructure_SecurityGroup\"],\n",
+    "            Exists([iface], \n",
+    "                ctx[\"assoc_rel\"](iface, ctx[\"assoc\"][\"infrastructure_NetworkInterface::associated\"], sg)\n",
+    "            )\n",
+    "        )\n",
+    "    )\n",
+    "    ctx[\"solver\"].assert_and_track(vmIfaceSecGroupAssertion, \"vm_secgroup\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# There are no duplicated interfaces.\n",
+    "def req_iface_uniq(ctx):\n",
+    "    endPointAttr = ctx[\"attr\"][\"infrastructure_NetworkInterface::endPoint\"]\n",
+    "    ni1, ni2 = Consts(\"ni1, ni2\", ctx[\"elem_sort\"])\n",
+    "    value = Const(\"value\", ctx[\"attr_data_sort\"])\n",
+    "    uniqueIfaceAssertion = And(\n",
+    "        ctx[\"attr_rel\"](ni1, endPointAttr, value),\n",
+    "        ctx[\"attr_rel\"](ni2, endPointAttr, value),\n",
+    "        ni1 != ni2,\n",
+    "    )\n",
+    "    ctx[\"solver\"].assert_and_track(uniqueIfaceAssertion, \"unique_iface\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 41,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def check_with_ubvars(ubvars_n: int = 0, requirements: list = []) -> Context:\n",
+    "    ctx = initialize_solver(ubvars_n, requirements)\n",
+    "    solver = ctx[\"solver\"]\n",
+    "\n",
+    "    res = solver.check()\n",
+    "\n",
+    "    if res == sat:\n",
+    "        print(f\"Sat with {ubvars_n} unbounded variables\")\n",
+    "        return ctx\n",
+    "    elif res == unsat:\n",
+    "        # print(f\"ubvars={ubvars_n}; UNSAT_CORE:\")\n",
+    "        # print(solver.unsat_core())\n",
+    "        print(f\"Increasing unbound vars to {ubvars_n + 1}\")\n",
+    "        return check_with_ubvars(ubvars_n + 1, requirements=requirements)\n",
+    "    else:\n",
+    "        raise RuntimeError(\"It took too long to decide.\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "REQUIREMENTS = [\n",
+    "    req_every_vm_has_iface,\n",
+    "    req_every_iface_has_a_secgroup,\n",
+    "    req_iface_uniq\n",
+    "]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Increasing unbound vars to 1\n",
+      "Increasing unbound vars to 2\n",
+      "Sat with 2 unbounded variables\n"
+     ]
+    }
+   ],
+   "source": [
+    "solved_ctx = check_with_ubvars(requirements=REQUIREMENTS)\n",
+    "solved_model = solved_ctx[\"solver\"].model()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def get_ubvars_and_assoc(ctx: Context, model: Model):\n",
+    "    elem, assoc, assoc_rel, unbound_elems = itemgetter(\"elem\", \"assoc\", \"assoc_rel\", \"unbound_elems\")(ctx)\n",
+    "\n",
+    "    return [ ((e1n, e1), a, (e2n, e2)) \n",
+    "        for (e1n, e1), a, (e2n, e2) in product(elem.items(), assoc.values(), elem.items()) \n",
+    "        if (e1n in unbound_elems or e2n in unbound_elems) and model.eval(assoc_rel(e1, a, e2))\n",
+    "    ]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def pretty_ubvar_assoc(assoc):\n",
+    "    (e1n, e1), a, (e2n, e2) = assoc\n",
+    "    tokens = str(str(e1) + \" \" + str(a) + \" \" + str(e2)).split()\n",
+    "    ret_str = \"\"\n",
+    "    for token in tokens:\n",
+    "        if token[0:4] == \"elem\":\n",
+    "            value = im.get(token)\n",
+    "            ret_str += f\"{value.class_} ({value.user_friendly_name})\" if value else f\"<'{token}' not found>\"\n",
+    "        else:\n",
+    "            ret_str += token\n",
+    "        ret_str += \" \"\n",
+    "    return ret_str.strip()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "As we can see, there are many associations that involve the unbound variable `unbound0`.\n",
+    "We can see that between them, there is the one we really want:\n",
+    "\n",
+    "`infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound0`\n",
+    "\n",
+    "We now need to filter out all the others, by taking one of these lines at a time, and adding it as a negated constraint.\n",
+    "\n",
+    "NOTE: It appears that the list is not deterministic. Sometimes at the end there are associations that start from `unbound0`, sometimes there is none. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 46,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ubvars_and_assoc = get_ubvars_and_assoc(solved_ctx, solved_model)\n",
+    "# print(\"\\n\".join([pretty_ubvar_assoc(assoc) for assoc in ubvars_and_assoc]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 52,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "-----------------------------------------\n",
+      "\tAdd constraint Not(infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound0)\n"
+     ]
+    },
+    {
+     "ename": "Z3Exception",
+     "evalue": "True, False or Z3 Boolean expression expected. Received [__neg_{e1_name}_{str(a)}_{e2_name}] of type <class 'list'>",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mZ3Exception\u001b[0m                               Traceback (most recent call last)",
+      "Cell \u001b[0;32mIn [52], line 44\u001b[0m\n\u001b[1;32m     40\u001b[0m             \u001b[39mprint\u001b[39m(\u001b[39m\"\u001b[39m\u001b[39m\\t\u001b[39;00m\u001b[39m\\t\u001b[39;00m\u001b[39m\"\u001b[39m \u001b[39m+\u001b[39m \u001b[39m\"\u001b[39m\u001b[39m\\n\u001b[39;00m\u001b[39m\\t\u001b[39;00m\u001b[39m\\t\u001b[39;00m\u001b[39m\"\u001b[39m\u001b[39m.\u001b[39mjoin([pretty_ubvar_assoc(assoc) \u001b[39mfor\u001b[39;00m assoc \u001b[39min\u001b[39;00m ubvars_and_assoc[\u001b[39m1\u001b[39m:]]))\n\u001b[1;32m     41\u001b[0m         \u001b[39mreturn\u001b[39;00m [\u001b[39m*\u001b[39m\u001b[39mset\u001b[39m([assoc] \u001b[39m+\u001b[39m thin_ubvars_and_assoc(ctx, ubvars_and_assoc[\u001b[39m1\u001b[39m:]))]\n\u001b[0;32m---> 44\u001b[0m assoc_to_implement \u001b[39m=\u001b[39m thin_ubvars_and_assoc(solved_ctx, ubvars_and_assoc)\n",
+      "Cell \u001b[0;32mIn [52], line 18\u001b[0m, in \u001b[0;36mthin_ubvars_and_assoc\u001b[0;34m(ctx, ubvars_and_assoc)\u001b[0m\n\u001b[1;32m     16\u001b[0m \u001b[39m# ctx[\"solver\"].assert_and_track(Not(assoc_rel), f\"__neg_{e1_name}_{str(a)}_{e2_name}\")\u001b[39;00m\n\u001b[1;32m     17\u001b[0m x \u001b[39m=\u001b[39m Bools(\u001b[39m\"\u001b[39m\u001b[39m__neg_\u001b[39m\u001b[39m{e1_name}\u001b[39;00m\u001b[39m_\u001b[39m\u001b[39m{\u001b[39m\u001b[39mstr(a)}_\u001b[39m\u001b[39m{e2_name}\u001b[39;00m\u001b[39m\"\u001b[39m)\n\u001b[0;32m---> 18\u001b[0m ctx[\u001b[39m\"\u001b[39m\u001b[39msolver\u001b[39m\u001b[39m\"\u001b[39m]\u001b[39m.\u001b[39madd(Implies(x, Not(assoc_rel)))\n\u001b[1;32m     20\u001b[0m res \u001b[39m=\u001b[39m ctx[\u001b[39m\"\u001b[39m\u001b[39msolver\u001b[39m\u001b[39m\"\u001b[39m]\u001b[39m.\u001b[39mcheck()\n\u001b[1;32m     21\u001b[0m \u001b[39mif\u001b[39;00m res \u001b[39m==\u001b[39m sat:\n",
+      "File \u001b[0;32m~/Projects/piacere-model-checker/.venv/lib/python3.10/site-packages/z3/z3.py:1785\u001b[0m, in \u001b[0;36mImplies\u001b[0;34m(a, b, ctx)\u001b[0m\n\u001b[1;32m   1783\u001b[0m ctx \u001b[39m=\u001b[39m _get_ctx(_ctx_from_ast_arg_list([a, b], ctx))\n\u001b[1;32m   1784\u001b[0m s \u001b[39m=\u001b[39m BoolSort(ctx)\n\u001b[0;32m-> 1785\u001b[0m a \u001b[39m=\u001b[39m s\u001b[39m.\u001b[39;49mcast(a)\n\u001b[1;32m   1786\u001b[0m b \u001b[39m=\u001b[39m s\u001b[39m.\u001b[39mcast(b)\n\u001b[1;32m   1787\u001b[0m \u001b[39mreturn\u001b[39;00m BoolRef(Z3_mk_implies(ctx\u001b[39m.\u001b[39mref(), a\u001b[39m.\u001b[39mas_ast(), b\u001b[39m.\u001b[39mas_ast()), ctx)\n",
+      "File \u001b[0;32m~/Projects/piacere-model-checker/.venv/lib/python3.10/site-packages/z3/z3.py:1528\u001b[0m, in \u001b[0;36mBoolSortRef.cast\u001b[0;34m(self, val)\u001b[0m\n\u001b[1;32m   1526\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m is_expr(val):\n\u001b[1;32m   1527\u001b[0m     msg \u001b[39m=\u001b[39m \u001b[39m\"\u001b[39m\u001b[39mTrue, False or Z3 Boolean expression expected. Received \u001b[39m\u001b[39m%s\u001b[39;00m\u001b[39m of type \u001b[39m\u001b[39m%s\u001b[39;00m\u001b[39m\"\u001b[39m\n\u001b[0;32m-> 1528\u001b[0m     _z3_assert(is_expr(val), msg \u001b[39m%\u001b[39;49m (val, \u001b[39mtype\u001b[39;49m(val)))\n\u001b[1;32m   1529\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39meq(val\u001b[39m.\u001b[39msort()):\n\u001b[1;32m   1530\u001b[0m     _z3_assert(\u001b[39mself\u001b[39m\u001b[39m.\u001b[39meq(val\u001b[39m.\u001b[39msort()), \u001b[39m\"\u001b[39m\u001b[39mValue cannot be converted into a Z3 Boolean value\u001b[39m\u001b[39m\"\u001b[39m)\n",
+      "File \u001b[0;32m~/Projects/piacere-model-checker/.venv/lib/python3.10/site-packages/z3/z3.py:107\u001b[0m, in \u001b[0;36m_z3_assert\u001b[0;34m(cond, msg)\u001b[0m\n\u001b[1;32m    105\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m_z3_assert\u001b[39m(cond, msg):\n\u001b[1;32m    106\u001b[0m     \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m cond:\n\u001b[0;32m--> 107\u001b[0m         \u001b[39mraise\u001b[39;00m Z3Exception(msg)\n",
+      "\u001b[0;31mZ3Exception\u001b[0m: True, False or Z3 Boolean expression expected. Received [__neg_{e1_name}_{str(a)}_{e2_name}] of type <class 'list'>"
+     ]
+    }
+   ],
+   "source": [
+    "def thin_ubvars_and_assoc(ctx: Context, ubvars_and_assoc: list):\n",
+    "    \"\"\"Returns a tuple where the first item is\n",
+    "    \"\"\"\n",
+    "    if not ubvars_and_assoc:\n",
+    "        return []\n",
+    "\n",
+    "\n",
+    "    (e1_name, e1), a, (e2_name, e2) = assoc = ubvars_and_assoc[0]\n",
+    "    assoc_rel = ctx[\"assoc_rel\"](e1, a, e2)\n",
+    "    \n",
+    "    print(\"-----------------------------------------\")\n",
+    "\n",
+    "    # Add negated constraint\n",
+    "    print(f\"\\tAdd constraint Not({pretty_ubvar_assoc(ubvars_and_assoc[0])})\")\n",
+    "    ctx[\"solver\"].push()\n",
+    "    # ctx[\"solver\"].assert_and_track(Not(assoc_rel), f\"__neg_{e1_name}_{str(a)}_{e2_name}\")\n",
+    "    ctx[\"solver\"].add(Not(assoc_rel))\n",
+    "    \n",
+    "    res = ctx[\"solver\"].check()\n",
+    "    if res == sat:\n",
+    "        print(\"SAT:\\tAdding one more constraint and trying again\")\n",
+    "        # Get new ubvars_and_assoc\n",
+    "        model = ctx[\"solver\"].model()\n",
+    "        thinned_ubvars_and_assoc = get_ubvars_and_assoc(ctx, model)\n",
+    "        \n",
+    "        # Print table showing the diff\n",
+    "        from difflib import context_diff\n",
+    "        uvar_as_text = lambda input: [pretty_ubvar_assoc(assoc) for assoc in input]\n",
+    "        print(\"\\n\".join([a for a in context_diff(uvar_as_text(ubvars_and_assoc), uvar_as_text(thinned_ubvars_and_assoc), lineterm=\"\", fromfile='Before', tofile=\"After\")]))\n",
+    "\n",
+    "        # Iterate\n",
+    "        return thin_ubvars_and_assoc(ctx, thinned_ubvars_and_assoc)\n",
+    "    else:\n",
+    "        print(\"UNSAT\\tLast constraint was the association we are looking for!\")\n",
+    "        ctx[\"solver\"].pop()\n",
+    "        \n",
+    "        if ubvars_and_assoc[1:]:\n",
+    "            print(\"\\tIterating over\")\n",
+    "            print(\"\\t\\t\" + \"\\n\\t\\t\".join([pretty_ubvar_assoc(assoc) for assoc in ubvars_and_assoc[1:]]))\n",
+    "        return [*set([assoc] + thin_ubvars_and_assoc(ctx, ubvars_and_assoc[1:]))]\n",
+    "\n",
+    "\n",
+    "assoc_to_implement = thin_ubvars_and_assoc(solved_ctx, ubvars_and_assoc)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "infrastructure_VirtualMachine (vm1) infrastructure_ComputingNode::ifaces unbound1\n",
+      "unbound1 infrastructure_NetworkInterface::associated infrastructure_SecurityGroup (sg)\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(\"\\n\".join([pretty_ubvar_assoc(assoc) for assoc in assoc_to_implement]))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "From here, we should then add this in the Intermediate Model, and then in the ECore (?) to generate the DOML file somehow.\n",
+    "\n",
+    "We can then provide the new file, or a diff to be patched onto the original?"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3.10.7 ('.venv': poetry)",
+   "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.10.8"
+  },
+  "orig_nbformat": 4,
+  "vscode": {
+   "interpreter": {
+    "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16"
+   }
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/mc_openapi/notebooks/find_missing_requirement_with_attrs.ipynb b/mc_openapi/notebooks/find_missing_requirement_with_attrs.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..a30bc463263626ab2c0341274b13f75b22d171ef
--- /dev/null
+++ b/mc_openapi/notebooks/find_missing_requirement_with_attrs.ipynb
@@ -0,0 +1,773 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Finding Missing Requirements (with Attributes)\n",
+    "\n",
+    "In this notebook, I try to put together an iterative way to:\n",
+    "1. Add *unbound variables* until the requirement is satisfied\n",
+    "2. Get the *relationships* of the unbound variables\n",
+    "3. Filter these relationships by adding one at a time as a negated constraint\n",
+    "   and check again the model.\n",
+    "4. When we find the one that makes the model unsat, it means we've found the right one.\n",
+    "\n",
+    "#### Goals\n",
+    "- Make the search of finding the correct relationship as fast as possible:\n",
+    "  usually relationships are quite a lot, and we need to iterate them at least a\n",
+    "  couple of times. We can add progressively only the relationships that remain\n",
+    "  after each pass, always one at a time and checking the model again."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from itertools import product\n",
+    "from operator import itemgetter\n",
+    "\n",
+    "import yaml\n",
+    "from z3 import (And, Const, Consts, DatatypeSortRef, Exists, ForAll,\n",
+    "                FuncDeclRef, Implies, Model, Not, Or, Solver, sat, unsat)\n",
+    "\n",
+    "from mc_openapi.doml_mc import DOMLVersion\n",
+    "from mc_openapi.doml_mc.intermediate_model.metamodel import (\n",
+    "    parse_inverse_associations, parse_metamodel)\n",
+    "from mc_openapi.doml_mc.xmi_parser.doml_model import (parse_doml_model,\n",
+    "                                                      parse_xmi_model)\n",
+    "from mc_openapi.doml_mc.z3encoding.im_encoding import (\n",
+    "    assert_im_associations, assert_im_attributes,\n",
+    "    def_elem_class_f_and_assert_classes, mk_attr_data_sort, mk_elem_sort_dict,\n",
+    "    mk_stringsym_sort_dict)\n",
+    "from mc_openapi.doml_mc.z3encoding.metamodel_encoding import (\n",
+    "    def_association_rel, def_attribute_rel, mk_association_sort_dict,\n",
+    "    mk_attribute_sort_dict, mk_class_sort_dict)\n",
+    "from mc_openapi.doml_mc.z3encoding.types import Refs"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "with open(\"../assets/doml_meta_v2.0.yaml\") as mmf:\n",
+    "    mmdoc = yaml.load(mmf, yaml.Loader)\n",
+    "mm = parse_metamodel(mmdoc)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**You can change here the input DOML file**"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0.domlx\"\n",
+    "# doml_document_path = \"../../tests/doml/v2.0/nginx-openstack_v2.0_wrong_vm_iface.domlx\"\n",
+    "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.0_wrong_iface_uniq.domlx\"\n",
+    "# doml_document_path = \"../../tests/doml/saas_no_https_rule.domlx\"\n",
+    "# doml_document_path = \"../../tests/doml/saas_https_no_attrs.domlx\"\n",
+    "doml_document_path = \"../../tests/doml/openstack_template.domlx\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "with open(doml_document_path, \"rb\") as xmif:\n",
+    "    doc = xmif.read()\n",
+    "\n",
+    "im, _ = parse_doml_model(doc, DOMLVersion.V2_0)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We need to initialize each time the Solver context before iterating,\n",
+    "since an unbound variable is an element, and elements are an EnumSort,\n",
+    "and EnumSorts cannot be modified and depend on the solver context.\n",
+    "\n",
+    "The following code is stuff that is already present in the `IntermediateModelChecker`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 41,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from typing import Dict\n",
+    "\n",
+    "Context = Dict"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from mc_openapi.doml_mc.intermediate_model.metamodel import get_mangled_attribute_defaults\n",
+    "\n",
+    "\n",
+    "def initialize_solver(\n",
+    "    unbound_elems_quantity: int = 0,\n",
+    "    unbound_values_quantity: int = 0,\n",
+    "    requirements: list = []\n",
+    ") -> Context:\n",
+    "    ctx = dict()\n",
+    "    \n",
+    "    ctx[\"solver\"] = Solver()\n",
+    "\n",
+    "    ctx[\"class_sort\"], ctx[\"class_\"] = mk_class_sort_dict(mm, ctx[\"solver\"].ctx)\n",
+    "    ctx[\"assoc_sort\"], ctx[\"assoc\"] = mk_association_sort_dict(mm, ctx[\"solver\"].ctx)\n",
+    "    ctx[\"attr_sort\"], ctx[\"attr\"] = mk_attribute_sort_dict(mm, ctx[\"solver\"].ctx)\n",
+    "    ctx[\"str_sort\"], ctx[\"str\"] = mk_stringsym_sort_dict(im, mm, ctx[\"solver\"].ctx)\n",
+    "    ctx[\"attr_data_sort\"] = mk_attr_data_sort(ctx[\"str_sort\"], ctx[\"solver\"].ctx)\n",
+    "\n",
+    "    ctx[\"unbound_elems\"] = [f\"unbound_elem_{i}\" for i in range(unbound_elems_quantity)]\n",
+    "\n",
+    "    # Takes a list of strings and creates an Enum out of 'em\n",
+    "    ctx[\"elem_sort\"], ctx[\"elem\"] = mk_elem_sort_dict(im, ctx[\"solver\"].ctx, ctx[\"unbound_elems\"])\n",
+    "\n",
+    "    ub_val_names = [f\"unbound_val_{i}\" for i in range(unbound_values_quantity)]\n",
+    "    ctx[\"unbound_values\"] = {\n",
+    "        name : ctx[\"attr_data_sort\"].placeholder for name in ub_val_names\n",
+    "    }\n",
+    "    # Examples of values that can go in unbound_values:\n",
+    "    # ctx[\"attr_data_sort\"].int(42), # ok\n",
+    "    # ctx[\"attr_data_sort\"].bool(True), # ok\n",
+    "    # ctx[\"attr_data_sort\"].str(\"x\"), # cant do: it accept a ctx[\"str\"][<str_key>] as input\n",
+    "    # Const(\"x\", ctx[\"attr_data_sort\"]) # cant do: it is a symbolic value that cannot be converted to a BoolRef expression\n",
+    "\n",
+    "    ctx[\"elem_class_f\"] = def_elem_class_f_and_assert_classes(\n",
+    "        im,\n",
+    "        ctx[\"solver\"],\n",
+    "        ctx[\"elem_sort\"],\n",
+    "        ctx[\"elem\"],\n",
+    "        ctx[\"class_sort\"],\n",
+    "        ctx[\"class_\"]\n",
+    "    )\n",
+    "    \n",
+    "    # attr_rel :: (elem_sort, attr_sort, attr_data_sort) -> BoolRef\n",
+    "    ctx[\"attr_rel\"] = def_attribute_rel(\n",
+    "        ctx[\"attr_sort\"],\n",
+    "        ctx[\"elem_sort\"],\n",
+    "        ctx[\"attr_data_sort\"]\n",
+    "    )\n",
+    "\n",
+    "    assert_im_attributes(\n",
+    "        ctx[\"attr_rel\"],\n",
+    "        ctx[\"solver\"],\n",
+    "        im,\n",
+    "        mm,\n",
+    "        ctx[\"elem\"],\n",
+    "        ctx[\"attr_sort\"],\n",
+    "        ctx[\"attr\"],\n",
+    "        ctx[\"attr_data_sort\"],\n",
+    "        ctx[\"str\"]\n",
+    "    )\n",
+    "\n",
+    "    # assoc_rel :: (elem_sort, assoc_sort, elem_sort) -> BoolRef\n",
+    "    ctx[\"assoc_rel\"] = def_association_rel(\n",
+    "        ctx[\"assoc_sort\"],\n",
+    "        ctx[\"elem_sort\"]\n",
+    "    )\n",
+    "    \n",
+    "    assert_im_associations(\n",
+    "        ctx[\"assoc_rel\"],\n",
+    "        ctx[\"solver\"],\n",
+    "        {k: v for k, v in im.items() if k not in ctx[\"unbound_elems\"]},\n",
+    "        ctx[\"elem\"],\n",
+    "        ctx[\"assoc_sort\"],\n",
+    "        ctx[\"assoc\"],\n",
+    "    )\n",
+    "\n",
+    "    # Add requirements\n",
+    "    for req in requirements:\n",
+    "        req(ctx)\n",
+    "\n",
+    "    return ctx"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def req_every_vm_has_iface(ctx: Context):    \n",
+    "    vm, iface = Consts(\"vm iface\", ctx[\"elem_sort\"])\n",
+    "    vmIfaceAssertion = ForAll(\n",
+    "        [vm],\n",
+    "        Implies(\n",
+    "            ctx[\"elem_class_f\"](vm) == ctx[\"class_\"][\"infrastructure_VirtualMachine\"],\n",
+    "            Exists(\n",
+    "                [iface],\n",
+    "                And(\n",
+    "                    ctx[\"assoc_rel\"](vm, ctx[\"assoc\"][\"infrastructure_ComputingNode::ifaces\"], iface)\n",
+    "                )\n",
+    "            )\n",
+    "        )\n",
+    "    )\n",
+    "    ctx[\"solver\"].assert_and_track(vmIfaceAssertion, \"vm_iface\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def req_every_vm_has_cpucount(ctx: Context):    \n",
+    "    vm = Const(\"vm\", ctx[\"elem_sort\"])\n",
+    "    CpuCount = Const(\"cpucount\", ctx[\"attr_data_sort\"])\n",
+    "    vmIfaceAssertion = ForAll(\n",
+    "        [vm],\n",
+    "        Implies(\n",
+    "            ctx[\"elem_class_f\"](vm) == ctx[\"class_\"][\"infrastructure_VirtualMachine\"],\n",
+    "            Exists(\n",
+    "                [CpuCount],\n",
+    "                And(\n",
+    "                    ctx[\"attr_rel\"](vm, ctx[\"attr\"][\"infrastructure_ComputingNode::cpu_count\"], CpuCount)\n",
+    "                )\n",
+    "            )\n",
+    "        )\n",
+    "    )\n",
+    "    ctx[\"solver\"].assert_and_track(vmIfaceAssertion, \"vm_cpucount\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def req_every_iface_has_a_secgroup(ctx):\n",
+    "    sg, iface = Consts(\"sg iface\", ctx[\"elem_sort\"])\n",
+    "    vmIfaceSecGroupAssertion = ForAll(\n",
+    "        [sg],\n",
+    "        Implies(\n",
+    "            ctx[\"elem_class_f\"](sg) == ctx[\"class_\"][\"infrastructure_SecurityGroup\"],\n",
+    "            Exists([iface], \n",
+    "                ctx[\"assoc_rel\"](iface, ctx[\"assoc\"][\"infrastructure_NetworkInterface::associated\"], sg)\n",
+    "            )\n",
+    "        )\n",
+    "    )\n",
+    "    ctx[\"solver\"].assert_and_track(vmIfaceSecGroupAssertion, \"vm_secgroup\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 46,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def req_iface_uniq(ctx):\n",
+    "    endPointAttr = ctx[\"attr\"][\"infrastructure_NetworkInterface::endPoint\"]\n",
+    "    ni1, ni2 = Consts(\"ni1 ni2\", ctx[\"elem_sort\"])\n",
+    "    value = Const(\"value\", ctx[\"attr_data_sort\"])\n",
+    "    uniqueIfaceAssertion = And(\n",
+    "        ctx[\"attr_rel\"](ni1, endPointAttr, value),\n",
+    "        ctx[\"attr_rel\"](ni2, endPointAttr, value),\n",
+    "        ni1 != ni2,\n",
+    "    )\n",
+    "    ctx[\"solver\"].assert_and_track(uniqueIfaceAssertion, \"unique_iface\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 47,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def req_external_services_must_have_https(ctx):\n",
+    "    saas, sw_iface, sw_comp, deployment, ielem, net_iface, sec_group, rule = Consts(\"saas, sw_iface, sw_comp, deployment, ielem, net_iface, sec_group, rule\", ctx[\"elem_sort\"])\n",
+    "    assertion = ForAll(\n",
+    "        [saas, sec_group, sw_iface, sw_comp, deployment, ielem, net_iface],\n",
+    "        Implies(\n",
+    "            And(\n",
+    "                ctx[\"elem_class_f\"](saas) == ctx[\"class_\"][\"application_SaaS\"],\n",
+    "                ctx[\"elem_class_f\"](sec_group) == ctx[\"class_\"][\"infrastructure_SecurityGroup\"],\n",
+    "                ctx[\"assoc_rel\"](saas, ctx[\"assoc\"][\"application_SaaS::exposedInterfaces\"], sw_iface),\n",
+    "                ctx[\"assoc_rel\"](sw_comp, ctx[\"assoc\"][\"application_SoftwareComponent::consumedInterfaces\"], sw_iface),\n",
+    "                ctx[\"assoc_rel\"](deployment, ctx[\"assoc\"][\"commons_Deployment::component\"], sw_comp),\n",
+    "                ctx[\"assoc_rel\"](deployment, ctx[\"assoc\"][\"commons_Deployment::node\"], ielem),\n",
+    "                ctx[\"assoc_rel\"](ielem, ctx[\"assoc\"][\"infrastructure_ComputingNode::ifaces\"], net_iface),\n",
+    "                ctx[\"assoc_rel\"](net_iface, ctx[\"assoc\"][\"infrastructure_NetworkInterface::associated\"], sec_group),\n",
+    "                ctx[\"assoc_rel\"](sec_group, ctx[\"assoc\"][\"infrastructure_SecurityGroup::rules\"], rule),\n",
+    "            ),\n",
+    "            Exists([rule],\n",
+    "                And(\n",
+    "                    # Every node that contacts an external service should belong to a security group implementing HTTPS\n",
+    "                    ctx[\"attr_rel\"](rule, ctx[\"attr\"][\"infrastructure_Rule::fromPort\"], ctx[\"attr_data_sort\"].int(443)),\n",
+    "                    ctx[\"attr_rel\"](rule, ctx[\"attr\"][\"infrastructure_Rule::toPort\"], ctx[\"attr_data_sort\"].int(443)),\n",
+    "                    ctx[\"attr_rel\"](rule, ctx[\"attr\"][\"infrastructure_Rule::kind\"], ctx[\"attr_data_sort\"].str(ctx[\"str\"][\"INGRESS\"]))\n",
+    "                )\n",
+    "            )\n",
+    "        )\n",
+    "    )\n",
+    "    ctx[\"solver\"].assert_and_track(assertion, \"ext_service_https\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### REMEMBER TO ADD REQUIREMENTS TO THE LIST!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 48,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "REQUIREMENTS = [\n",
+    "    req_every_vm_has_iface,\n",
+    "    # req_every_vm_has_cpucount\n",
+    "    # req_every_iface_has_a_secgroup,\n",
+    "    # req_iface_uniq,\n",
+    "    # req_external_services_must_have_https\n",
+    "]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 49,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def check_iteratively(ubelems_n: int = 0, ubvals_n: int = 0, requirements: list = [], curr_try: int = 0, max_tries: int = 10) -> Context:\n",
+    "    if curr_try > max_tries:\n",
+    "        raise RuntimeError(\"Max tries exceeded.\")\n",
+    "\n",
+    "    ctx = initialize_solver(ubelems_n, ubvals_n, requirements)\n",
+    "    solver = ctx[\"solver\"]\n",
+    "\n",
+    "    res = solver.check()\n",
+    "\n",
+    "    if res == sat:\n",
+    "        print(\"\\033[92m\" + f\"<Sat>\\tubelems_n={ubelems_n}, ubvals_n={ubvals_n}\" + \"\\033[0m\")\n",
+    "        return ctx\n",
+    "    elif res == unsat:\n",
+    "        print(\"\\033[91m\" + f\"<Unsat>\\tubelems_n={ubelems_n}, ubvals_n={ubvals_n}\" + \"\\033[0m\")\n",
+    "        if ubelems_n > ubvals_n:\n",
+    "            new_ubvals_n = ubvals_n * 2 if ubvals_n >= 1 else 1\n",
+    "            return check_iteratively(ubelems_n, new_ubvals_n, requirements, curr_try + 1, max_tries)\n",
+    "            # TODO: Choose which goes first\n",
+    "        elif ubelems_n <= ubvals_n:\n",
+    "            new_ubelems_n = ubelems_n * 2 if ubelems_n >= 1 else 1\n",
+    "            return check_iteratively(new_ubelems_n, ubvals_n, requirements, curr_try + 1, max_tries)\n",
+    "    else: # res == dontknow\n",
+    "        raise RuntimeError(\"It took too long to decide.\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 50,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\u001b[91m<Unsat>\tubelems_n=0, ubvals_n=0\u001b[0m\n",
+      "\u001b[92m<Sat>\tubelems_n=1, ubvals_n=0\u001b[0m\n"
+     ]
+    }
+   ],
+   "source": [
+    "solved_ctx = check_iteratively(0, 0, requirements=REQUIREMENTS)\n",
+    "\n",
+    "solved_model = solved_ctx[\"solver\"].model()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 51,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def get_ubelems_and_assoc(ctx: Context, model: Model):\n",
+    "    elem, assoc, assoc_rel, unbound_elems = itemgetter(\"elem\", \"assoc\", \"assoc_rel\", \"unbound_elems\")(ctx)\n",
+    "\n",
+    "    return [ ((e1n, e1), a, (e2n, e2)) \n",
+    "        for (e1n, e1), a, (e2n, e2) in product(elem.items(), assoc.values(), elem.items()) \n",
+    "        if (e1n in unbound_elems or e2n in unbound_elems) and model.eval(assoc_rel(e1, a, e2))\n",
+    "    ]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 52,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def get_ubvals_and_attr(ctx: Context, model: Model):\n",
+    "    elem, attr, attr_rel, unbound_values = itemgetter(\"elem\", \"attr\", \"attr_rel\", \"unbound_values\")(ctx)\n",
+    "\n",
+    "    return [ ((elem_k, elem_v), a, (ubval_k, ubval_v))\n",
+    "        for (elem_k, elem_v), a, (ubval_k, ubval_v) in product(elem.items(), attr.values(), unbound_values.items())\n",
+    "        if model.eval(attr_rel(elem_v, a, ubval_v))\n",
+    "    ]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 53,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Utility code to print the names of associations and attributes in a human-readable way\n",
+    "def pretty_ubelems_assoc(assoc):\n",
+    "    (elem_1_k, elem_1_v), a, (elem_2_k, elem_2_v) = assoc\n",
+    "    elem_1 = im.get(elem_1_k)\n",
+    "    if elem_1:\n",
+    "        elem_1_name = f\"{elem_1.class_} ({elem_1.user_friendly_name})\" if elem_1_k[0:4] == \"elem\" else f\"<'{elem_1_k}' not found>\"\n",
+    "    else:\n",
+    "        elem_1_name = elem_1_k\n",
+    "    \n",
+    "    elem_2 = im.get(elem_2_k)\n",
+    "    if elem_2:\n",
+    "        elem_2_name = f\"{elem_2.class_} ({elem_2.user_friendly_name})\" if elem_2_k[0:4] == \"elem\" else f\"<'{elem_2_k}' not found>\"\n",
+    "    else:\n",
+    "        elem_2_name = elem_2_k\n",
+    "    \n",
+    "    assoc_name = str(a)\n",
+    "\n",
+    "    return f\"{elem_1_name:<50s} {assoc_name:<60s} {elem_2_name:<30s}\"\n",
+    "\n",
+    "def pretty_ubvals_attrs(attrs):\n",
+    "    (elem_k, elem_v), a, (ubval_k, ubval_v) = attrs\n",
+    "\n",
+    "    elem_1 = im.get(elem_k)\n",
+    "    if elem_1:\n",
+    "        elem_1_name = f\"{elem_1.class_} ({elem_1.user_friendly_name})\" if elem_k[0:4] == \"elem\" else f\"<'{elem_k}' not found>\"\n",
+    "    else:\n",
+    "        elem_1_name = elem_k\n",
+    "\n",
+    "    attr_name = str(a)\n",
+    "\n",
+    "    val_name = str(ubval_k)\n",
+    "\n",
+    "    return f\"{elem_1_name:<50s} {attr_name:<60s} {val_name:<30s}\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 54,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "infrastructure_VirtualMachine (vm1)                commons_Property::reference                                  unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                application_SoftwareComponent::exposedInterfaces             unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                application_SoftwareComponent::consumedInterfaces            unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                application_SaaS::exposedInterfaces                          unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::generators               unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::storages                 unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::faas                     unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::credentials              unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::groups                   unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::securityGroups           unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::networks                 unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::ifaces                         unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::location                       unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::credentials                    unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::group                          unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_VirtualMachine::generatedFrom                 unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_Container::generatedFrom                      unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_Container::hosts                              unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_VMImage::generatedVMs                         unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_ContainerImage::generatedContainers           unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_AutoScalingGroup::machineDefinition           unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_AutoScalingGroup::deploymentNetwork           unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_AutoScalingGroup::securityGroup               unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_Storage::ifaces                               unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_FunctionAsAService::ifaces                    unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_Network::connectedIfaces                      unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_Network::igws                                 unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_Network::subnets                              unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_Subnet::connectedTo                           unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_NetworkInterface::belongsTo                   unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_NetworkInterface::associated                  unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_ComputingGroup::groupedNodes                  unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_SecurityGroup::rules                          unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_SecurityGroup::ifaces                         unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_SwarmRole::nodes                              unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                infrastructure_Swarm::roles                                  unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::vmImages                           unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::containerImages                    unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::networks                           unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::storages                           unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::faas                               unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::group                              unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_VMImage::maps                                       unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_ContainerImage::maps                                unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_Network::maps                                       unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_Storage::maps                                       unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_FunctionAsAService::maps                            unbound_elem_0                \n",
+      "infrastructure_VirtualMachine (vm1)                concrete_ComputingGroup::maps                                unbound_elem_0                \n",
+      "------------------------------------------------------------------------------------------------------------------------\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "ubelems_and_assoc = get_ubelems_and_assoc(solved_ctx, solved_model)\n",
+    "print(\"\\n\".join([pretty_ubelems_assoc(assoc) for assoc in ubelems_and_assoc]))\n",
+    "\n",
+    "print(\"-\" * 120)\n",
+    "\n",
+    "ubvals_and_attr = get_ubvals_and_attr(solved_ctx, solved_model)\n",
+    "print(\"\\n\".join([pretty_ubvals_attrs(attr) for attr in ubvals_and_attr]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 55,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\tAdd constraint Not(infrastructure_VirtualMachine (vm1)                commons_Property::reference                                  unbound_elem_0                )\n",
+      "SAT:\tAdding one more constraint and trying again\n",
+      "*** Before\n",
+      "--- After\n",
+      "***************\n",
+      "*** 1,48 ****\n",
+      "- infrastructure_VirtualMachine (vm1)                commons_Property::reference                                  unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                application_SoftwareComponent::exposedInterfaces             unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                application_SoftwareComponent::consumedInterfaces            unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                application_SaaS::exposedInterfaces                          unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::generators               unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::storages                 unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::faas                     unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::credentials              unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::groups                   unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::securityGroups           unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_InfrastructureLayer::networks                 unbound_elem_0                \n",
+      "  infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::ifaces                         unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::location                       unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::credentials                    unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::group                          unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_VirtualMachine::generatedFrom                 unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_Container::generatedFrom                      unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_Container::hosts                              unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_VMImage::generatedVMs                         unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_ContainerImage::generatedContainers           unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_AutoScalingGroup::machineDefinition           unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_AutoScalingGroup::deploymentNetwork           unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_AutoScalingGroup::securityGroup               unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_Storage::ifaces                               unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_FunctionAsAService::ifaces                    unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_Network::connectedIfaces                      unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_Network::igws                                 unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_Network::subnets                              unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_Subnet::connectedTo                           unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_NetworkInterface::belongsTo                   unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_NetworkInterface::associated                  unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_ComputingGroup::groupedNodes                  unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_SecurityGroup::rules                          unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_SecurityGroup::ifaces                         unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_SwarmRole::nodes                              unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                infrastructure_Swarm::roles                                  unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::vmImages                           unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::containerImages                    unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::networks                           unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::storages                           unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::faas                               unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_RuntimeProvider::group                              unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_VMImage::maps                                       unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_ContainerImage::maps                                unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_Network::maps                                       unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_Storage::maps                                       unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_FunctionAsAService::maps                            unbound_elem_0                \n",
+      "- infrastructure_VirtualMachine (vm1)                concrete_ComputingGroup::maps                                unbound_elem_0                \n",
+      "--- 1 ----\n",
+      "\tAdd constraint Not(infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::ifaces                         unbound_elem_0                )\n",
+      "UNSAT\tLast constraint was the association we are looking for!\n"
+     ]
+    }
+   ],
+   "source": [
+    "def thin_ubelems_and_assoc(ctx: Context, ubelems_and_assoc: list):\n",
+    "    if not ubelems_and_assoc:\n",
+    "        return []\n",
+    "\n",
+    "    (_, elem_1_v), a, (_, elem_2_v) = assoc = ubelems_and_assoc[0]\n",
+    "    assoc_rel = ctx[\"assoc_rel\"](elem_1_v, a, elem_2_v)\n",
+    "\n",
+    "    # Add negated constraint\n",
+    "    ctx[\"solver\"].push()\n",
+    "    print(f\"\\tAdd constraint Not({pretty_ubelems_assoc(assoc)})\")\n",
+    "    ctx[\"solver\"].add(Not(assoc_rel))\n",
+    "    \n",
+    "    res = ctx[\"solver\"].check()\n",
+    "    \n",
+    "    if res == sat:\n",
+    "        print(\"SAT:\\tAdding one more constraint and trying again\")\n",
+    "        # Get new ubelems_and_assoc\n",
+    "        model = ctx[\"solver\"].model()\n",
+    "        thinned_ubelems_and_assoc = get_ubelems_and_assoc(ctx, model)\n",
+    "        \n",
+    "        # Print table showing the diff\n",
+    "        from difflib import context_diff\n",
+    "        uvar_as_text = lambda input: [pretty_ubelems_assoc(assoc) for assoc in input]\n",
+    "        print(\"\\n\".join([a for a in context_diff(uvar_as_text(ubelems_and_assoc), uvar_as_text(thinned_ubelems_and_assoc), lineterm=\"\", fromfile='Before', tofile=\"After\")]))\n",
+    "\n",
+    "        # Iterate\n",
+    "        return thin_ubelems_and_assoc(ctx, thinned_ubelems_and_assoc)\n",
+    "    else:\n",
+    "        print(\"UNSAT\\tLast constraint was the association we are looking for!\")\n",
+    "        ctx[\"solver\"].pop()\n",
+    "        \n",
+    "        if ubelems_and_assoc[1:]:\n",
+    "            print(\"\\tIterating over\")\n",
+    "            print(\"\\t\\t\" + \"\\n\\t\\t\".join([pretty_ubelems_assoc(assoc) for assoc in ubelems_and_assoc[1:]]))\n",
+    "        return [*set([assoc] + thin_ubelems_and_assoc(ctx, ubelems_and_assoc[1:]))]\n",
+    "\n",
+    "\n",
+    "assoc_to_implement = thin_ubelems_and_assoc(solved_ctx, ubelems_and_assoc)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 56,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "infrastructure_VirtualMachine (vm1)                infrastructure_ComputingNode::ifaces                         unbound_elem_0                \n"
+     ]
+    }
+   ],
+   "source": [
+    "print(\"\\n\".join([pretty_ubelems_assoc(assoc) for assoc in assoc_to_implement]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 57,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def thin_ubvals_and_attr(ctx: Context, ubvals_and_attr: list):\n",
+    "    if not ubvals_and_attr:\n",
+    "        return []\n",
+    "\n",
+    "    (_, elem_v), a, (_, attr_v) = attr = ubvals_and_attr[0]\n",
+    "    attr_rel = ctx[\"attr_rel\"](elem_v, a, attr_v)\n",
+    "\n",
+    "    # Add negated constraint\n",
+    "    ctx[\"solver\"].push()\n",
+    "    print(f\"\\tAdd constraint Not({pretty_ubvals_attrs(attr)})\")\n",
+    "    ctx[\"solver\"].add(Not(attr_rel))\n",
+    "    \n",
+    "    res = ctx[\"solver\"].check()\n",
+    "    \n",
+    "    if res == sat:\n",
+    "        print(\"SAT:\\tAdding one more constraint and trying again\")\n",
+    "        # Get new ubelems_and_assoc\n",
+    "        model = ctx[\"solver\"].model()\n",
+    "        thinned_ubvals_and_attr = get_ubvals_and_attr(ctx, model)\n",
+    "        \n",
+    "        # Print table showing the diff\n",
+    "        from difflib import context_diff\n",
+    "        uvar_as_text = lambda input: [pretty_ubvals_attrs(attr) for attr in input]\n",
+    "        print(\"\\n\".join([a for a in context_diff(uvar_as_text(ubelems_and_assoc), uvar_as_text(thinned_ubvals_and_attr), lineterm=\"\", fromfile='Before', tofile=\"After\")]))\n",
+    "\n",
+    "        # Iterate\n",
+    "        return thin_ubvals_and_attr(ctx, thinned_ubvals_and_attr)\n",
+    "    else:\n",
+    "        print(\"UNSAT\\tLast constraint was the attribute we are looking for!\")\n",
+    "        ctx[\"solver\"].pop()\n",
+    "        \n",
+    "        if ubvals_and_attr[1:]:\n",
+    "            print(\"\\tIterating over\")\n",
+    "            print(\"\\t\\t\" + \"\\n\\t\\t\".join([pretty_ubvals_attrs(attr) for attr in ubvals_and_attr[1:]]))\n",
+    "        return [*set([attr] + thin_ubvals_and_attr(ctx, ubvals_and_attr[1:]))]\n",
+    "\n",
+    "\n",
+    "attrs_to_implement = thin_ubvals_and_attr(solved_ctx, ubvals_and_attr)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 58,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(\"\\n\".join([pretty_ubvals_attrs(attr) for attr in attrs_to_implement]))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "From here, we should then add this in the Intermediate Model, and then in the ECore (?) to generate the DOML file somehow.\n",
+    "\n",
+    "We can then provide the new file, or a diff to be patched onto the original?"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3.10.7 ('.venv': poetry)",
+   "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.11.0"
+  },
+  "orig_nbformat": 4,
+  "vscode": {
+   "interpreter": {
+    "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16"
+   }
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/mc_openapi/doml_mc/test.ipynb b/mc_openapi/notebooks/test.ipynb
similarity index 83%
rename from mc_openapi/doml_mc/test.ipynb
rename to mc_openapi/notebooks/test.ipynb
index 9d72011c35730dd45f39f1b5d4d1f587a59d67ae..c94c86e4f20176442a329ef00ad45ef6d54d6de9 100644
--- a/mc_openapi/doml_mc/test.ipynb
+++ b/mc_openapi/notebooks/test.ipynb
@@ -23,14 +23,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "r = dmc.check_common_requirements(2, False, 50)\n",
+    "r = dmc.check_requirements(2, False, 50)\n",
     "r.summarize()"
    ]
   }
  ],
  "metadata": {
   "kernelspec": {
-   "display_name": "Python 3.10.4 ('mc-openapi-dl7Bx6Lh-py3.10')",
+   "display_name": "Python 3.11.0 ('.venv': poetry)",
    "language": "python",
    "name": "python3"
   },
@@ -44,12 +44,12 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.10.6"
+   "version": "3.11.0"
   },
   "orig_nbformat": 4,
   "vscode": {
    "interpreter": {
-    "hash": "ad63ed7e22c54016fdab5faefd8d83d59c3e39bc25e97a3e7b72bed4daaf83ed"
+    "hash": "d98256633358fe1daa4009223d54520a3e2548801398a173545d5698bb289e16"
    }
   }
  },
diff --git a/mc_openapi/openapi/model_checker.yaml b/mc_openapi/openapi/model_checker.yaml
index b1875dd5fcab22615fd7d6bb63595aa38d96ae98..66638bbff3283e435c25af47ddd47e8e61e2eaf3 100644
--- a/mc_openapi/openapi/model_checker.yaml
+++ b/mc_openapi/openapi/model_checker.yaml
@@ -17,13 +17,6 @@ paths:
             schema:
               type: string
         required: true
-      parameters:
-        - in: query
-          name: requirement
-          required: false
-          schema:
-            type: string
-          description: Requirement to be verified (optional)
       responses:
         "200":
           content:
diff --git a/poetry.lock b/poetry.lock
deleted file mode 100644
index df5701280e4a00cbf20b8932a05d504f3fbb239c..0000000000000000000000000000000000000000
--- a/poetry.lock
+++ /dev/null
@@ -1,2020 +0,0 @@
-[[package]]
-name = "alabaster"
-version = "0.7.12"
-description = "A configurable sidebar-enabled Sphinx theme"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "anyio"
-version = "3.6.1"
-description = "High level compatibility layer for multiple asynchronous event loop implementations"
-category = "main"
-optional = false
-python-versions = ">=3.6.2"
-
-[package.dependencies]
-idna = ">=2.8"
-sniffio = ">=1.1"
-
-[package.extras]
-doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
-test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"]
-trio = ["trio (>=0.16)"]
-
-[[package]]
-name = "appnope"
-version = "0.1.3"
-description = "Disable App Nap on macOS >= 10.9"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "asttokens"
-version = "2.0.8"
-description = "Annotate AST trees with source code positions"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-six = "*"
-
-[package.extras]
-test = ["astroid (<=2.5.3)", "pytest"]
-
-[[package]]
-name = "attrs"
-version = "22.1.0"
-description = "Classes Without Boilerplate"
-category = "main"
-optional = false
-python-versions = ">=3.5"
-
-[package.extras]
-dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
-docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
-tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
-tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
-
-[[package]]
-name = "Babel"
-version = "2.10.3"
-description = "Internationalization utilities"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-pytz = ">=2015.7"
-
-[[package]]
-name = "backcall"
-version = "0.2.0"
-description = "Specifications for callback functions passed in to an API"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "certifi"
-version = "2022.9.24"
-description = "Python package for providing Mozilla's CA Bundle."
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "cffi"
-version = "1.15.1"
-description = "Foreign Function Interface for Python calling C code."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-pycparser = "*"
-
-[[package]]
-name = "charset-normalizer"
-version = "2.1.1"
-description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-category = "main"
-optional = false
-python-versions = ">=3.6.0"
-
-[package.extras]
-unicode_backport = ["unicodedata2"]
-
-[[package]]
-name = "click"
-version = "8.1.3"
-description = "Composable command line interface toolkit"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-colorama = {version = "*", markers = "platform_system == \"Windows\""}
-
-[[package]]
-name = "clickclick"
-version = "20.10.2"
-description = "Click utility functions"
-category = "main"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-click = ">=4.0"
-PyYAML = ">=3.11"
-
-[[package]]
-name = "colorama"
-version = "0.4.5"
-description = "Cross-platform colored terminal text."
-category = "main"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-
-[[package]]
-name = "colorful"
-version = "0.5.4"
-description = "Terminal string styling done right, in Python."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-colorama = {version = "*", markers = "platform_system == \"Windows\""}
-
-[[package]]
-name = "connexion"
-version = "2.14.1"
-description = "Connexion - API first applications with OpenAPI/Swagger and Flask"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-clickclick = ">=1.2,<21"
-flask = ">=1.0.4,<3"
-inflection = ">=0.3.1,<0.6"
-itsdangerous = ">=0.24"
-jsonschema = ">=2.5.1,<5"
-packaging = ">=20"
-PyYAML = ">=5.1,<7"
-requests = ">=2.9.1,<3"
-swagger-ui-bundle = {version = ">=0.0.2,<0.1", optional = true, markers = "extra == \"swagger-ui\""}
-werkzeug = ">=1.0,<3"
-
-[package.extras]
-aiohttp = ["MarkupSafe (>=0.23)", "aiohttp (>=2.3.10,<4)", "aiohttp-jinja2 (>=0.14.0,<2)"]
-docs = ["sphinx-autoapi (==1.8.1)"]
-flask = ["flask (>=1.0.4,<3)", "itsdangerous (>=0.24)"]
-swagger-ui = ["swagger-ui-bundle (>=0.0.2,<0.1)"]
-tests = ["MarkupSafe (>=0.23)", "aiohttp (>=2.3.10,<4)", "aiohttp-jinja2 (>=0.14.0,<2)", "aiohttp-remotes", "decorator (>=5,<6)", "flask (>=1.0.4,<3)", "itsdangerous (>=0.24)", "pytest (>=6,<7)", "pytest-aiohttp", "pytest-cov (>=2,<3)", "swagger-ui-bundle (>=0.0.2,<0.1)", "testfixtures (>=6,<7)"]
-
-[[package]]
-name = "debugpy"
-version = "1.6.3"
-description = "An implementation of the Debug Adapter Protocol for Python"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "decorator"
-version = "5.1.1"
-description = "Decorators for Humans"
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-
-[[package]]
-name = "docutils"
-version = "0.17.1"
-description = "Docutils -- Python Documentation Utilities"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-
-[[package]]
-name = "entrypoints"
-version = "0.4"
-description = "Discover and load entry points from installed packages."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "executing"
-version = "1.1.0"
-description = "Get the currently executing AST node of a frame, and other information"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.extras]
-tests = ["asttokens", "littleutils", "pytest", "rich"]
-
-[[package]]
-name = "Flask"
-version = "2.2.2"
-description = "A simple framework for building complex web applications."
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-click = ">=8.0"
-importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""}
-itsdangerous = ">=2.0"
-Jinja2 = ">=3.0"
-Werkzeug = ">=2.2.2"
-
-[package.extras]
-async = ["asgiref (>=3.2)"]
-dotenv = ["python-dotenv"]
-
-[[package]]
-name = "future-fstrings"
-version = "1.2.0"
-description = "A backport of fstrings to python<3.6"
-category = "main"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-
-[package.extras]
-rewrite = ["tokenize-rt (>=3)"]
-
-[[package]]
-name = "h11"
-version = "0.14.0"
-description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "httptools"
-version = "0.5.0"
-description = "A collection of framework independent HTTP protocol utils."
-category = "main"
-optional = false
-python-versions = ">=3.5.0"
-
-[package.extras]
-test = ["Cython (>=0.29.24,<0.30.0)"]
-
-[[package]]
-name = "idna"
-version = "3.4"
-description = "Internationalized Domain Names in Applications (IDNA)"
-category = "main"
-optional = false
-python-versions = ">=3.5"
-
-[[package]]
-name = "imagesize"
-version = "1.4.1"
-description = "Getting image size from png/jpeg/jpeg2000/gif file"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-
-[[package]]
-name = "importlib-metadata"
-version = "5.0.0"
-description = "Read metadata from Python packages"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-zipp = ">=0.5"
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
-perf = ["ipython"]
-testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
-
-[[package]]
-name = "inflection"
-version = "0.5.1"
-description = "A port of Ruby on Rails inflector to Python"
-category = "main"
-optional = false
-python-versions = ">=3.5"
-
-[[package]]
-name = "iniconfig"
-version = "1.1.1"
-description = "iniconfig: brain-dead simple config-ini parsing"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "ipykernel"
-version = "6.16.0"
-description = "IPython Kernel for Jupyter"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-appnope = {version = "*", markers = "platform_system == \"Darwin\""}
-debugpy = ">=1.0"
-ipython = ">=7.23.1"
-jupyter-client = ">=6.1.12"
-matplotlib-inline = ">=0.1"
-nest-asyncio = "*"
-packaging = "*"
-psutil = "*"
-pyzmq = ">=17"
-tornado = ">=6.1"
-traitlets = ">=5.1.0"
-
-[package.extras]
-test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=6.0)", "pytest-cov", "pytest-timeout"]
-
-[[package]]
-name = "ipython"
-version = "8.5.0"
-description = "IPython: Productive Interactive Computing"
-category = "dev"
-optional = false
-python-versions = ">=3.8"
-
-[package.dependencies]
-appnope = {version = "*", markers = "sys_platform == \"darwin\""}
-backcall = "*"
-colorama = {version = "*", markers = "sys_platform == \"win32\""}
-decorator = "*"
-jedi = ">=0.16"
-matplotlib-inline = "*"
-pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""}
-pickleshare = "*"
-prompt-toolkit = ">3.0.1,<3.1.0"
-pygments = ">=2.4.0"
-stack-data = "*"
-traitlets = ">=5"
-
-[package.extras]
-all = ["Sphinx (>=1.3)", "black", "curio", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "testpath", "trio"]
-black = ["black"]
-doc = ["Sphinx (>=1.3)"]
-kernel = ["ipykernel"]
-nbconvert = ["nbconvert"]
-nbformat = ["nbformat"]
-notebook = ["ipywidgets", "notebook"]
-parallel = ["ipyparallel"]
-qtconsole = ["qtconsole"]
-test = ["pytest (<7.1)", "pytest-asyncio", "testpath"]
-test_extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"]
-
-[[package]]
-name = "itsdangerous"
-version = "2.1.2"
-description = "Safely pass data to untrusted environments and back."
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "jedi"
-version = "0.18.1"
-description = "An autocompletion tool for Python that can be used for text editors."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-parso = ">=0.8.0,<0.9.0"
-
-[package.extras]
-qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
-testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"]
-
-[[package]]
-name = "Jinja2"
-version = "3.1.2"
-description = "A very fast and expressive template engine."
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-MarkupSafe = ">=2.0"
-
-[package.extras]
-i18n = ["Babel (>=2.7)"]
-
-[[package]]
-name = "joblib"
-version = "1.2.0"
-description = "Lightweight pipelining with Python functions"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "jsonschema"
-version = "4.16.0"
-description = "An implementation of JSON Schema validation for Python"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-attrs = ">=17.4.0"
-pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2"
-
-[package.extras]
-format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
-format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
-
-[[package]]
-name = "jupyter-client"
-version = "7.3.5"
-description = "Jupyter protocol implementation and client libraries"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-entrypoints = "*"
-jupyter-core = ">=4.9.2"
-nest-asyncio = ">=1.5.4"
-python-dateutil = ">=2.8.2"
-pyzmq = ">=23.0"
-tornado = ">=6.2"
-traitlets = "*"
-
-[package.extras]
-doc = ["ipykernel", "myst-parser", "sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"]
-test = ["codecov", "coverage", "ipykernel (>=6.5)", "ipython", "mypy", "pre-commit", "pytest", "pytest-asyncio (>=0.18)", "pytest-cov", "pytest-timeout"]
-
-[[package]]
-name = "jupyter-core"
-version = "4.11.1"
-description = "Jupyter core package. A base package on which Jupyter projects rely."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""}
-traitlets = "*"
-
-[package.extras]
-test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"]
-
-[[package]]
-name = "lxml"
-version = "4.9.1"
-description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
-category = "main"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*"
-
-[package.extras]
-cssselect = ["cssselect (>=0.7)"]
-html5 = ["html5lib"]
-htmlsoup = ["BeautifulSoup4"]
-source = ["Cython (>=0.29.7)"]
-
-[[package]]
-name = "MarkupSafe"
-version = "2.1.1"
-description = "Safely add untrusted strings to HTML/XML markup."
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "matplotlib-inline"
-version = "0.1.6"
-description = "Inline Matplotlib backend for Jupyter"
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-
-[package.dependencies]
-traitlets = "*"
-
-[[package]]
-name = "nest-asyncio"
-version = "1.5.6"
-description = "Patch asyncio to allow nested event loops"
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-
-[[package]]
-name = "networkx"
-version = "2.8.7"
-description = "Python package for creating and manipulating graphs and networks"
-category = "main"
-optional = false
-python-versions = ">=3.8"
-
-[package.extras]
-default = ["matplotlib (>=3.4)", "numpy (>=1.19)", "pandas (>=1.3)", "scipy (>=1.8)"]
-developer = ["mypy (>=0.981)", "pre-commit (>=2.20)"]
-doc = ["nb2plots (>=0.6)", "numpydoc (>=1.4)", "pillow (>=9.1)", "pydata-sphinx-theme (>=0.9)", "sphinx (>=5)", "sphinx-gallery (>=0.10)", "texext (>=0.6.6)"]
-extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.9)", "sympy (>=1.10)"]
-test = ["codecov (>=2.1)", "pytest (>=7.1)", "pytest-cov (>=3.0)"]
-
-[[package]]
-name = "ordered-set"
-version = "4.1.0"
-description = "An OrderedSet is a custom MutableSet that remembers its order, so that every"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-dev = ["black", "mypy", "pytest"]
-
-[[package]]
-name = "packaging"
-version = "21.3"
-description = "Core utilities for Python packages"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
-
-[[package]]
-name = "parso"
-version = "0.8.3"
-description = "A Python Parser"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
-testing = ["docopt", "pytest (<6.0.0)"]
-
-[[package]]
-name = "pexpect"
-version = "4.8.0"
-description = "Pexpect allows easy control of interactive console applications."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-ptyprocess = ">=0.5"
-
-[[package]]
-name = "pickleshare"
-version = "0.7.5"
-description = "Tiny 'shelve'-like database with concurrency support"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "pluggy"
-version = "1.0.0"
-description = "plugin and hook calling mechanisms for python"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-dev = ["pre-commit", "tox"]
-testing = ["pytest", "pytest-benchmark"]
-
-[[package]]
-name = "prettyprinter"
-version = "0.18.0"
-description = "Syntax-highlighting, declarative and composable pretty printer for Python 3.5+"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-colorful = ">=0.4.0"
-Pygments = ">=2.2.0"
-
-[[package]]
-name = "prompt-toolkit"
-version = "3.0.31"
-description = "Library for building powerful interactive command lines in Python"
-category = "dev"
-optional = false
-python-versions = ">=3.6.2"
-
-[package.dependencies]
-wcwidth = "*"
-
-[[package]]
-name = "psutil"
-version = "5.9.2"
-description = "Cross-platform lib for process and system monitoring in Python."
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-
-[package.extras]
-test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
-
-[[package]]
-name = "ptyprocess"
-version = "0.7.0"
-description = "Run a subprocess in a pseudo terminal"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "pure-eval"
-version = "0.2.2"
-description = "Safely evaluate AST nodes without side effects"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.extras]
-tests = ["pytest"]
-
-[[package]]
-name = "py"
-version = "1.11.0"
-description = "library with cross-python path, ini-parsing, io, code, log facilities"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-
-[[package]]
-name = "pycparser"
-version = "2.21"
-description = "C parser in Python"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-
-[[package]]
-name = "pyecore"
-version = "0.12.2"
-description = "A Python(ic) Implementation of the Eclipse Modeling Framework (EMF/Ecore)"
-category = "main"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-future-fstrings = "*"
-lxml = "*"
-ordered-set = ">=4.0.1"
-restrictedpython = ">=4.0b6"
-
-[[package]]
-name = "Pygments"
-version = "2.13.0"
-description = "Pygments is a syntax highlighting package written in Python."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-plugins = ["importlib-metadata"]
-
-[[package]]
-name = "pyparsing"
-version = "3.0.9"
-description = "pyparsing module - Classes and methods to define and execute parsing grammars"
-category = "main"
-optional = false
-python-versions = ">=3.6.8"
-
-[package.extras]
-diagrams = ["jinja2", "railroad-diagrams"]
-
-[[package]]
-name = "pyrsistent"
-version = "0.18.1"
-description = "Persistent/Functional/Immutable data structures"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "pytest"
-version = "7.1.3"
-description = "pytest: simple powerful testing with Python"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-attrs = ">=19.2.0"
-colorama = {version = "*", markers = "sys_platform == \"win32\""}
-iniconfig = "*"
-packaging = "*"
-pluggy = ">=0.12,<2.0"
-py = ">=1.8.2"
-tomli = ">=1.0.0"
-
-[package.extras]
-testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
-
-[[package]]
-name = "python-dateutil"
-version = "2.8.2"
-description = "Extensions to the standard Python datetime module"
-category = "dev"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
-
-[package.dependencies]
-six = ">=1.5"
-
-[[package]]
-name = "python-dotenv"
-version = "0.21.0"
-description = "Read key-value pairs from a .env file and set them as environment variables"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-cli = ["click (>=5.0)"]
-
-[[package]]
-name = "pytz"
-version = "2022.4"
-description = "World timezone definitions, modern and historical"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "pywin32"
-version = "304"
-description = "Python for Window Extensions"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "PyYAML"
-version = "6.0"
-description = "YAML parser and emitter for Python"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "pyzmq"
-version = "24.0.1"
-description = "Python bindings for 0MQ"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-cffi = {version = "*", markers = "implementation_name == \"pypy\""}
-py = {version = "*", markers = "implementation_name == \"pypy\""}
-
-[[package]]
-name = "requests"
-version = "2.28.1"
-description = "Python HTTP for Humans."
-category = "main"
-optional = false
-python-versions = ">=3.7, <4"
-
-[package.dependencies]
-certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<3"
-idna = ">=2.5,<4"
-urllib3 = ">=1.21.1,<1.27"
-
-[package.extras]
-socks = ["PySocks (>=1.5.6,!=1.5.7)"]
-use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
-
-[[package]]
-name = "RestrictedPython"
-version = "5.0"
-description = "RestrictedPython is a defined subset of the Python language which allows to provide a program input into a trusted environment."
-category = "main"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-setuptools = "*"
-
-[package.extras]
-test = ["pytest", "pytest-mock"]
-
-[[package]]
-name = "setuptools"
-version = "65.4.1"
-description = "Easily download, build, install, upgrade, and uninstall Python packages"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
-testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
-testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
-
-[[package]]
-name = "six"
-version = "1.16.0"
-description = "Python 2 and 3 compatibility utilities"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
-
-[[package]]
-name = "sniffio"
-version = "1.3.0"
-description = "Sniff out which async library your code is running under"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "snowballstemmer"
-version = "2.2.0"
-description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "Sphinx"
-version = "5.2.3"
-description = "Python documentation generator"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-alabaster = ">=0.7,<0.8"
-babel = ">=2.9"
-colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
-docutils = ">=0.14,<0.20"
-imagesize = ">=1.3"
-importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""}
-Jinja2 = ">=3.0"
-packaging = ">=21.0"
-Pygments = ">=2.12"
-requests = ">=2.5.0"
-snowballstemmer = ">=2.0"
-sphinxcontrib-applehelp = "*"
-sphinxcontrib-devhelp = "*"
-sphinxcontrib-htmlhelp = ">=2.0.0"
-sphinxcontrib-jsmath = "*"
-sphinxcontrib-qthelp = "*"
-sphinxcontrib-serializinghtml = ">=1.1.5"
-
-[package.extras]
-docs = ["sphinxcontrib-websupport"]
-lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "types-requests", "types-typed-ast"]
-test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"]
-
-[[package]]
-name = "sphinx-rtd-theme"
-version = "1.0.0"
-description = "Read the Docs theme for Sphinx"
-category = "dev"
-optional = false
-python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
-
-[package.dependencies]
-docutils = "<0.18"
-sphinx = ">=1.6"
-
-[package.extras]
-dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client"]
-
-[[package]]
-name = "sphinxcontrib-applehelp"
-version = "1.0.2"
-description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books"
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["pytest"]
-
-[[package]]
-name = "sphinxcontrib-devhelp"
-version = "1.0.2"
-description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document."
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["pytest"]
-
-[[package]]
-name = "sphinxcontrib-htmlhelp"
-version = "2.0.0"
-description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["html5lib", "pytest"]
-
-[[package]]
-name = "sphinxcontrib-jsmath"
-version = "1.0.1"
-description = "A sphinx extension which renders display math in HTML via JavaScript"
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-
-[package.extras]
-test = ["flake8", "mypy", "pytest"]
-
-[[package]]
-name = "sphinxcontrib-qthelp"
-version = "1.0.3"
-description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document."
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["pytest"]
-
-[[package]]
-name = "sphinxcontrib-serializinghtml"
-version = "1.1.5"
-description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)."
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-
-[package.extras]
-lint = ["docutils-stubs", "flake8", "mypy"]
-test = ["pytest"]
-
-[[package]]
-name = "stack-data"
-version = "0.5.1"
-description = "Extract data from python stack frames and tracebacks for informative displays"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-asttokens = "*"
-executing = "*"
-pure-eval = "*"
-
-[package.extras]
-tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
-
-[[package]]
-name = "swagger-ui-bundle"
-version = "0.0.9"
-description = "swagger_ui_bundle - swagger-ui files in a pip package"
-category = "main"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-Jinja2 = ">=2.0"
-
-[[package]]
-name = "tomli"
-version = "2.0.1"
-description = "A lil' TOML parser"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "tornado"
-version = "6.2"
-description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
-category = "dev"
-optional = false
-python-versions = ">= 3.7"
-
-[[package]]
-name = "traitlets"
-version = "5.4.0"
-description = ""
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-test = ["pre-commit", "pytest"]
-
-[[package]]
-name = "urllib3"
-version = "1.26.12"
-description = "HTTP library with thread-safe connection pooling, file post, and more."
-category = "main"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
-
-[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
-secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
-socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
-
-[[package]]
-name = "uvicorn"
-version = "0.18.3"
-description = "The lightning-fast ASGI server."
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-click = ">=7.0"
-colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""}
-h11 = ">=0.8"
-httptools = {version = ">=0.4.0", optional = true, markers = "extra == \"standard\""}
-python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
-pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""}
-uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""}
-watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
-websockets = {version = ">=10.0", optional = true, markers = "extra == \"standard\""}
-
-[package.extras]
-standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"]
-
-[[package]]
-name = "uvloop"
-version = "0.17.0"
-description = "Fast implementation of asyncio event loop on top of libuv"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-dev = ["Cython (>=0.29.32,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=3.6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"]
-docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"]
-test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)"]
-
-[[package]]
-name = "watchfiles"
-version = "0.17.0"
-description = "Simple, modern and high performance file watching and code reload in python."
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-anyio = ">=3.0.0,<4"
-
-[[package]]
-name = "wcwidth"
-version = "0.2.5"
-description = "Measures the displayed width of unicode strings in a terminal"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "websockets"
-version = "10.3"
-description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[[package]]
-name = "Werkzeug"
-version = "2.2.2"
-description = "The comprehensive WSGI web application library."
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.dependencies]
-MarkupSafe = ">=2.1.1"
-
-[package.extras]
-watchdog = ["watchdog"]
-
-[[package]]
-name = "z3-solver"
-version = "4.11.2.0"
-description = "an efficient SMT solver library"
-category = "main"
-optional = false
-python-versions = "*"
-
-[[package]]
-name = "zipp"
-version = "3.8.1"
-description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "main"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"]
-testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
-
-[metadata]
-lock-version = "1.1"
-python-versions = "^3.9"
-content-hash = "a9d927113aa49367234cc4d09abee6d3743b94f59a0f47c6d1b707abd47c246e"
-
-[metadata.files]
-alabaster = [
-    {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
-    {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
-]
-anyio = [
-    {file = "anyio-3.6.1-py3-none-any.whl", hash = "sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be"},
-    {file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"},
-]
-appnope = [
-    {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"},
-    {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"},
-]
-asttokens = [
-    {file = "asttokens-2.0.8-py2.py3-none-any.whl", hash = "sha256:e3305297c744ae53ffa032c45dc347286165e4ffce6875dc662b205db0623d86"},
-    {file = "asttokens-2.0.8.tar.gz", hash = "sha256:c61e16246ecfb2cde2958406b4c8ebc043c9e6d73aaa83c941673b35e5d3a76b"},
-]
-attrs = [
-    {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
-    {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
-]
-Babel = [
-    {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"},
-    {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"},
-]
-backcall = [
-    {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
-    {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
-]
-certifi = [
-    {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"},
-    {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"},
-]
-cffi = [
-    {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
-    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
-    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
-    {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
-    {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
-    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
-    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
-    {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
-    {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
-    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
-    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
-    {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
-    {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
-    {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
-    {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
-    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
-    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
-    {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
-    {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
-    {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
-    {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
-    {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
-    {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
-    {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
-    {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
-    {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
-    {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
-    {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
-    {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
-    {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
-    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
-    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
-    {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
-    {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
-    {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
-]
-charset-normalizer = [
-    {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"},
-    {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"},
-]
-click = [
-    {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
-    {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
-]
-clickclick = [
-    {file = "clickclick-20.10.2-py2.py3-none-any.whl", hash = "sha256:c8f33e6d9ec83f68416dd2136a7950125bd256ec39ccc9a85c6e280a16be2bb5"},
-    {file = "clickclick-20.10.2.tar.gz", hash = "sha256:4efb13e62353e34c5eef7ed6582c4920b418d7dedc86d819e22ee089ba01802c"},
-]
-colorama = [
-    {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
-    {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
-]
-colorful = [
-    {file = "colorful-0.5.4-py2.py3-none-any.whl", hash = "sha256:8d264b52a39aae4c0ba3e2a46afbaec81b0559a99be0d2cfe2aba4cf94531348"},
-    {file = "colorful-0.5.4.tar.gz", hash = "sha256:86848ad4e2eda60cd2519d8698945d22f6f6551e23e95f3f14dfbb60997807ea"},
-]
-connexion = [
-    {file = "connexion-2.14.1-py2.py3-none-any.whl", hash = "sha256:f343717241b4c4802a694c38fee66fb1693c897fe4ea5a957fa9b3b07caf6394"},
-    {file = "connexion-2.14.1.tar.gz", hash = "sha256:99aa5781e70a7b94f8ffae8cf89f309d49cdb811bbd65a8e2f2546f3b19a01e6"},
-]
-debugpy = [
-    {file = "debugpy-1.6.3-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:c4b2bd5c245eeb49824bf7e539f95fb17f9a756186e51c3e513e32999d8846f3"},
-    {file = "debugpy-1.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b8deaeb779699350deeed835322730a3efec170b88927debc9ba07a1a38e2585"},
-    {file = "debugpy-1.6.3-cp310-cp310-win32.whl", hash = "sha256:fc233a0160f3b117b20216f1169e7211b83235e3cd6749bcdd8dbb72177030c7"},
-    {file = "debugpy-1.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:dda8652520eae3945833e061cbe2993ad94a0b545aebd62e4e6b80ee616c76b2"},
-    {file = "debugpy-1.6.3-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5c814596a170a0a58fa6fad74947e30bfd7e192a5d2d7bd6a12156c2899e13a"},
-    {file = "debugpy-1.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c4cd6f37e3c168080d61d698390dfe2cd9e74ebf80b448069822a15dadcda57d"},
-    {file = "debugpy-1.6.3-cp37-cp37m-win32.whl", hash = "sha256:3c9f985944a30cfc9ae4306ac6a27b9c31dba72ca943214dad4a0ab3840f6161"},
-    {file = "debugpy-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:5ad571a36cec137ae6ed951d0ff75b5e092e9af6683da084753231150cbc5b25"},
-    {file = "debugpy-1.6.3-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:adcfea5ea06d55d505375995e150c06445e2b20cd12885bcae566148c076636b"},
-    {file = "debugpy-1.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:daadab4403427abd090eccb38d8901afd8b393e01fd243048fab3f1d7132abb4"},
-    {file = "debugpy-1.6.3-cp38-cp38-win32.whl", hash = "sha256:6efc30325b68e451118b795eff6fe8488253ca3958251d5158106d9c87581bc6"},
-    {file = "debugpy-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:86d784b72c5411c833af1cd45b83d80c252b77c3bfdb43db17c441d772f4c734"},
-    {file = "debugpy-1.6.3-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4e255982552b0edfe3a6264438dbd62d404baa6556a81a88f9420d3ed79b06ae"},
-    {file = "debugpy-1.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cca23cb6161ac89698d629d892520327dd1be9321c0960e610bbcb807232b45d"},
-    {file = "debugpy-1.6.3-cp39-cp39-win32.whl", hash = "sha256:7c302095a81be0d5c19f6529b600bac971440db3e226dce85347cc27e6a61908"},
-    {file = "debugpy-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:34d2cdd3a7c87302ba5322b86e79c32c2115be396f3f09ca13306d8a04fe0f16"},
-    {file = "debugpy-1.6.3-py2.py3-none-any.whl", hash = "sha256:84c39940a0cac410bf6aa4db00ba174f973eef521fbe9dd058e26bcabad89c4f"},
-    {file = "debugpy-1.6.3.zip", hash = "sha256:e8922090514a890eec99cfb991bab872dd2e353ebb793164d5f01c362b9a40bf"},
-]
-decorator = [
-    {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
-    {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
-]
-docutils = [
-    {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"},
-    {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"},
-]
-entrypoints = [
-    {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"},
-    {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"},
-]
-executing = [
-    {file = "executing-1.1.0-py2.py3-none-any.whl", hash = "sha256:4a6d96ba89eb3dcc11483471061b42b9006d8c9f81c584dd04246944cd022530"},
-    {file = "executing-1.1.0.tar.gz", hash = "sha256:2c2c07d1ec4b2d8f9676b25170f1d8445c0ee2eb78901afb075a4b8d83608c6a"},
-]
-Flask = [
-    {file = "Flask-2.2.2-py3-none-any.whl", hash = "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526"},
-    {file = "Flask-2.2.2.tar.gz", hash = "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b"},
-]
-future-fstrings = [
-    {file = "future_fstrings-1.2.0-py2.py3-none-any.whl", hash = "sha256:90e49598b553d8746c4dc7d9442e0359d038c3039d802c91c0a55505da318c63"},
-    {file = "future_fstrings-1.2.0.tar.gz", hash = "sha256:6cf41cbe97c398ab5a81168ce0dbb8ad95862d3caf23c21e4430627b90844089"},
-]
-h11 = [
-    {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
-    {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
-]
-httptools = [
-    {file = "httptools-0.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8f470c79061599a126d74385623ff4744c4e0f4a0997a353a44923c0b561ee51"},
-    {file = "httptools-0.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e90491a4d77d0cb82e0e7a9cb35d86284c677402e4ce7ba6b448ccc7325c5421"},
-    {file = "httptools-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d2357f791b12d86faced7b5736dea9ef4f5ecdc6c3f253e445ee82da579449"},
-    {file = "httptools-0.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f90cd6fd97c9a1b7fe9215e60c3bd97336742a0857f00a4cb31547bc22560c2"},
-    {file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5230a99e724a1bdbbf236a1b58d6e8504b912b0552721c7c6b8570925ee0ccde"},
-    {file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a47a34f6015dd52c9eb629c0f5a8a5193e47bf2a12d9a3194d231eaf1bc451a"},
-    {file = "httptools-0.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:24bb4bb8ac3882f90aa95403a1cb48465de877e2d5298ad6ddcfdebec060787d"},
-    {file = "httptools-0.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e67d4f8734f8054d2c4858570cc4b233bf753f56e85217de4dfb2495904cf02e"},
-    {file = "httptools-0.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e5eefc58d20e4c2da82c78d91b2906f1a947ef42bd668db05f4ab4201a99f49"},
-    {file = "httptools-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0297822cea9f90a38df29f48e40b42ac3d48a28637368f3ec6d15eebefd182f9"},
-    {file = "httptools-0.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:557be7fbf2bfa4a2ec65192c254e151684545ebab45eca5d50477d562c40f986"},
-    {file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:54465401dbbec9a6a42cf737627fb0f014d50dc7365a6b6cd57753f151a86ff0"},
-    {file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4d9ebac23d2de960726ce45f49d70eb5466725c0087a078866043dad115f850f"},
-    {file = "httptools-0.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:e8a34e4c0ab7b1ca17b8763613783e2458e77938092c18ac919420ab8655c8c1"},
-    {file = "httptools-0.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f659d7a48401158c59933904040085c200b4be631cb5f23a7d561fbae593ec1f"},
-    {file = "httptools-0.5.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1616b3ba965cd68e6f759eeb5d34fbf596a79e84215eeceebf34ba3f61fdc7"},
-    {file = "httptools-0.5.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3625a55886257755cb15194efbf209584754e31d336e09e2ffe0685a76cb4b60"},
-    {file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:72ad589ba5e4a87e1d404cc1cb1b5780bfcb16e2aec957b88ce15fe879cc08ca"},
-    {file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:850fec36c48df5a790aa735417dca8ce7d4b48d59b3ebd6f83e88a8125cde324"},
-    {file = "httptools-0.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f222e1e9d3f13b68ff8a835574eda02e67277d51631d69d7cf7f8e07df678c86"},
-    {file = "httptools-0.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3cb8acf8f951363b617a8420768a9f249099b92e703c052f9a51b66342eea89b"},
-    {file = "httptools-0.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550059885dc9c19a072ca6d6735739d879be3b5959ec218ba3e013fd2255a11b"},
-    {file = "httptools-0.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a04fe458a4597aa559b79c7f48fe3dceabef0f69f562daf5c5e926b153817281"},
-    {file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d0c1044bce274ec6711f0770fd2d5544fe392591d204c68328e60a46f88843b"},
-    {file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c6eeefd4435055a8ebb6c5cc36111b8591c192c56a95b45fe2af22d9881eee25"},
-    {file = "httptools-0.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5b65be160adcd9de7a7e6413a4966665756e263f0d5ddeffde277ffeee0576a5"},
-    {file = "httptools-0.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fe9c766a0c35b7e3d6b6939393c8dfdd5da3ac5dec7f971ec9134f284c6c36d6"},
-    {file = "httptools-0.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:85b392aba273566c3d5596a0a490978c085b79700814fb22bfd537d381dd230c"},
-    {file = "httptools-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5e3088f4ed33947e16fd865b8200f9cfae1144f41b64a8cf19b599508e096bc"},
-    {file = "httptools-0.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c2a56b6aad7cc8f5551d8e04ff5a319d203f9d870398b94702300de50190f63"},
-    {file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9b571b281a19762adb3f48a7731f6842f920fa71108aff9be49888320ac3e24d"},
-    {file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa47ffcf70ba6f7848349b8a6f9b481ee0f7637931d91a9860a1838bfc586901"},
-    {file = "httptools-0.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:bede7ee075e54b9a5bde695b4fc8f569f30185891796b2e4e09e2226801d09bd"},
-    {file = "httptools-0.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:64eba6f168803a7469866a9c9b5263a7463fa8b7a25b35e547492aa7322036b6"},
-    {file = "httptools-0.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4b098e4bb1174096a93f48f6193e7d9aa7071506a5877da09a783509ca5fff42"},
-    {file = "httptools-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9423a2de923820c7e82e18980b937893f4aa8251c43684fa1772e341f6e06887"},
-    {file = "httptools-0.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1b7becf7d9d3ccdbb2f038f665c0f4857e08e1d8481cbcc1a86a0afcfb62b2"},
-    {file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:50d4613025f15f4b11f1c54bbed4761c0020f7f921b95143ad6d58c151198142"},
-    {file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8ffce9d81c825ac1deaa13bc9694c0562e2840a48ba21cfc9f3b4c922c16f372"},
-    {file = "httptools-0.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:1af91b3650ce518d226466f30bbba5b6376dbd3ddb1b2be8b0658c6799dd450b"},
-    {file = "httptools-0.5.0.tar.gz", hash = "sha256:295874861c173f9101960bba332429bb77ed4dcd8cdf5cee9922eb00e4f6bc09"},
-]
-idna = [
-    {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
-    {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
-]
-imagesize = [
-    {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"},
-    {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
-]
-importlib-metadata = [
-    {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"},
-    {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"},
-]
-inflection = [
-    {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"},
-    {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"},
-]
-iniconfig = [
-    {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
-    {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
-]
-ipykernel = [
-    {file = "ipykernel-6.16.0-py3-none-any.whl", hash = "sha256:d3d95241cd4dd302fea9d5747b00509b58997356d1f6333c9a074c3eccb78cb3"},
-    {file = "ipykernel-6.16.0.tar.gz", hash = "sha256:7fe42c0d58435e971dc15fd42189f20d66bf35f3056bda4f6554271bc1fa3d0d"},
-]
-ipython = [
-    {file = "ipython-8.5.0-py3-none-any.whl", hash = "sha256:6f090e29ab8ef8643e521763a4f1f39dc3914db643122b1e9d3328ff2e43ada2"},
-    {file = "ipython-8.5.0.tar.gz", hash = "sha256:097bdf5cd87576fd066179c9f7f208004f7a6864ee1b20f37d346c0bcb099f84"},
-]
-itsdangerous = [
-    {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"},
-    {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"},
-]
-jedi = [
-    {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"},
-    {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"},
-]
-Jinja2 = [
-    {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
-    {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
-]
-joblib = [
-    {file = "joblib-1.2.0-py3-none-any.whl", hash = "sha256:091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385"},
-    {file = "joblib-1.2.0.tar.gz", hash = "sha256:e1cee4a79e4af22881164f218d4311f60074197fb707e082e803b61f6d137018"},
-]
-jsonschema = [
-    {file = "jsonschema-4.16.0-py3-none-any.whl", hash = "sha256:9e74b8f9738d6a946d70705dc692b74b5429cd0960d58e79ffecfc43b2221eb9"},
-    {file = "jsonschema-4.16.0.tar.gz", hash = "sha256:165059f076eff6971bae5b742fc029a7b4ef3f9bcf04c14e4776a7605de14b23"},
-]
-jupyter-client = [
-    {file = "jupyter_client-7.3.5-py3-none-any.whl", hash = "sha256:b33222bdc9dd1714228bd286af006533a0abe2bbc093e8f3d29dc0b91bdc2be4"},
-    {file = "jupyter_client-7.3.5.tar.gz", hash = "sha256:3c58466a1b8d55dba0bf3ce0834e4f5b7760baf98d1d73db0add6f19de9ecd1d"},
-]
-jupyter-core = [
-    {file = "jupyter_core-4.11.1-py3-none-any.whl", hash = "sha256:715e22bb6cc7db3718fddfac1f69f1c7e899ca00e42bdfd4bf3705452b9fd84a"},
-    {file = "jupyter_core-4.11.1.tar.gz", hash = "sha256:2e5f244d44894c4154d06aeae3419dd7f1b0ef4494dc5584929b398c61cfd314"},
-]
-lxml = [
-    {file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"},
-    {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"},
-    {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc"},
-    {file = "lxml-4.9.1-cp27-cp27m-win32.whl", hash = "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3"},
-    {file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"},
-    {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"},
-    {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"},
-    {file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"},
-    {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"},
-    {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"},
-    {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8"},
-    {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d"},
-    {file = "lxml-4.9.1-cp310-cp310-win32.whl", hash = "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7"},
-    {file = "lxml-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b"},
-    {file = "lxml-4.9.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d"},
-    {file = "lxml-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3"},
-    {file = "lxml-4.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29"},
-    {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d"},
-    {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318"},
-    {file = "lxml-4.9.1-cp35-cp35m-win32.whl", hash = "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7"},
-    {file = "lxml-4.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4"},
-    {file = "lxml-4.9.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb"},
-    {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067"},
-    {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536"},
-    {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8"},
-    {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b"},
-    {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf"},
-    {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3"},
-    {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391"},
-    {file = "lxml-4.9.1-cp36-cp36m-win32.whl", hash = "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e"},
-    {file = "lxml-4.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7"},
-    {file = "lxml-4.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2"},
-    {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc"},
-    {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c"},
-    {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4"},
-    {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3"},
-    {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca"},
-    {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785"},
-    {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785"},
-    {file = "lxml-4.9.1-cp37-cp37m-win32.whl", hash = "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a"},
-    {file = "lxml-4.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e"},
-    {file = "lxml-4.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b"},
-    {file = "lxml-4.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97"},
-    {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21"},
-    {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2"},
-    {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130"},
-    {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715"},
-    {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036"},
-    {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387"},
-    {file = "lxml-4.9.1-cp38-cp38-win32.whl", hash = "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94"},
-    {file = "lxml-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345"},
-    {file = "lxml-4.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67"},
-    {file = "lxml-4.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb"},
-    {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448"},
-    {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7"},
-    {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91"},
-    {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000"},
-    {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25"},
-    {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd"},
-    {file = "lxml-4.9.1-cp39-cp39-win32.whl", hash = "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb"},
-    {file = "lxml-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d"},
-    {file = "lxml-4.9.1-pp37-pypy37_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c"},
-    {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b"},
-    {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc"},
-    {file = "lxml-4.9.1-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b"},
-    {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2"},
-    {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73"},
-    {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c"},
-    {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9"},
-    {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"},
-]
-MarkupSafe = [
-    {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"},
-    {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"},
-    {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"},
-    {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"},
-    {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"},
-    {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"},
-    {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"},
-    {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"},
-    {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"},
-    {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"},
-    {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"},
-    {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"},
-    {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"},
-    {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"},
-    {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"},
-    {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"},
-    {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"},
-    {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"},
-    {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"},
-    {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"},
-    {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"},
-    {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"},
-]
-matplotlib-inline = [
-    {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"},
-    {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"},
-]
-nest-asyncio = [
-    {file = "nest_asyncio-1.5.6-py3-none-any.whl", hash = "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8"},
-    {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"},
-]
-networkx = [
-    {file = "networkx-2.8.7-py3-none-any.whl", hash = "sha256:15cdf7f7c157637107ea690cabbc488018f8256fa28242aed0fb24c93c03a06d"},
-    {file = "networkx-2.8.7.tar.gz", hash = "sha256:815383fd52ece0a7024b5fd8408cc13a389ea350cd912178b82eed8b96f82cd3"},
-]
-ordered-set = [
-    {file = "ordered-set-4.1.0.tar.gz", hash = "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8"},
-    {file = "ordered_set-4.1.0-py3-none-any.whl", hash = "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562"},
-]
-packaging = [
-    {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
-    {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
-]
-parso = [
-    {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"},
-    {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"},
-]
-pexpect = [
-    {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
-    {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"},
-]
-pickleshare = [
-    {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"},
-    {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
-]
-pluggy = [
-    {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
-    {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
-]
-prettyprinter = [
-    {file = "prettyprinter-0.18.0-py2.py3-none-any.whl", hash = "sha256:358a58f276cb312e3ca29d7a7f244c91e4e0bda7848249d30e4f36d2eb58b67c"},
-    {file = "prettyprinter-0.18.0.tar.gz", hash = "sha256:9fe5da7ec53510881dd35d7a5c677ba45f34cfe6a8e78d1abd20652cf82139a8"},
-]
-prompt-toolkit = [
-    {file = "prompt_toolkit-3.0.31-py3-none-any.whl", hash = "sha256:9696f386133df0fc8ca5af4895afe5d78f5fcfe5258111c2a79a1c3e41ffa96d"},
-    {file = "prompt_toolkit-3.0.31.tar.gz", hash = "sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148"},
-]
-psutil = [
-    {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:8f024fbb26c8daf5d70287bb3edfafa22283c255287cf523c5d81721e8e5d82c"},
-    {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b2f248ffc346f4f4f0d747ee1947963613216b06688be0be2e393986fe20dbbb"},
-    {file = "psutil-5.9.2-cp27-cp27m-win32.whl", hash = "sha256:b1928b9bf478d31fdffdb57101d18f9b70ed4e9b0e41af751851813547b2a9ab"},
-    {file = "psutil-5.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:404f4816c16a2fcc4eaa36d7eb49a66df2d083e829d3e39ee8759a411dbc9ecf"},
-    {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:94e621c6a4ddb2573d4d30cba074f6d1aa0186645917df42c811c473dd22b339"},
-    {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:256098b4f6ffea6441eb54ab3eb64db9ecef18f6a80d7ba91549195d55420f84"},
-    {file = "psutil-5.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:614337922702e9be37a39954d67fdb9e855981624d8011a9927b8f2d3c9625d9"},
-    {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec06dc6c934fb53df10c1672e299145ce609ff0611b569e75a88f313634969"},
-    {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3ac2c0375ef498e74b9b4ec56df3c88be43fe56cac465627572dbfb21c4be34"},
-    {file = "psutil-5.9.2-cp310-cp310-win32.whl", hash = "sha256:e4c4a7636ffc47b7141864f1c5e7d649f42c54e49da2dd3cceb1c5f5d29bfc85"},
-    {file = "psutil-5.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:f4cb67215c10d4657e320037109939b1c1d2fd70ca3d76301992f89fe2edb1f1"},
-    {file = "psutil-5.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dc9bda7d5ced744622f157cc8d8bdd51735dafcecff807e928ff26bdb0ff097d"},
-    {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75291912b945a7351d45df682f9644540d564d62115d4a20d45fa17dc2d48f8"},
-    {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4018d5f9b6651f9896c7a7c2c9f4652e4eea53f10751c4e7d08a9093ab587ec"},
-    {file = "psutil-5.9.2-cp36-cp36m-win32.whl", hash = "sha256:f40ba362fefc11d6bea4403f070078d60053ed422255bd838cd86a40674364c9"},
-    {file = "psutil-5.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9770c1d25aee91417eba7869139d629d6328a9422ce1cdd112bd56377ca98444"},
-    {file = "psutil-5.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42638876b7f5ef43cef8dcf640d3401b27a51ee3fa137cb2aa2e72e188414c32"},
-    {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91aa0dac0c64688667b4285fa29354acfb3e834e1fd98b535b9986c883c2ce1d"},
-    {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fb54941aac044a61db9d8eb56fc5bee207db3bc58645d657249030e15ba3727"},
-    {file = "psutil-5.9.2-cp37-cp37m-win32.whl", hash = "sha256:7cbb795dcd8ed8fd238bc9e9f64ab188f3f4096d2e811b5a82da53d164b84c3f"},
-    {file = "psutil-5.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5d39e3a2d5c40efa977c9a8dd4f679763c43c6c255b1340a56489955dbca767c"},
-    {file = "psutil-5.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd331866628d18223a4265371fd255774affd86244fc307ef66eaf00de0633d5"},
-    {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b315febaebae813326296872fdb4be92ad3ce10d1d742a6b0c49fb619481ed0b"},
-    {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7929a516125f62399d6e8e026129c8835f6c5a3aab88c3fff1a05ee8feb840d"},
-    {file = "psutil-5.9.2-cp38-cp38-win32.whl", hash = "sha256:561dec454853846d1dd0247b44c2e66a0a0c490f937086930ec4b8f83bf44f06"},
-    {file = "psutil-5.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:67b33f27fc0427483b61563a16c90d9f3b547eeb7af0ef1b9fe024cdc9b3a6ea"},
-    {file = "psutil-5.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3591616fa07b15050b2f87e1cdefd06a554382e72866fcc0ab2be9d116486c8"},
-    {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b29f581b5edab1f133563272a6011925401804d52d603c5c606936b49c8b97"},
-    {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4642fd93785a29353d6917a23e2ac6177308ef5e8be5cc17008d885cb9f70f12"},
-    {file = "psutil-5.9.2-cp39-cp39-win32.whl", hash = "sha256:ed29ea0b9a372c5188cdb2ad39f937900a10fb5478dc077283bf86eeac678ef1"},
-    {file = "psutil-5.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:68b35cbff92d1f7103d8f1db77c977e72f49fcefae3d3d2b91c76b0e7aef48b8"},
-    {file = "psutil-5.9.2.tar.gz", hash = "sha256:feb861a10b6c3bb00701063b37e4afc754f8217f0f09c42280586bd6ac712b5c"},
-]
-ptyprocess = [
-    {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
-    {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
-]
-pure-eval = [
-    {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"},
-    {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"},
-]
-py = [
-    {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
-    {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
-]
-pycparser = [
-    {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
-    {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
-]
-pyecore = [
-    {file = "pyecore-0.12.2-py3-none-any.whl", hash = "sha256:8ebbefea2fcb97602ddb9eb859ae15d7c0900231128da92e10b7f9a9e1a29b76"},
-    {file = "pyecore-0.12.2.tar.gz", hash = "sha256:4fb417df37fc5433da37f3d42724f7c4cc36cbbe63988f3e43ad7653e0808387"},
-]
-Pygments = [
-    {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"},
-    {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"},
-]
-pyparsing = [
-    {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
-    {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
-]
-pyrsistent = [
-    {file = "pyrsistent-0.18.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1"},
-    {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26"},
-    {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e"},
-    {file = "pyrsistent-0.18.1-cp310-cp310-win32.whl", hash = "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6"},
-    {file = "pyrsistent-0.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec"},
-    {file = "pyrsistent-0.18.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b"},
-    {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc"},
-    {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22"},
-    {file = "pyrsistent-0.18.1-cp37-cp37m-win32.whl", hash = "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8"},
-    {file = "pyrsistent-0.18.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286"},
-    {file = "pyrsistent-0.18.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"},
-    {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec"},
-    {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c"},
-    {file = "pyrsistent-0.18.1-cp38-cp38-win32.whl", hash = "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca"},
-    {file = "pyrsistent-0.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a"},
-    {file = "pyrsistent-0.18.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5"},
-    {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045"},
-    {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c"},
-    {file = "pyrsistent-0.18.1-cp39-cp39-win32.whl", hash = "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc"},
-    {file = "pyrsistent-0.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07"},
-    {file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"},
-]
-pytest = [
-    {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"},
-    {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"},
-]
-python-dateutil = [
-    {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
-    {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
-]
-python-dotenv = [
-    {file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"},
-    {file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"},
-]
-pytz = [
-    {file = "pytz-2022.4-py2.py3-none-any.whl", hash = "sha256:2c0784747071402c6e99f0bafdb7da0fa22645f06554c7ae06bf6358897e9c91"},
-    {file = "pytz-2022.4.tar.gz", hash = "sha256:48ce799d83b6f8aab2020e369b627446696619e79645419610b9facd909b3174"},
-]
-pywin32 = [
-    {file = "pywin32-304-cp310-cp310-win32.whl", hash = "sha256:3c7bacf5e24298c86314f03fa20e16558a4e4138fc34615d7de4070c23e65af3"},
-    {file = "pywin32-304-cp310-cp310-win_amd64.whl", hash = "sha256:4f32145913a2447736dad62495199a8e280a77a0ca662daa2332acf849f0be48"},
-    {file = "pywin32-304-cp310-cp310-win_arm64.whl", hash = "sha256:d3ee45adff48e0551d1aa60d2ec066fec006083b791f5c3527c40cd8aefac71f"},
-    {file = "pywin32-304-cp311-cp311-win32.whl", hash = "sha256:30c53d6ce44c12a316a06c153ea74152d3b1342610f1b99d40ba2795e5af0269"},
-    {file = "pywin32-304-cp311-cp311-win_amd64.whl", hash = "sha256:7ffa0c0fa4ae4077e8b8aa73800540ef8c24530057768c3ac57c609f99a14fd4"},
-    {file = "pywin32-304-cp311-cp311-win_arm64.whl", hash = "sha256:cbbe34dad39bdbaa2889a424d28752f1b4971939b14b1bb48cbf0182a3bcfc43"},
-    {file = "pywin32-304-cp36-cp36m-win32.whl", hash = "sha256:be253e7b14bc601718f014d2832e4c18a5b023cbe72db826da63df76b77507a1"},
-    {file = "pywin32-304-cp36-cp36m-win_amd64.whl", hash = "sha256:de9827c23321dcf43d2f288f09f3b6d772fee11e809015bdae9e69fe13213988"},
-    {file = "pywin32-304-cp37-cp37m-win32.whl", hash = "sha256:f64c0377cf01b61bd5e76c25e1480ca8ab3b73f0c4add50538d332afdf8f69c5"},
-    {file = "pywin32-304-cp37-cp37m-win_amd64.whl", hash = "sha256:bb2ea2aa81e96eee6a6b79d87e1d1648d3f8b87f9a64499e0b92b30d141e76df"},
-    {file = "pywin32-304-cp38-cp38-win32.whl", hash = "sha256:94037b5259701988954931333aafd39cf897e990852115656b014ce72e052e96"},
-    {file = "pywin32-304-cp38-cp38-win_amd64.whl", hash = "sha256:ead865a2e179b30fb717831f73cf4373401fc62fbc3455a0889a7ddac848f83e"},
-    {file = "pywin32-304-cp39-cp39-win32.whl", hash = "sha256:25746d841201fd9f96b648a248f731c1dec851c9a08b8e33da8b56148e4c65cc"},
-    {file = "pywin32-304-cp39-cp39-win_amd64.whl", hash = "sha256:d24a3382f013b21aa24a5cfbfad5a2cd9926610c0affde3e8ab5b3d7dbcf4ac9"},
-]
-PyYAML = [
-    {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
-    {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
-    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
-    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
-    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
-    {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
-    {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
-    {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
-    {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
-    {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
-    {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
-    {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
-    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
-    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
-    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
-    {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
-    {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
-    {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
-    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
-    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
-    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
-    {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
-    {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
-    {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
-    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
-    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
-    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
-    {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
-    {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
-    {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
-    {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
-    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
-    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
-    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
-    {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
-    {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
-    {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
-]
-pyzmq = [
-    {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:28b119ba97129d3001673a697b7cce47fe6de1f7255d104c2f01108a5179a066"},
-    {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bcbebd369493d68162cddb74a9c1fcebd139dfbb7ddb23d8f8e43e6c87bac3a6"},
-    {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae61446166983c663cee42c852ed63899e43e484abf080089f771df4b9d272ef"},
-    {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f7ac99b15270db8d53f28c3c7b968612993a90a5cf359da354efe96f5372b4"},
-    {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca7c3956b03b7663fac4d150f5e6d4f6f38b2462c1e9afd83bcf7019f17913"},
-    {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8c78bfe20d4c890cb5580a3b9290f700c570e167d4cdcc55feec07030297a5e3"},
-    {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48f721f070726cd2a6e44f3c33f8ee4b24188e4b816e6dd8ba542c8c3bb5b246"},
-    {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afe1f3bc486d0ce40abb0a0c9adb39aed3bbac36ebdc596487b0cceba55c21c1"},
-    {file = "pyzmq-24.0.1-cp310-cp310-win32.whl", hash = "sha256:3e6192dbcefaaa52ed81be88525a54a445f4b4fe2fffcae7fe40ebb58bd06bfd"},
-    {file = "pyzmq-24.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:86de64468cad9c6d269f32a6390e210ca5ada568c7a55de8e681ca3b897bb340"},
-    {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:838812c65ed5f7c2bd11f7b098d2e5d01685a3f6d1f82849423b570bae698c00"},
-    {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfb992dbcd88d8254471760879d48fb20836d91baa90f181c957122f9592b3dc"},
-    {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7abddb2bd5489d30ffeb4b93a428130886c171b4d355ccd226e83254fcb6b9ef"},
-    {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94010bd61bc168c103a5b3b0f56ed3b616688192db7cd5b1d626e49f28ff51b3"},
-    {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8242543c522d84d033fe79be04cb559b80d7eb98ad81b137ff7e0a9020f00ace"},
-    {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ccb94342d13e3bf3ffa6e62f95b5e3f0bc6bfa94558cb37f4b3d09d6feb536ff"},
-    {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6640f83df0ae4ae1104d4c62b77e9ef39be85ebe53f636388707d532bee2b7b8"},
-    {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a180dbd5ea5d47c2d3b716d5c19cc3fb162d1c8db93b21a1295d69585bfddac1"},
-    {file = "pyzmq-24.0.1-cp311-cp311-win32.whl", hash = "sha256:624321120f7e60336be8ec74a172ae7fba5c3ed5bf787cc85f7e9986c9e0ebc2"},
-    {file = "pyzmq-24.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1724117bae69e091309ffb8255412c4651d3f6355560d9af312d547f6c5bc8b8"},
-    {file = "pyzmq-24.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:15975747462ec49fdc863af906bab87c43b2491403ab37a6d88410635786b0f4"},
-    {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b947e264f0e77d30dcbccbb00f49f900b204b922eb0c3a9f0afd61aaa1cedc3d"},
-    {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ec91f1bad66f3ee8c6deb65fa1fe418e8ad803efedd69c35f3b5502f43bd1dc"},
-    {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db03704b3506455d86ec72c3358a779e9b1d07b61220dfb43702b7b668edcd0d"},
-    {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e7e66b4e403c2836ac74f26c4b65d8ac0ca1eef41dfcac2d013b7482befaad83"},
-    {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7a23ccc1083c260fa9685c93e3b170baba45aeed4b524deb3f426b0c40c11639"},
-    {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fa0ae3275ef706c0309556061185dd0e4c4cd3b7d6f67ae617e4e677c7a41e2e"},
-    {file = "pyzmq-24.0.1-cp36-cp36m-win32.whl", hash = "sha256:f01de4ec083daebf210531e2cca3bdb1608dbbbe00a9723e261d92087a1f6ebc"},
-    {file = "pyzmq-24.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:de4217b9eb8b541cf2b7fde4401ce9d9a411cc0af85d410f9d6f4333f43640be"},
-    {file = "pyzmq-24.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:78068e8678ca023594e4a0ab558905c1033b2d3e806a0ad9e3094e231e115a33"},
-    {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77c2713faf25a953c69cf0f723d1b7dd83827b0834e6c41e3fb3bbc6765914a1"},
-    {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bb4af15f305056e95ca1bd086239b9ebc6ad55e9f49076d27d80027f72752f6"},
-    {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0f14cffd32e9c4c73da66db97853a6aeceaac34acdc0fae9e5bbc9370281864c"},
-    {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0108358dab8c6b27ff6b985c2af4b12665c1bc659648284153ee501000f5c107"},
-    {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d66689e840e75221b0b290b0befa86f059fb35e1ee6443bce51516d4d61b6b99"},
-    {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae08ac90aa8fa14caafc7a6251bd218bf6dac518b7bff09caaa5e781119ba3f2"},
-    {file = "pyzmq-24.0.1-cp37-cp37m-win32.whl", hash = "sha256:8421aa8c9b45ea608c205db9e1c0c855c7e54d0e9c2c2f337ce024f6843cab3b"},
-    {file = "pyzmq-24.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54d8b9c5e288362ec8595c1d98666d36f2070fd0c2f76e2b3c60fbad9bd76227"},
-    {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:acbd0a6d61cc954b9f535daaa9ec26b0a60a0d4353c5f7c1438ebc88a359a47e"},
-    {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:47b11a729d61a47df56346283a4a800fa379ae6a85870d5a2e1e4956c828eedc"},
-    {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abe6eb10122f0d746a0d510c2039ae8edb27bc9af29f6d1b05a66cc2401353ff"},
-    {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:07bec1a1b22dacf718f2c0e71b49600bb6a31a88f06527dfd0b5aababe3fa3f7"},
-    {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d945a85b70da97ae86113faf9f1b9294efe66bd4a5d6f82f2676d567338b66"},
-    {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1b7928bb7580736ffac5baf814097be342ba08d3cfdfb48e52773ec959572287"},
-    {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b946da90dc2799bcafa682692c1d2139b2a96ec3c24fa9fc6f5b0da782675330"},
-    {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c8840f064b1fb377cffd3efeaad2b190c14d4c8da02316dae07571252d20b31f"},
-    {file = "pyzmq-24.0.1-cp38-cp38-win32.whl", hash = "sha256:4854f9edc5208f63f0841c0c667260ae8d6846cfa233c479e29fdc85d42ebd58"},
-    {file = "pyzmq-24.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:42d4f97b9795a7aafa152a36fe2ad44549b83a743fd3e77011136def512e6c2a"},
-    {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:52afb0ac962963fff30cf1be775bc51ae083ef4c1e354266ab20e5382057dd62"},
-    {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bad8210ad4df68c44ff3685cca3cda448ee46e20d13edcff8909eba6ec01ca4"},
-    {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dabf1a05318d95b1537fd61d9330ef4313ea1216eea128a17615038859da3b3b"},
-    {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5bd3d7dfd9cd058eb68d9a905dec854f86649f64d4ddf21f3ec289341386c44b"},
-    {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8012bce6836d3f20a6c9599f81dfa945f433dab4dbd0c4917a6fb1f998ab33d"},
-    {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c31805d2c8ade9b11feca4674eee2b9cce1fec3e8ddb7bbdd961a09dc76a80ea"},
-    {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3104f4b084ad5d9c0cb87445cc8cfd96bba710bef4a66c2674910127044df209"},
-    {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:df0841f94928f8af9c7a1f0aaaffba1fb74607af023a152f59379c01c53aee58"},
-    {file = "pyzmq-24.0.1-cp39-cp39-win32.whl", hash = "sha256:a435ef8a3bd95c8a2d316d6e0ff70d0db524f6037411652803e118871d703333"},
-    {file = "pyzmq-24.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:2032d9cb994ce3b4cba2b8dfae08c7e25bc14ba484c770d4d3be33c27de8c45b"},
-    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bb5635c851eef3a7a54becde6da99485eecf7d068bd885ac8e6d173c4ecd68b0"},
-    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:83ea1a398f192957cb986d9206ce229efe0ee75e3c6635baff53ddf39bd718d5"},
-    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:941fab0073f0a54dc33d1a0460cb04e0d85893cb0c5e1476c785000f8b359409"},
-    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8f482c44ccb5884bf3f638f29bea0f8dc68c97e38b2061769c4cb697f6140d"},
-    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:613010b5d17906c4367609e6f52e9a2595e35d5cc27d36ff3f1b6fa6e954d944"},
-    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:65c94410b5a8355cfcf12fd600a313efee46ce96a09e911ea92cf2acf6708804"},
-    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:20e7eeb1166087db636c06cae04a1ef59298627f56fb17da10528ab52a14c87f"},
-    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2712aee7b3834ace51738c15d9ee152cc5a98dc7d57dd93300461b792ab7b43"},
-    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a7c280185c4da99e0cc06c63bdf91f5b0b71deb70d8717f0ab870a43e376db8"},
-    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:858375573c9225cc8e5b49bfac846a77b696b8d5e815711b8d4ba3141e6e8879"},
-    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:80093b595921eed1a2cead546a683b9e2ae7f4a4592bb2ab22f70d30174f003a"},
-    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f3f3154fde2b1ff3aa7b4f9326347ebc89c8ef425ca1db8f665175e6d3bd42f"},
-    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb756147314430bee5d10919b8493c0ccb109ddb7f5dfd2fcd7441266a25b75"},
-    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e706bac34e9f50779cb8c39f10b53a4d15aebb97235643d3112ac20bd577b4"},
-    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:687700f8371643916a1d2c61f3fdaa630407dd205c38afff936545d7b7466066"},
-    {file = "pyzmq-24.0.1.tar.gz", hash = "sha256:216f5d7dbb67166759e59b0479bca82b8acf9bed6015b526b8eb10143fb08e77"},
-]
-requests = [
-    {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
-    {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
-]
-RestrictedPython = [
-    {file = "RestrictedPython-5.0-py2.py3-none-any.whl", hash = "sha256:9bd69505147b0ff8c68f4ff5a275975a3ab66fc43cbf3b61a195650ed767cd4e"},
-    {file = "RestrictedPython-5.0.tar.gz", hash = "sha256:a080569bffdf53371ae3e754ab1732f43054b1bab904fc100f74ba68ac731abc"},
-]
-setuptools = [
-    {file = "setuptools-65.4.1-py3-none-any.whl", hash = "sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012"},
-    {file = "setuptools-65.4.1.tar.gz", hash = "sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e"},
-]
-six = [
-    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
-    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
-]
-sniffio = [
-    {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"},
-    {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"},
-]
-snowballstemmer = [
-    {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
-    {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
-]
-Sphinx = [
-    {file = "Sphinx-5.2.3.tar.gz", hash = "sha256:5b10cb1022dac8c035f75767799c39217a05fc0fe2d6fe5597560d38e44f0363"},
-    {file = "sphinx-5.2.3-py3-none-any.whl", hash = "sha256:7abf6fabd7b58d0727b7317d5e2650ef68765bbe0ccb63c8795fa8683477eaa2"},
-]
-sphinx-rtd-theme = [
-    {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"},
-    {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"},
-]
-sphinxcontrib-applehelp = [
-    {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"},
-    {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"},
-]
-sphinxcontrib-devhelp = [
-    {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"},
-    {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"},
-]
-sphinxcontrib-htmlhelp = [
-    {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"},
-    {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"},
-]
-sphinxcontrib-jsmath = [
-    {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
-    {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"},
-]
-sphinxcontrib-qthelp = [
-    {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"},
-    {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"},
-]
-sphinxcontrib-serializinghtml = [
-    {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"},
-    {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"},
-]
-stack-data = [
-    {file = "stack_data-0.5.1-py3-none-any.whl", hash = "sha256:5120731a18ba4c82cefcf84a945f6f3e62319ef413bfc210e32aca3a69310ba2"},
-    {file = "stack_data-0.5.1.tar.gz", hash = "sha256:95eb784942e861a3d80efd549ff9af6cf847d88343a12eb681d7157cfcb6e32b"},
-]
-swagger-ui-bundle = [
-    {file = "swagger_ui_bundle-0.0.9-py3-none-any.whl", hash = "sha256:cea116ed81147c345001027325c1ddc9ca78c1ee7319935c3c75d3669279d575"},
-    {file = "swagger_ui_bundle-0.0.9.tar.gz", hash = "sha256:b462aa1460261796ab78fd4663961a7f6f347ce01760f1303bbbdf630f11f516"},
-]
-tomli = [
-    {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
-    {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
-]
-tornado = [
-    {file = "tornado-6.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72"},
-    {file = "tornado-6.2-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9"},
-    {file = "tornado-6.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba09ef14ca9893954244fd872798b4ccb2367c165946ce2dd7376aebdde8e3ac"},
-    {file = "tornado-6.2-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8150f721c101abdef99073bf66d3903e292d851bee51910839831caba341a75"},
-    {file = "tornado-6.2-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3a2f5999215a3a06a4fc218026cd84c61b8b2b40ac5296a6db1f1451ef04c1e"},
-    {file = "tornado-6.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c52d219d4995388119af7ccaa0bcec289535747620116a58d830e7c25d8a8"},
-    {file = "tornado-6.2-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:6fdfabffd8dfcb6cf887428849d30cf19a3ea34c2c248461e1f7d718ad30b66b"},
-    {file = "tornado-6.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:1d54d13ab8414ed44de07efecb97d4ef7c39f7438cf5e976ccd356bebb1b5fca"},
-    {file = "tornado-6.2-cp37-abi3-win32.whl", hash = "sha256:5c87076709343557ef8032934ce5f637dbb552efa7b21d08e89ae7619ed0eb23"},
-    {file = "tornado-6.2-cp37-abi3-win_amd64.whl", hash = "sha256:e5f923aa6a47e133d1cf87d60700889d7eae68988704e20c75fb2d65677a8e4b"},
-    {file = "tornado-6.2.tar.gz", hash = "sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13"},
-]
-traitlets = [
-    {file = "traitlets-5.4.0-py3-none-any.whl", hash = "sha256:93663cc8236093d48150e2af5e2ed30fc7904a11a6195e21bab0408af4e6d6c8"},
-    {file = "traitlets-5.4.0.tar.gz", hash = "sha256:3f2c4e435e271592fe4390f1746ea56836e3a080f84e7833f0f801d9613fec39"},
-]
-urllib3 = [
-    {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
-    {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
-]
-uvicorn = [
-    {file = "uvicorn-0.18.3-py3-none-any.whl", hash = "sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af"},
-    {file = "uvicorn-0.18.3.tar.gz", hash = "sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b"},
-]
-uvloop = [
-    {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce9f61938d7155f79d3cb2ffa663147d4a76d16e08f65e2c66b77bd41b356718"},
-    {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:68532f4349fd3900b839f588972b3392ee56042e440dd5873dfbbcd2cc67617c"},
-    {file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0949caf774b9fcefc7c5756bacbbbd3fc4c05a6b7eebc7c7ad6f825b23998d6d"},
-    {file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff3d00b70ce95adce264462c930fbaecb29718ba6563db354608f37e49e09024"},
-    {file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a5abddb3558d3f0a78949c750644a67be31e47936042d4f6c888dd6f3c95f4aa"},
-    {file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8efcadc5a0003d3a6e887ccc1fb44dec25594f117a94e3127954c05cf144d811"},
-    {file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3378eb62c63bf336ae2070599e49089005771cc651c8769aaad72d1bd9385a7c"},
-    {file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6aafa5a78b9e62493539456f8b646f85abc7093dd997f4976bb105537cf2635e"},
-    {file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c686a47d57ca910a2572fddfe9912819880b8765e2f01dc0dd12a9bf8573e539"},
-    {file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:864e1197139d651a76c81757db5eb199db8866e13acb0dfe96e6fc5d1cf45fc4"},
-    {file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2a6149e1defac0faf505406259561bc14b034cdf1d4711a3ddcdfbaa8d825a05"},
-    {file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6708f30db9117f115eadc4f125c2a10c1a50d711461699a0cbfaa45b9a78e376"},
-    {file = "uvloop-0.17.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:23609ca361a7fc587031429fa25ad2ed7242941adec948f9d10c045bfecab06b"},
-    {file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2deae0b0fb00a6af41fe60a675cec079615b01d68beb4cc7b722424406b126a8"},
-    {file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45cea33b208971e87a31c17622e4b440cac231766ec11e5d22c76fab3bf9df62"},
-    {file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9b09e0f0ac29eee0451d71798878eae5a4e6a91aa275e114037b27f7db72702d"},
-    {file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dbbaf9da2ee98ee2531e0c780455f2841e4675ff580ecf93fe5c48fe733b5667"},
-    {file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a4aee22ece20958888eedbad20e4dbb03c37533e010fb824161b4f05e641f738"},
-    {file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:307958f9fc5c8bb01fad752d1345168c0abc5d62c1b72a4a8c6c06f042b45b20"},
-    {file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ebeeec6a6641d0adb2ea71dcfb76017602ee2bfd8213e3fcc18d8f699c5104f"},
-    {file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1436c8673c1563422213ac6907789ecb2b070f5939b9cbff9ef7113f2b531595"},
-    {file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8887d675a64cfc59f4ecd34382e5b4f0ef4ae1da37ed665adba0c2badf0d6578"},
-    {file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3db8de10ed684995a7f34a001f15b374c230f7655ae840964d51496e2f8a8474"},
-    {file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d37dccc7ae63e61f7b96ee2e19c40f153ba6ce730d8ba4d3b4e9738c1dccc1b"},
-    {file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cbbe908fda687e39afd6ea2a2f14c2c3e43f2ca88e3a11964b297822358d0e6c"},
-    {file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d97672dc709fa4447ab83276f344a165075fd9f366a97b712bdd3fee05efae8"},
-    {file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1e507c9ee39c61bfddd79714e4f85900656db1aec4d40c6de55648e85c2799c"},
-    {file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c092a2c1e736086d59ac8e41f9c98f26bbf9b9222a76f21af9dfe949b99b2eb9"},
-    {file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:30babd84706115626ea78ea5dbc7dd8d0d01a2e9f9b306d24ca4ed5796c66ded"},
-    {file = "uvloop-0.17.0.tar.gz", hash = "sha256:0ddf6baf9cf11a1a22c71487f39f15b2cf78eb5bde7e5b45fbb99e8a9d91b9e1"},
-]
-watchfiles = [
-    {file = "watchfiles-0.17.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:c7e1ffbd03cbcb46d1b7833e10e7d6b678ab083b4e4b80db06cfff5baca3c93f"},
-    {file = "watchfiles-0.17.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:539bcdb55a487126776c9d8c011094214d1df3f9a2321a6c0b1583197309405a"},
-    {file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:00e5f307a58752ec1478eeb738863544bde21cc7a2728bd1c216060406bde9c1"},
-    {file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:92675f379a9d5adbc6a52179f3e39aa56944c6eecb80384608fff2ed2619103a"},
-    {file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dd1e3181ad5d83ca35e9147c72e24f39437fcdf570c9cdc532016399fb62957"},
-    {file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:204950f1d6083539af5c8b7d4f5f8039c3ce36fa692da12d9743448f3199cb15"},
-    {file = "watchfiles-0.17.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:4056398d8f6d4972fe0918707b59d4cb84470c91d3c37f0e11e5a66c2a598760"},
-    {file = "watchfiles-0.17.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ffff3418dc753a2aed2d00200a4daeaac295c40458f8012836a65555f288be8b"},
-    {file = "watchfiles-0.17.0-cp37-abi3-win32.whl", hash = "sha256:b5c334cd3bc88aa4a8a1e08ec9f702b63c947211275defdc2dd79dc037fcb500"},
-    {file = "watchfiles-0.17.0-cp37-abi3-win_amd64.whl", hash = "sha256:53a2faeb121bc51bb6b960984f46901227e2e2475acc5a8d4c905a600436752d"},
-    {file = "watchfiles-0.17.0-cp37-abi3-win_arm64.whl", hash = "sha256:58dc3140dcf02a8aa76464a77a093016f10e89306fec21a4814922a64f3e8b9f"},
-    {file = "watchfiles-0.17.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:adcf15ecc2182ea9d2358c1a8c2b53203c3909484918776929b7bbe205522c0e"},
-    {file = "watchfiles-0.17.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:afd35a1bd3b9e68efe384ae7538481ae725597feb66f56f4bd23ecdbda726da0"},
-    {file = "watchfiles-0.17.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad2bdcae4c0f07ca6c090f5a2c30188cc6edba011b45e7c96eb1896648092367"},
-    {file = "watchfiles-0.17.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:a53cb6c06e5c1f216c792fbb432ce315239d432cb8b68d508547100939ec0399"},
-    {file = "watchfiles-0.17.0-pp39-pypy39_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6a3d6c699f3ce238dfa90bcef501f331a69b0d9b076f14459ed8eab26ba2f4cf"},
-    {file = "watchfiles-0.17.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f4271af86569bdbf131dd5c7c121c45d0ed194f3c88b88326e48a3b6a2db12"},
-    {file = "watchfiles-0.17.0.tar.gz", hash = "sha256:ae7c57ef920589a40270d5ef3216d693f4e6f8864d8fc8b6cb7885ca98ad2a61"},
-]
-wcwidth = [
-    {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
-    {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
-]
-websockets = [
-    {file = "websockets-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978"},
-    {file = "websockets-10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500"},
-    {file = "websockets-10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b"},
-    {file = "websockets-10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c"},
-    {file = "websockets-10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8"},
-    {file = "websockets-10.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677"},
-    {file = "websockets-10.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e"},
-    {file = "websockets-10.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f"},
-    {file = "websockets-10.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47"},
-    {file = "websockets-10.3-cp310-cp310-win32.whl", hash = "sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae"},
-    {file = "websockets-10.3-cp310-cp310-win_amd64.whl", hash = "sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079"},
-    {file = "websockets-10.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916"},
-    {file = "websockets-10.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb"},
-    {file = "websockets-10.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79"},
-    {file = "websockets-10.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d"},
-    {file = "websockets-10.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98"},
-    {file = "websockets-10.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e"},
-    {file = "websockets-10.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6"},
-    {file = "websockets-10.3-cp37-cp37m-win32.whl", hash = "sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1"},
-    {file = "websockets-10.3-cp37-cp37m-win_amd64.whl", hash = "sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4"},
-    {file = "websockets-10.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36"},
-    {file = "websockets-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69"},
-    {file = "websockets-10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd"},
-    {file = "websockets-10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2"},
-    {file = "websockets-10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c"},
-    {file = "websockets-10.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e"},
-    {file = "websockets-10.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991"},
-    {file = "websockets-10.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442"},
-    {file = "websockets-10.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76"},
-    {file = "websockets-10.3-cp38-cp38-win32.whl", hash = "sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559"},
-    {file = "websockets-10.3-cp38-cp38-win_amd64.whl", hash = "sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d"},
-    {file = "websockets-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094"},
-    {file = "websockets-10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667"},
-    {file = "websockets-10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731"},
-    {file = "websockets-10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9"},
-    {file = "websockets-10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680"},
-    {file = "websockets-10.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247"},
-    {file = "websockets-10.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af"},
-    {file = "websockets-10.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3"},
-    {file = "websockets-10.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8"},
-    {file = "websockets-10.3-cp39-cp39-win32.whl", hash = "sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582"},
-    {file = "websockets-10.3-cp39-cp39-win_amd64.whl", hash = "sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02"},
-    {file = "websockets-10.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7"},
-    {file = "websockets-10.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f"},
-    {file = "websockets-10.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4"},
-    {file = "websockets-10.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755"},
-    {file = "websockets-10.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55"},
-    {file = "websockets-10.3.tar.gz", hash = "sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4"},
-]
-Werkzeug = [
-    {file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"},
-    {file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"},
-]
-z3-solver = [
-    {file = "z3-solver-4.11.2.0.tar.gz", hash = "sha256:c7c7f10350db19eec831f9a45833268022c786e9ac0fbd9b2330956b377b9c39"},
-    {file = "z3_solver-4.11.2.0-py2.py3-none-macosx_10_16_x86_64.whl", hash = "sha256:90b34ffbd42ee9465ca047bfb99775c1000f6548f2b98bdeb7d52397347aa197"},
-    {file = "z3_solver-4.11.2.0-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:2cb81dcc220292dfcff6b5937f5faebeba4d0db7d2cc690f43e6f619bda40c47"},
-    {file = "z3_solver-4.11.2.0-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:9b5a11370df7ac27394fc660c812b2c9aac26f21fadf11e2c51a19cb707c1795"},
-    {file = "z3_solver-4.11.2.0-py2.py3-none-win32.whl", hash = "sha256:e4d3302c4046d65d0c8b5601d9b085f219b0fa78e312d08a5b24c86bb1629d05"},
-    {file = "z3_solver-4.11.2.0-py2.py3-none-win_amd64.whl", hash = "sha256:f763c6ad22a8455df46efa3755a75d5af5d40535a1e5ec5171c199cfda663e90"},
-]
-zipp = [
-    {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"},
-    {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"},
-]
diff --git a/pyproject.toml b/pyproject.toml
deleted file mode 100644
index 5555494edb4086027825211b318f958a3f79fc49..0000000000000000000000000000000000000000
--- a/pyproject.toml
+++ /dev/null
@@ -1,28 +0,0 @@
-[tool.poetry]
-name = "mc_openapi"
-version = "1.2.0"
-description = "OpenAPI interface for the PIACERE DOML model checker."
-authors = ["Michele Chiari <michele.chiari@polimi.it>", "Michele De Pascalis <michele.de.pascalis.1024@gmail.com>"]
-license = "Apache-2.0"
-
-[tool.poetry.dependencies]
-python = "^3.9"
-connexion = {extras = ["swagger-ui"], version = "^2.14"}
-pyecore = "^0.12.2"
-z3-solver = "^4.9"
-PyYAML = "^6.0"
-networkx = "^2.8"
-joblib = "^1.1"
-uvicorn = {extras = ["standard"], version = "^0.18"}
-
-[tool.poetry.dev-dependencies]
-pytest = "^7.0"
-requests = "^2.28"
-ipykernel = "^6.15"
-prettyprinter = "^0.18"
-Sphinx = "^5.0"
-sphinx-rtd-theme = "^1.0"
-
-[build-system]
-requires = ["poetry-core>=1.0.0"]
-build-backend = "poetry.core.masonry.api"
diff --git a/requirements.txt b/requirements.txt
index 33608f3d47393b4ec11aa1a1b6fea42cd1812fd1..b5475e5c8b9a4ef6d17a7ee2173db6e95a7ffa72 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,42 +1,54 @@
-anyio==3.6.1 ; python_version >= "3.9" and python_version < "4.0"
-attrs==22.1.0 ; python_version >= "3.9" and python_version < "4.0"
-certifi==2022.9.24 ; python_version >= "3.9" and python_version < "4"
-charset-normalizer==2.1.1 ; python_version >= "3.9" and python_version < "4"
-click==8.1.3 ; python_version >= "3.9" and python_version < "4.0"
-clickclick==20.10.2 ; python_version >= "3.9" and python_version < "4.0"
-colorama==0.4.5 ; sys_platform == "win32" and python_version >= "3.9" and python_version < "4.0" or python_version >= "3.9" and python_version < "4.0" and platform_system == "Windows"
-connexion[swagger-ui]==2.14.1 ; python_version >= "3.9" and python_version < "4.0"
-flask==2.2.2 ; python_version >= "3.9" and python_version < "4.0"
-future-fstrings==1.2.0 ; python_version >= "3.9" and python_version < "4.0"
-h11==0.14.0 ; python_version >= "3.9" and python_version < "4.0"
-httptools==0.5.0 ; python_version >= "3.9" and python_version < "4.0"
-idna==3.4 ; python_version >= "3.9" and python_version < "4"
-importlib-metadata==5.0.0 ; python_version >= "3.9" and python_version < "3.10"
-inflection==0.5.1 ; python_version >= "3.9" and python_version < "4.0"
-itsdangerous==2.1.2 ; python_version >= "3.9" and python_version < "4.0"
-jinja2==3.1.2 ; python_version >= "3.9" and python_version < "4.0"
-joblib==1.2.0 ; python_version >= "3.9" and python_version < "4.0"
-jsonschema==4.16.0 ; python_version >= "3.9" and python_version < "4.0"
-lxml==4.9.1 ; python_version >= "3.9" and python_version < "4.0"
-markupsafe==2.1.1 ; python_version >= "3.9" and python_version < "4.0"
-networkx==2.8.7 ; python_version >= "3.9" and python_version < "4.0"
-ordered-set==4.1.0 ; python_version >= "3.9" and python_version < "4.0"
-packaging==21.3 ; python_version >= "3.9" and python_version < "4.0"
-pyecore==0.12.2 ; python_version >= "3.9" and python_version < "4.0"
-pyparsing==3.0.9 ; python_version >= "3.9" and python_version < "4.0"
-pyrsistent==0.18.1 ; python_version >= "3.9" and python_version < "4.0"
-python-dotenv==0.21.0 ; python_version >= "3.9" and python_version < "4.0"
-pyyaml==6.0 ; python_version >= "3.9" and python_version < "4.0"
-requests==2.28.1 ; python_version >= "3.9" and python_version < "4"
-restrictedpython==5.0 ; python_version >= "3.9" and python_version < "4.0"
-setuptools==65.4.1 ; python_version >= "3.9" and python_version < "4.0"
-sniffio==1.3.0 ; python_version >= "3.9" and python_version < "4.0"
-swagger-ui-bundle==0.0.9 ; python_version >= "3.9" and python_version < "4.0"
-urllib3==1.26.12 ; python_version >= "3.9" and python_version < "4"
-uvicorn[standard]==0.18.3 ; python_version >= "3.9" and python_version < "4.0"
-uvloop==0.17.0 ; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" and python_version >= "3.9" and python_version < "4.0"
-watchfiles==0.17.0 ; python_version >= "3.9" and python_version < "4.0"
-websockets==10.3 ; python_version >= "3.9" and python_version < "4.0"
-werkzeug==2.2.2 ; python_version >= "3.9" and python_version < "4.0"
-z3-solver==4.11.2.0 ; python_version >= "3.9" and python_version < "4.0"
-zipp==3.8.1 ; python_version >= "3.9" and python_version < "3.10"
+alabaster==0.7.13
+attrs==22.2.0
+Babel==2.11.0
+beautifulsoup4==4.11.1
+certifi==2022.12.7
+charset-normalizer==3.0.1
+click==8.1.3
+clickclick==20.10.2
+connexion==2.14.2
+docutils==0.19
+Flask==2.2.2
+furo==2022.12.7
+future-fstrings==1.2.0
+h11==0.14.0
+idna==3.4
+imagesize==1.4.1
+inflection==0.5.1
+iniconfig==2.0.0
+itsdangerous==2.1.2
+Jinja2==3.1.2
+joblib==1.2.0
+jsonschema==4.17.3
+lark==1.1.5
+lxml==4.9.2
+MarkupSafe==2.1.2
+networkx==3.0
+ordered-set==4.1.0
+packaging==23.0
+piacere-doml-synthesis==2023.1.3
+pluggy==1.0.0
+pyecore==0.13.0
+Pygments==2.14.0
+pyrsistent==0.19.3
+pytest==7.2.1
+pytz==2022.7.1
+PyYAML==6.0
+requests==2.28.2
+RestrictedPython==6.0
+snowballstemmer==2.2.0
+soupsieve==2.3.2.post1
+Sphinx==6.1.3
+sphinx-basic-ng==1.0.0b1
+sphinxcontrib-applehelp==1.0.4
+sphinxcontrib-devhelp==1.0.2
+sphinxcontrib-htmlhelp==2.0.0
+sphinxcontrib-jsmath==1.0.1
+sphinxcontrib-qthelp==1.0.3
+sphinxcontrib-serializinghtml==1.1.5
+swagger-ui-bundle==0.0.9
+termcolor==2.2.0
+urllib3==1.26.14
+uvicorn==0.20.0
+Werkzeug==2.2.2
+z3-solver==4.11.2.0
diff --git a/tests/doml/v2.0/nginx-openstack_v2.0_valid_mem_req.domlx b/tests/doml/v2.0/nginx-openstack_v2.0_valid_mem_req.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..79ba8b959d36aa642f1b3515e830e80af943e4aa
--- /dev/null
+++ b/tests/doml/v2.0/nginx-openstack_v2.0_valid_mem_req.domlx
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_openstack" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="app">
+    <components xsi:type="app:SoftwareComponent" name="nginx">
+      <annotations xsi:type="commons:SProperty" key="source_code" value="/usr/share/nginx/html/index.html"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <generators xsi:type="infra:VMImage" name="v_img" generatedVMs="//@infrastructure/@groups.0/@machineDefinition"/>
+    <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/>
+    <groups xsi:type="infra:AutoScalingGroup" name="ag" deploymentNetwork="//@infrastructure/@networks.0">
+      <machineDefinition name="vm1" os="ubuntu-20.04.3" memory_mb="512.0" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0">
+        <ifaces name="i1" endPoint="16.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+      </machineDefinition>
+    </groups>
+    <securityGroups name="sg" ifaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0">
+      <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+    </securityGroups>
+    <networks name="net1" protocol="tcp/ip" addressRange="16.0.0.0/24" connectedIfaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"/>
+  </infrastructure>
+  <concretizations name="con_infra">
+    <providers name="openstack">
+      <vms name="concrete_vm" maps="//@infrastructure/@groups.0/@machineDefinition">
+        <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/>
+        <annotations xsi:type="commons:SProperty" key="vm_flavor" value="small"/>
+        <annotations xsi:type="commons:SProperty" key="vm_key_name" value="user1"/>
+      </vms>
+      <vmImages name="concrete_vm_image" maps="//@infrastructure/@generators.0">
+        <annotations xsi:type="commons:SProperty" key="name" value="ubuntu-20.04.3"/>
+      </vmImages>
+      <networks name="concrete_net" maps="//@infrastructure/@networks.0">
+        <annotations xsi:type="commons:SProperty" key="name" value="ostack2"/>
+      </networks>
+    </providers>
+  </concretizations>
+  <optimization name="opt">
+    <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost &lt;= 200" property="cost" max="200.0"/>
+    <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider">
+      <values>AMAZ</values>
+    </nonfunctionalRequirements>
+  </optimization>
+  <configurations name="config">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@groups.0/@machineDefinition"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.0/nginx-openstack_v2.0_wrong_nginx_source_code.domlx b/tests/doml/v2.0/nginx-openstack_v2.0_wrong_nginx_source_code.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..455b90f55300e3a4d61b4c5d726a1224fa9d81dc
--- /dev/null
+++ b/tests/doml/v2.0/nginx-openstack_v2.0_wrong_nginx_source_code.domlx
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_openstack" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="app">
+    <components xsi:type="app:SoftwareComponent" name="nginx"/>
+  </application>
+  <infrastructure name="infra">
+    <generators xsi:type="infra:VMImage" name="v_img" generatedVMs="//@infrastructure/@groups.0/@machineDefinition"/>
+    <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/>
+    <groups xsi:type="infra:AutoScalingGroup" name="ag" deploymentNetwork="//@infrastructure/@networks.0">
+      <machineDefinition name="vm1" os="ubuntu-20.04.3" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0">
+        <ifaces name="i1" endPoint="16.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+      </machineDefinition>
+    </groups>
+    <securityGroups name="sg" ifaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0">
+      <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+    </securityGroups>
+    <networks name="net1" protocol="tcp/ip" addressRange="16.0.0.0/24" connectedIfaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0"/>
+  </infrastructure>
+  <concretizations name="con_infra">
+    <providers name="openstack">
+      <vms name="concrete_vm" maps="//@infrastructure/@groups.0/@machineDefinition">
+        <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/>
+        <annotations xsi:type="commons:SProperty" key="vm_flavor" value="small"/>
+        <annotations xsi:type="commons:SProperty" key="vm_key_name" value="user1"/>
+      </vms>
+      <vmImages name="concrete_vm_image" maps="//@infrastructure/@generators.0">
+        <annotations xsi:type="commons:SProperty" key="name" value="ubuntu-20.04.3"/>
+      </vmImages>
+      <networks name="concrete_net" maps="//@infrastructure/@networks.0">
+        <annotations xsi:type="commons:SProperty" key="name" value="ostack2"/>
+      </networks>
+    </providers>
+  </concretizations>
+  <optimization name="opt">
+    <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost &lt;= 200" property="cost" max="200.0"/>
+    <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider">
+      <values>AMAZ</values>
+    </nonfunctionalRequirements>
+  </optimization>
+  <configurations name="config">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@groups.0/@machineDefinition"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.0/openstack_template.domlx b/tests/doml/v2.0/openstack_template.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..514308a5a88e83ed0173b8af5b5d698bc00744ff
--- /dev/null
+++ b/tests/doml/v2.0/openstack_template.domlx
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_openstack" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="app">
+    <components xsi:type="app:SoftwareComponent" name="nginx">
+      <annotations xsi:type="commons:SProperty" key="source_code" value="/usr/share/nginx/html/index.html"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <nodes xsi:type="infra:VirtualMachine" name="vm1" os="ubuntu-20.04.3"/>
+  </infrastructure>
+  <concretizations name="con_infra">
+    <providers name="openstack">
+      <vms name="concrete_vm" maps="//@infrastructure/@nodes.0">
+        <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/>
+        <annotations xsi:type="commons:SProperty" key="vm_flavor" value="small"/>
+        <annotations xsi:type="commons:SProperty" key="vm_key_name" value="user1"/>
+      </vms>
+    </providers>
+  </concretizations>
+  <optimization name="opt">
+    <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/>
+  </optimization>
+  <configurations name="config">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.0/saas.domlx b/tests/doml/v2.0/saas.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..bdfa1f32b00544dc4215557ea74c98884e61e693
--- /dev/null
+++ b/tests/doml/v2.0/saas.domlx
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="iot_simple_app">
+    <components xsi:type="app:DBMS" name="oracle">
+      <exposedInterfaces name="sql_interface"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0">
+      <exposedInterfaces name="sensor_info"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/>
+    <components xsi:type="app:SaaS" name="external_meteo">
+      <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <nodes xsi:type="infra:VirtualMachine" name="vm1">
+      <ifaces name="i1" endPoint="10.0.0.2" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:VirtualMachine" name="vm2">
+      <ifaces name="i1" endPoint="10.0.0.3" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1">
+      <ifaces name="i1" endPoint="10.0.0.4" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2">
+      <ifaces name="i1" endPoint="10.0.0.5" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/>
+    <securityGroups name="sg1" ifaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0">
+      <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+    </securityGroups>
+    <networks name="net1" protocol="tcp/ip" addressRange="10.0.0.0/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"/>
+  </infrastructure>
+  <concretizations name="con_infra1">
+    <providers name="aws">
+      <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0">
+        <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/>
+      </vms>
+      <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/>
+      <networks name="concrete_net1" maps="//@infrastructure/@networks.0"/>
+    </providers>
+  </concretizations>
+  <optimization name="opt">
+    <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost &lt;= 200" property="cost" max="200.0"/>
+    <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider">
+      <values>AMAZ</values>
+    </nonfunctionalRequirements>
+  </optimization>
+  <configurations name="config1">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/>
+    <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.0/saas_https_no_attrs.domlx b/tests/doml/v2.0/saas_https_no_attrs.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..38cf851c241d1de8d8d970c58117e7e5c9f026e3
--- /dev/null
+++ b/tests/doml/v2.0/saas_https_no_attrs.domlx
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="iot_simple_app">
+    <components xsi:type="app:DBMS" name="oracle">
+      <exposedInterfaces name="sql_interface"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0">
+      <exposedInterfaces name="sensor_info"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/>
+    <components xsi:type="app:SaaS" name="external_meteo">
+      <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <nodes xsi:type="infra:VirtualMachine" name="vm1">
+      <ifaces name="i1" endPoint="10.0.0.2" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:VirtualMachine" name="vm2">
+      <ifaces name="i1" endPoint="10.0.0.3" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1">
+      <ifaces name="i1" endPoint="10.0.0.4" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2">
+      <ifaces name="i1" endPoint="10.0.0.5" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/>
+    <securityGroups name="sg1" ifaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0">
+      <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="https" kind="INGRESS"/>
+      <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+    </securityGroups>
+    <networks name="net1" protocol="tcp/ip" addressRange="10.0.0.0/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"/>
+  </infrastructure>
+  <concretizations name="con_infra1">
+    <providers name="aws">
+      <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0">
+        <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/>
+      </vms>
+      <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/>
+      <networks name="concrete_net1" maps="//@infrastructure/@networks.0"/>
+    </providers>
+  </concretizations>
+  <optimization name="opt">
+    <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost &lt;= 200" property="cost" max="200.0"/>
+    <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider">
+      <values>AMAZ</values>
+    </nonfunctionalRequirements>
+  </optimization>
+  <configurations name="config1">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/>
+    <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.0/saas_no_https_rule.domlx b/tests/doml/v2.0/saas_no_https_rule.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..8d824c6679283729984ceec8bc4ff0c4a313729f
--- /dev/null
+++ b/tests/doml/v2.0/saas_no_https_rule.domlx
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="iot_simple_app">
+    <components xsi:type="app:DBMS" name="oracle">
+      <exposedInterfaces name="sql_interface"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0">
+      <exposedInterfaces name="sensor_info"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/>
+    <components xsi:type="app:SaaS" name="external_meteo">
+      <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <nodes xsi:type="infra:VirtualMachine" name="vm1">
+      <ifaces name="i1" endPoint="10.0.0.2" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:VirtualMachine" name="vm2">
+      <ifaces name="i1" endPoint="10.0.0.3" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1">
+      <ifaces name="i1" endPoint="10.0.0.4" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2">
+      <ifaces name="i1" endPoint="10.0.0.5" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/>
+    <securityGroups name="sg1" ifaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0">
+      <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+    </securityGroups>
+    <networks name="net1" protocol="tcp/ip" addressRange="10.0.0.0/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"/>
+  </infrastructure>
+  <concretizations name="con_infra1">
+    <providers name="aws">
+      <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0">
+        <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/>
+      </vms>
+      <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/>
+      <networks name="concrete_net1" maps="//@infrastructure/@networks.0"/>
+    </providers>
+  </concretizations>
+  <optimization name="opt">
+    <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost &lt;= 200" property="cost" max="200.0"/>
+    <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider">
+      <values>AMAZ</values>
+    </nonfunctionalRequirements>
+  </optimization>
+  <configurations name="config1">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/>
+    <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.0/saas_wrong_no_iface_sg.domlx b/tests/doml/v2.0/saas_wrong_no_iface_sg.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..be6aaffdf2eda69c3eef4d1ebbf936ae2b5afdbe
--- /dev/null
+++ b/tests/doml/v2.0/saas_wrong_no_iface_sg.domlx
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="iot_simple_app">
+    <components xsi:type="app:DBMS" name="oracle">
+      <exposedInterfaces name="sql_interface"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0">
+      <exposedInterfaces name="sensor_info"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/>
+    <components xsi:type="app:SaaS" name="external_meteo">
+      <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <nodes xsi:type="infra:VirtualMachine" name="vm1">
+      <ifaces name="i1" endPoint="10.0.0.2" belongsTo="//@infrastructure/@networks.0"/>
+    </nodes>
+    <nodes xsi:type="infra:VirtualMachine" name="vm2">
+      <ifaces name="i1" endPoint="10.0.0.3" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1">
+      <ifaces name="i1" endPoint="10.0.0.4" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2">
+      <ifaces name="i1" endPoint="10.0.0.5" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+    </nodes>
+    <credentials xsi:type="infra:KeyPair" name="ssh_key" user="ubuntu" keyfile="/home/user1/.ssh/openstack.key" algorithm="RSA" bits="4096"/>
+    <securityGroups name="sg1" ifaces="//@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0">
+      <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+    </securityGroups>
+    <networks name="net1" protocol="tcp/ip" addressRange="10.0.0.0/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0 //@infrastructure/@nodes.1/@ifaces.0 //@infrastructure/@nodes.2/@ifaces.0 //@infrastructure/@nodes.3/@ifaces.0"/>
+  </infrastructure>
+  <concretizations name="con_infra1">
+    <providers name="aws">
+      <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0">
+        <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/>
+      </vms>
+      <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/>
+      <networks name="concrete_net1" maps="//@infrastructure/@networks.0"/>
+    </providers>
+  </concretizations>
+  <optimization name="opt">
+    <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost &lt;= 200" property="cost" max="200.0"/>
+    <nonfunctionalRequirements xsi:type="commons:EnumeratedRequirement" name="req2" description="Provider" property="provider">
+      <values>AMAZ</values>
+    </nonfunctionalRequirements>
+  </optimization>
+  <configurations name="config1">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/>
+    <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.2/.project b/tests/doml/v2.2/.project
new file mode 100644
index 0000000000000000000000000000000000000000..96bcdb7a1076c114a39e5046f8f7d8a1b7c96daa
--- /dev/null
+++ b/tests/doml/v2.2/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>domlTests</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
+	</natures>
+</projectDescription>
diff --git a/tests/doml/v2.2/faas.doml b/tests/doml/v2.2/faas.doml
new file mode 100644
index 0000000000000000000000000000000000000000..9345cc7d776cafd80d1a0af2553202e6f8ea112d
--- /dev/null
+++ b/tests/doml/v2.2/faas.doml
@@ -0,0 +1,177 @@
+doml faas_app
+
+application ImageResizeApp {
+
+	software_component image_resize {
+		provides {
+			handle_image
+		}
+		consumes {
+			storage_interface,
+			bucket_in,
+			bucket_out
+		}
+		properties {
+			source_code = "path/lambda/function/image_resize.py";
+		}
+	}
+
+	saas s1 {
+		provides {
+			storage_interface
+			bucket_in
+		}
+	}
+
+	saas s2 {
+		provides {
+			storage_interface
+			bucket_out
+		}
+	}
+
+	software_component notification {
+		consumes {
+			handle_image,
+			bucket_in
+		}
+	}
+
+	software_component web {
+		consumes {
+			storage_interface,
+			bucket_out
+		}
+		properties {
+			source_code = "path/web_app";
+		}
+	}
+}
+
+infrastructure infra {
+	vm vm1 {
+		iface i1 {
+			address "10.0.0.1"
+			belongs_to vpc
+			security sg
+		}
+		credentials ssh_key
+		loc {
+			region "eu-central-1"
+		}
+	}
+
+	vm_image v_img {
+		generates vm1
+		image "ami-xxxxxxxxxxxxxxxxx"
+	}
+
+	container c {
+		host vm1
+	}
+
+	cont_image c_img {
+		generates c
+		image "web-app:0.1.0"
+	}
+
+	faas f { }
+
+	sto st1 { }
+
+	sto st2 { }
+
+	net vpc {
+		cidr "/24"
+		protocol "tcp/ip"
+		subnet vpc_subnet {
+			cidr "/24"
+			protocol "tcp/ip"
+		}
+	}
+
+	security_group sg {
+		egress icmp {
+			from_port -1
+			to_port -1
+			protocol "icmp"
+			cidr ["0.0.0.0/0"]
+		}
+		ingress http {
+			from_port 80
+			to_port 80
+			protocol "tcp"
+			cidr ["0.0.0.0/0"]
+		}
+		ingress https {
+			from_port 443
+			to_port 443
+			protocol "tcp"
+			cidr ["0.0.0.0/0"]
+		}
+		ingress ssh {
+			from_port 22
+			to_port 22
+			protocol "tcp"
+			cidr ["0.0.0.0/0"]
+		}
+		ifaces i1
+	}
+
+	key_pair ssh_key {
+		user "ec2-user"
+		keyfile "/tmp/ssh_key_file"
+		algorithm "RSA"
+		bits 4096
+	}
+}
+
+deployment config1 {
+	image_resize -> f,
+	web -> c,
+	s1 -> st1,
+	s2 -> st2
+}
+
+active deployment config1
+
+concretizations {
+	concrete_infrastructure con_infra {
+		provider aws {
+			vm concrete_vm {
+				properties {
+					instance_type = "t2.micro";
+					ssh_key_name = "demo-key";
+					ec2_role_name = "demo-ec2-role";
+				}
+				maps vm1
+			}
+			faas concrete_f {
+				properties {
+					lambda_role_name = "DemoLambdaRole";
+					lambda_runtime = "python3.8";
+					lambda_handler = "image_resize.lambda_handler";
+					lambda_timeout = 5;
+					lambda_memory = 128;
+				}
+				maps f
+			}
+			storage s3_bucket_in {
+				properties {
+					bucket_name = "bucket_in";
+				}
+				maps st1
+			}
+			storage s3_bucket_out {
+				properties {
+					bucket_name = "bucket_out";
+				}
+				maps st2
+			}
+			net concrete_net {
+				maps vpc
+			}
+		}
+	}
+	active con_infra
+}
\ No newline at end of file
diff --git a/tests/doml/v2.2/faas.domlx b/tests/doml/v2.2/faas.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..dc83d7135253786f5e7d1fbb9180c0ab1da9e2ca
--- /dev/null
+++ b/tests/doml/v2.2/faas.domlx
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" name="faas_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="ImageResizeApp">
+    <components xsi:type="app:SoftwareComponent" name="image_resize" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0 //@application/@components.1/@exposedInterfaces.1 //@application/@components.2/@exposedInterfaces.1">
+      <annotations xsi:type="commons:SProperty" key="source_code" value="path/lambda/function/image_resize.py"/>
+      <exposedInterfaces name="handle_image"/>
+    </components>
+    <components xsi:type="app:SaaS" name="s1">
+      <exposedInterfaces name="storage_interface"/>
+      <exposedInterfaces name="bucket_in"/>
+    </components>
+    <components xsi:type="app:SaaS" name="s2">
+      <exposedInterfaces name="storage_interface"/>
+      <exposedInterfaces name="bucket_out"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="notification" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.1/@exposedInterfaces.1"/>
+    <components xsi:type="app:SoftwareComponent" name="web" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0 //@application/@components.2/@exposedInterfaces.1">
+      <annotations xsi:type="commons:SProperty" key="source_code" value="path/web_app"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <nodes xsi:type="infra:VirtualMachine" name="vm1" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0">
+      <ifaces name="i1" endPoint="10.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+      <location region="eu-central-1"/>
+    </nodes>
+    <nodes xsi:type="infra:Container" name="c" generatedFrom="//@infrastructure/@generators.1">
+      <configs host="//@infrastructure/@nodes.0"/>
+    </nodes>
+    <generators xsi:type="infra:VMImage" name="v_img" uri="ami-xxxxxxxxxxxxxxxxx" kind="IMAGE" generatedVMs="//@infrastructure/@nodes.0"/>
+    <generators xsi:type="infra:ContainerImage" name="c_img" uri="web-app:0.1.0" kind="IMAGE" generatedContainers="//@infrastructure/@nodes.1"/>
+    <storages name="st1"/>
+    <storages name="st2"/>
+    <faas name="f"/>
+    <credentials xsi:type="commons:KeyPair" name="ssh_key" user="ec2-user" keyfile="/tmp/ssh_key_file" algorithm="RSA" bits="4096"/>
+    <securityGroups name="sg" ifaces="//@infrastructure/@nodes.0/@ifaces.0">
+      <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+    </securityGroups>
+    <networks name="vpc" protocol="tcp/ip" addressRange="/24" connectedIfaces="//@infrastructure/@nodes.0/@ifaces.0">
+      <subnets name="vpc_subnet" protocol="tcp/ip" addressRange="/24"/>
+    </networks>
+  </infrastructure>
+  <concretizations name="con_infra">
+    <providers name="aws">
+      <vms name="concrete_vm" maps="//@infrastructure/@nodes.0">
+        <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/>
+        <annotations xsi:type="commons:SProperty" key="ssh_key_name" value="demo-key"/>
+        <annotations xsi:type="commons:SProperty" key="ec2_role_name" value="demo-ec2-role"/>
+      </vms>
+      <networks name="concrete_net" maps="//@infrastructure/@networks.0"/>
+      <storages name="s3_bucket_in" maps="//@infrastructure/@storages.0">
+        <annotations xsi:type="commons:SProperty" key="bucket_name" value="bucket_in"/>
+      </storages>
+      <storages name="s3_bucket_out" maps="//@infrastructure/@storages.1">
+        <annotations xsi:type="commons:SProperty" key="bucket_name" value="bucket_out"/>
+      </storages>
+      <faas name="concrete_f" maps="//@infrastructure/@faas.0">
+        <annotations xsi:type="commons:SProperty" key="lambda_role_name" value="DemoLambdaRole"/>
+        <annotations xsi:type="commons:SProperty" key="lambda_runtime" value="python3.8"/>
+        <annotations xsi:type="commons:SProperty" key="lambda_handler" value="image_resize.lambda_handler"/>
+        <annotations xsi:type="commons:IProperty" key="lambda_timeout" value="5"/>
+        <annotations xsi:type="commons:IProperty" key="lambda_memory" value="128"/>
+      </faas>
+    </providers>
+  </concretizations>
+  <configurations name="config1">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@faas.0"/>
+    <deployments component="//@application/@components.4" node="//@infrastructure/@nodes.1"/>
+    <deployments component="//@application/@components.1" node="//@infrastructure/@storages.0"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@storages.1"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.2/iot_simple_app.doml b/tests/doml/v2.2/iot_simple_app.doml
new file mode 100644
index 0000000000000000000000000000000000000000..4dca09ac6ec52afa070731e6942535354b8eb5b4
--- /dev/null
+++ b/tests/doml/v2.2/iot_simple_app.doml
@@ -0,0 +1,52 @@
+doml iot_simple_app
+
+application iot_simple_app {
+	dbms oracle {
+		provides { sql_interface }
+	}
+
+	software_component web_server {
+		provides { sensor_info }
+		consumes { sql_interface, get_weather }
+	}
+
+	software_component iot_provider {
+		consumes { sensor_info }
+	}
+
+	saas external_meteo {
+		provides { get_weather @ "https://api.mymeteo.com/get" }
+	}
+}
+
+infrastructure infra {
+	vm vm1 {}
+	vm vm2 {}
+	node iot_device1 {}
+	node iot_device2 {}
+}
+
+deployment config1 {
+	oracle -> vm1,
+	web_server -> vm2,
+	iot_provider -> iot_device1,
+	iot_provider -> iot_device2
+}
+
+active deployment config1
+
+concretizations {
+	concrete_infrastructure con_infra1 {
+		provider aws {
+			vm concrete_vm1 {
+				properties { instance_type = "t2.micro"; }
+				maps vm1
+			}
+			vm concrete_vm2 {
+				properties {}
+				maps vm2
+			}
+		}
+	}
+	active con_infra1
+}
\ No newline at end of file
diff --git a/tests/doml/v2.2/iot_simple_app.domlx b/tests/doml/v2.2/iot_simple_app.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..d750eee5e1487c0b0097e48b3a92453dc3da95d2
--- /dev/null
+++ b/tests/doml/v2.2/iot_simple_app.domlx
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" name="iot_simple_app" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="iot_simple_app">
+    <components xsi:type="app:DBMS" name="oracle">
+      <exposedInterfaces name="sql_interface"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="web_server" consumedInterfaces="//@application/@components.0/@exposedInterfaces.0 //@application/@components.3/@exposedInterfaces.0">
+      <exposedInterfaces name="sensor_info"/>
+    </components>
+    <components xsi:type="app:SoftwareComponent" name="iot_provider" consumedInterfaces="//@application/@components.1/@exposedInterfaces.0"/>
+    <components xsi:type="app:SaaS" name="external_meteo">
+      <exposedInterfaces name="get_weather" endPoint="https://api.mymeteo.com/get"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <nodes xsi:type="infra:VirtualMachine" name="vm1"/>
+    <nodes xsi:type="infra:VirtualMachine" name="vm2"/>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device1"/>
+    <nodes xsi:type="infra:PhysicalComputingNode" name="iot_device2"/>
+  </infrastructure>
+  <concretizations name="con_infra1">
+    <providers name="aws">
+      <vms name="concrete_vm1" maps="//@infrastructure/@nodes.0">
+        <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/>
+      </vms>
+      <vms name="concrete_vm2" maps="//@infrastructure/@nodes.1"/>
+    </providers>
+  </concretizations>
+  <configurations name="config1">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@nodes.0"/>
+    <deployments component="//@application/@components.1" node="//@infrastructure/@nodes.1"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.2"/>
+    <deployments component="//@application/@components.2" node="//@infrastructure/@nodes.3"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.2/nginx-aws-ec2.doml b/tests/doml/v2.2/nginx-aws-ec2.doml
new file mode 100644
index 0000000000000000000000000000000000000000..8b1f7635abe55981f613ee869c490d364fd236a0
--- /dev/null
+++ b/tests/doml/v2.2/nginx-aws-ec2.doml
@@ -0,0 +1,121 @@
+doml nginx_aws_ec2
+
+application app {
+
+	software_component nginx {
+		properties {
+			source_code="/usr/share/nginx/html/index.html";
+		}
+	}
+}
+
+infrastructure infra {
+
+	vm_image vm_img {
+		generates vm1
+		image "ami-xxxxxxxxxxxxxxxxx"
+	}
+
+	net vpc {
+		cidr "/24"
+		protocol "tcp/ip"
+		subnet vpc_subnet {
+			cidr "/24"
+			protocol "tcp/ip"
+		}
+	}
+
+	security_group sg {
+		egress icmp {
+			from_port -1
+			to_port -1
+			protocol "icmp"
+			cidr ["0.0.0.0/0"]
+		}
+		ingress http {
+			from_port 80
+			to_port 80
+			protocol "tcp"
+			cidr ["0.0.0.0/0"]
+		}
+		ingress https {
+			from_port 443
+			to_port 443
+			protocol "tcp"
+			cidr ["0.0.0.0/0"]
+		}
+		ingress ssh {
+			from_port 22
+			to_port 22
+			protocol "tcp"
+			cidr ["0.0.0.0/0"]
+		}
+		ifaces i1
+	}
+
+	key_pair ssh_key {
+		user "ec2-user"
+		keyfile "/tmp/ssh_key_file"
+		algorithm "RSA"
+		bits 4096
+	}
+
+	autoscale_group ag {
+		vm vm1 {
+			iface i1 {
+				address "10.0.0.1"
+				belongs_to vpc
+				security sg
+			}
+			credentials ssh_key
+			loc {
+				region "eu-central-1"
+			}
+		}
+	}
+}
+
+deployment conf {
+	nginx -> vm1
+}
+
+active deployment conf
+
+concretizations {
+	concrete_infrastructure con_infra {
+		provider aws {
+			vm ec2_vm {
+				properties {
+					vm_name = "nginx-host";
+					instance_type = "t2.micro";
+					ssh_key_name = "demo-key";
+					ec2_role_name = "demo-ec2-role";
+				}
+				maps vm1
+			}
+
+			vm_image concrete_vm_image {
+				maps vm_img
+			}
+
+			net concrete_net {
+				properties {
+					vm_name = "nginx-host";
+				}
+				maps vpc
+			}
+		}
+	}
+	active con_infra
+}
+
+optimization opt {
+	objectives {
+		"cost" => min
+		"availability" => max
+	}
+	nonfunctional_requirements {
+		req1 "Cost <= 70.0" max 70.0 => "cost";
+		req2 "Availability >= 66.5%" min 66.5 => "availability";
+	}
+}
diff --git a/tests/doml/v2.2/nginx-aws-ec2.domlx b/tests/doml/v2.2/nginx-aws-ec2.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..14660f0286d3bb24560cccada553c121e06cd4e9
--- /dev/null
+++ b/tests/doml/v2.2/nginx-aws-ec2.domlx
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_aws_ec2" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="app">
+    <components xsi:type="app:SoftwareComponent" name="nginx">
+      <annotations xsi:type="commons:SProperty" key="source_code" value="/usr/share/nginx/html/index.html"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <generators xsi:type="infra:VMImage" name="vm_img" uri="ami-xxxxxxxxxxxxxxxxx" kind="IMAGE" generatedVMs="//@infrastructure/@groups.0/@machineDefinition"/>
+    <credentials xsi:type="commons:KeyPair" name="ssh_key" user="ec2-user" keyfile="/tmp/ssh_key_file" algorithm="RSA" bits="4096"/>
+    <groups xsi:type="infra:AutoScalingGroup" name="ag">
+      <machineDefinition name="vm1" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0">
+        <ifaces name="i1" endPoint="10.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+        <location region="eu-central-1"/>
+      </machineDefinition>
+    </groups>
+    <securityGroups name="sg" ifaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0">
+      <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+    </securityGroups>
+    <networks name="vpc" protocol="tcp/ip" addressRange="/24" connectedIfaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0">
+      <subnets name="vpc_subnet" protocol="tcp/ip" addressRange="/24"/>
+    </networks>
+  </infrastructure>
+  <concretizations name="con_infra">
+    <providers name="aws">
+      <vms name="ec2_vm" maps="//@infrastructure/@groups.0/@machineDefinition">
+        <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/>
+        <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/>
+        <annotations xsi:type="commons:SProperty" key="ssh_key_name" value="demo-key"/>
+        <annotations xsi:type="commons:SProperty" key="ec2_role_name" value="demo-ec2-role"/>
+      </vms>
+      <vmImages name="concrete_vm_image" maps="//@infrastructure/@generators.0"/>
+      <networks name="concrete_net" maps="//@infrastructure/@networks.0">
+        <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/>
+      </networks>
+    </providers>
+  </concretizations>
+  <optimization name="opt">
+    <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/>
+    <objectives xsi:type="optimization:MeasurableObjective" kind="max" property="availability"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost &lt;= 70.0" property="cost" max="70.0"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req2" description="Availability >= 66.5%" property="availability" min="66.5"/>
+  </optimization>
+  <configurations name="conf">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@groups.0/@machineDefinition"/>
+  </configurations>
+</commons:DOMLModel>
diff --git a/tests/doml/v2.2/nginx_func_req.doml b/tests/doml/v2.2/nginx_func_req.doml
new file mode 100644
index 0000000000000000000000000000000000000000..f810a6be84417f7a40da07b084b08c4e5f50db8a
--- /dev/null
+++ b/tests/doml/v2.2/nginx_func_req.doml
@@ -0,0 +1,149 @@
+doml nginx_func_req
+
+application app {
+
+	software_component nginx {
+		properties {
+			source_code="/usr/share/nginx/html/index.html";
+		}
+	}
+}
+
+infrastructure infra {
+
+	vm_image vm_img {
+		generates vm1
+		image "ami-xxxxxxxxxxxxxxxxx"
+	}
+
+	net vpc {
+		cidr "/24"
+		protocol "tcp/ip"
+		subnet vpc_subnet {
+			cidr "/24"
+			protocol "tcp/ip"
+		}
+	}
+
+	security_group sg {
+		egress icmp {
+			from_port -1
+			to_port -1
+			protocol "icmp"
+			cidr ["0.0.0.0/0"]
+		}
+		ingress http {
+			from_port 80
+			to_port 80
+			protocol "tcp"
+			cidr ["0.0.0.0/0"]
+		}
+		ingress https {
+			from_port 443
+			to_port 443
+			protocol "tcp"
+			cidr ["0.0.0.0/0"]
+		}
+		ingress ssh {
+			from_port 22
+			to_port 22
+			protocol "tcp"
+			cidr ["0.0.0.0/0"]
+		}
+		ifaces i1
+	}
+
+	key_pair ssh_key {
+		user "ec2-user"
+		keyfile "/tmp/ssh_key_file"
+		algorithm "RSA"
+		bits 4096
+	}
+
+	autoscale_group ag {
+		vm vm1 {
+			iface i1 {
+				address "10.0.0.1"
+				belongs_to vpc
+				security sg
+			}
+			credentials ssh_key
+			loc {
+				region "eu-central-1"
+			}
+		}
+	}
+}
+
+deployment conf {
+	nginx -> vm1
+}
+
+active deployment conf
+
+concretizations {
+	concrete_infrastructure con_infra {
+		provider aws {
+			vm ec2_vm {
+				properties {
+					vm_name = "nginx-host";
+					instance_type = "t2.micro";
+					ssh_key_name = "demo-key";
+					ec2_role_name = "demo-ec2-role";
+				}
+				maps vm1
+			}
+
+			vm_image concrete_vm_image {
+				maps vm_img
+			}
+
+			net concrete_net {
+				properties {
+					vm_name = "nginx-host";
+				}
+				maps vpc
+			}
+		}
+	}
+	active con_infra
+}
+
+optimization opt {
+	objectives {
+		"cost" => min
+		"availability" => max
+	}
+	nonfunctional_requirements {
+		req1 "Cost <= 70.0" max 70.0 => "cost";
+		req2 "Availability >= 66.5%" min 66.5 => "availability";
+	}
+}
+
+functional_requirements {
+	req_ext ```
+        >   "example requirement to test"
+            # Expr to parse
+            not ( 
+                vm is class infrastructure.VirtualMachine
+                and
+                vm is not class infrastructure.Storage
+                or
+                vm is not class infrastructure.Storage
+                implies
+                vm is class infrastructure.Storage
+            )
+            iff
+            not exists iface, apple (
+                forall orange (
+                    vm has association infrastructure.ComputingNode->ifaces iface
+                    or
+                    vm has association infrastructure.ComputingNode->ifaces iface
+                )
+                and
+                vm has attribute infrastructure.ComputingNode->os Os1
+            )
+            ---
+            "Virtual Machine {vm} has no iface"
+	```;
+}
diff --git a/tests/doml/v2.2/nginx_func_req.domlx b/tests/doml/v2.2/nginx_func_req.domlx
new file mode 100644
index 0000000000000000000000000000000000000000..f0f4e5af2424f404c8532f60487286bcf46367fb
--- /dev/null
+++ b/tests/doml/v2.2/nginx_func_req.domlx
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="ASCII"?>
+<commons:DOMLModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:app="http://www.piacere-project.eu/doml/application" xmlns:commons="http://www.piacere-project.eu/doml/commons" xmlns:infra="http://www.piacere-project.eu/doml/infrastructure" xmlns:optimization="http://www.piacere-project.eu/doml/optimization" name="nginx_func_req" activeConfiguration="//@configurations.0" activeInfrastructure="//@concretizations.0">
+  <application name="app">
+    <components xsi:type="app:SoftwareComponent" name="nginx">
+      <annotations xsi:type="commons:SProperty" key="source_code" value="/usr/share/nginx/html/index.html"/>
+    </components>
+  </application>
+  <infrastructure name="infra">
+    <generators xsi:type="infra:VMImage" name="vm_img" uri="ami-xxxxxxxxxxxxxxxxx" kind="IMAGE" generatedVMs="//@infrastructure/@groups.0/@machineDefinition"/>
+    <credentials xsi:type="commons:KeyPair" name="ssh_key" user="ec2-user" keyfile="/tmp/ssh_key_file" algorithm="RSA" bits="4096"/>
+    <groups xsi:type="infra:AutoScalingGroup" name="ag">
+      <machineDefinition name="vm1" credentials="//@infrastructure/@credentials.0" generatedFrom="//@infrastructure/@generators.0">
+        <ifaces name="i1" endPoint="10.0.0.1" belongsTo="//@infrastructure/@networks.0" associated="//@infrastructure/@securityGroups.0"/>
+        <location region="eu-central-1"/>
+      </machineDefinition>
+    </groups>
+    <securityGroups name="sg" ifaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0">
+      <rules name="icmp" protocol="icmp" fromPort="-1" toPort="-1">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="http" kind="INGRESS" protocol="tcp" fromPort="80" toPort="80">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="https" kind="INGRESS" protocol="tcp" fromPort="443" toPort="443">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+      <rules name="ssh" kind="INGRESS" protocol="tcp" fromPort="22" toPort="22">
+        <cidr>0.0.0.0/0</cidr>
+      </rules>
+    </securityGroups>
+    <networks name="vpc" protocol="tcp/ip" addressRange="/24" connectedIfaces="//@infrastructure/@groups.0/@machineDefinition/@ifaces.0">
+      <subnets name="vpc_subnet" protocol="tcp/ip" addressRange="/24"/>
+    </networks>
+  </infrastructure>
+  <concretizations name="con_infra">
+    <providers name="aws">
+      <vms name="ec2_vm" maps="//@infrastructure/@groups.0/@machineDefinition">
+        <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/>
+        <annotations xsi:type="commons:SProperty" key="instance_type" value="t2.micro"/>
+        <annotations xsi:type="commons:SProperty" key="ssh_key_name" value="demo-key"/>
+        <annotations xsi:type="commons:SProperty" key="ec2_role_name" value="demo-ec2-role"/>
+      </vms>
+      <vmImages name="concrete_vm_image" maps="//@infrastructure/@generators.0"/>
+      <networks name="concrete_net" maps="//@infrastructure/@networks.0">
+        <annotations xsi:type="commons:SProperty" key="vm_name" value="nginx-host"/>
+      </networks>
+    </providers>
+  </concretizations>
+  <optimization name="opt">
+    <objectives xsi:type="optimization:MeasurableObjective" kind="min" property="cost"/>
+    <objectives xsi:type="optimization:MeasurableObjective" kind="max" property="availability"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req1" description="Cost &lt;= 70.0" property="cost" max="70.0"/>
+    <nonfunctionalRequirements xsi:type="commons:RangedRequirement" name="req2" description="Availability >= 66.5%" property="availability" min="66.5"/>
+  </optimization>
+  <configurations name="conf">
+    <deployments component="//@application/@components.0" node="//@infrastructure/@groups.0/@machineDefinition"/>
+  </configurations>
+  <functionalRequirements name="req_ext" description="+ &quot;All Virtual Machines have a Interface and at least 4 CPUs&quot; forall vm (vm is class abstract.VirtualMachine implies exists iface (vm has abstract.ComputingNode.ifaces iface and vm has abstract.ComputingNode.cpu_count >= 4 )) error: &quot;A vm does lacks an associated interface or has less than 4 CPUs&quot;"/>
+</commons:DOMLModel>
diff --git a/tests/domlr/example_multiple_reqs.domlr b/tests/domlr/example_multiple_reqs.domlr
new file mode 100644
index 0000000000000000000000000000000000000000..451857494997fd31bd458e29b6c09d8c19021338
--- /dev/null
+++ b/tests/domlr/example_multiple_reqs.domlr
@@ -0,0 +1,52 @@
+-   "VM must have iface"
+    vm is class infrastructure.VirtualMachine
+    and
+    not exists iface (
+        vm has infrastructure.ComputingNode.ifaces iface
+    )
+
+    error: "VM {vm} must have iface {iface}"
+
+# +   "VM must have iface"
+#     forall vm (
+#         vm is class infrastructure.VirtualMachine
+#         implies
+#         exists iface (
+#             vm has infrastructure.ComputingNode.ifaces iface
+#         )
+#     )
+
+#     error: "VM {vm} must have iface {iface}"
+
++   "VM must have cpu_count >= 4"
+    forall vm (
+        vm is class infrastructure.VirtualMachine
+        implies
+        vm has infrastructure.ComputingNode.cpu_count >= 4
+    )
+
+    error: "VM {vm} must have cpu_count >= 4 {iface}"
+
++   "VM must have os == 'rhel8'"
+    forall vm (
+        vm is class infrastructure.VirtualMachine
+        implies
+        vm has infrastructure.ComputingNode.os == "rhel8"
+    )
+
+    error: "VM {vm} must have os == 'rhel'"
+
+# OLD SYNTAX:
+# -   "Iface must be unique"
+#     ni1 has infrastructure.NetworkInterface.endPoint Value
+#     and
+#     ni1 is not ni2
+#     and
+#     ni2 has infrastructure.NetworkInterface.endPoint Value
+
+-   "Iface must be unique"
+    ni1 has infrastructure.NetworkInterface.endPoint == ni2 infrastructure.NetworkInterface.endPoint
+    and
+    ni1 is not ni2
+
+    error: "Iface {ni1} and {ni2} must have different values"
diff --git a/tests/domlr/example_single_req.domlr b/tests/domlr/example_single_req.domlr
new file mode 100644
index 0000000000000000000000000000000000000000..a3e87f406f7802d20ad1964591d49b2b7cad0210
--- /dev/null
+++ b/tests/domlr/example_single_req.domlr
@@ -0,0 +1,18 @@
+# vm, iface = get_consts(smtsorts, ["vm", "iface"])
+# return And(
+#     smtenc.element_class_fun(vm) == smtenc.classes["infrastructure_VirtualMachine"],
+#     Not(
+#         Exists(
+#             [iface],
+#             ENCODINGS.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], iface)
+#         )
+#     )
+# )
+
+-   "All VMs have at least one interface 1"
+    vm is class infrastructure.VirtualMachine
+    and
+    not exists iface (
+        vm has abstract.ComputingNode.ifaces iface
+    )
+    error: "VM {vm} has no associated interface."
diff --git a/tests/domlr/example_single_req_bad_syntax.domlr b/tests/domlr/example_single_req_bad_syntax.domlr
new file mode 100644
index 0000000000000000000000000000000000000000..195f5b49205d9368e0245a3d17334cda7a765ef9
--- /dev/null
+++ b/tests/domlr/example_single_req_bad_syntax.domlr
@@ -0,0 +1,21 @@
+# vm, iface = get_consts(smtsorts, ["vm", "iface"])
+# return And(
+#     smtenc.element_class_fun(vm) == smtenc.classes["infrastructure_VirtualMachine"],
+#     Not(
+#         Exists(
+#             [iface],
+#             ENCODINGS.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], iface)
+#         )
+#     )
+# )
+
++   "All VMs have at least one interface 1"
+    vm is class infrastructure.VirtualMachine
+    and
+    not exists iface (
+        vm has infrastructure.ComputingNode.ifaces iface
+        and
+        vm has infrastructure.ComputingNode.ifaces X
+    )
+    ---
+    "VM {vm} has no associated interface."
diff --git a/tests/domlr/example_single_req_qty_comparison.domlr b/tests/domlr/example_single_req_qty_comparison.domlr
new file mode 100644
index 0000000000000000000000000000000000000000..9d7029dcc1b145e2d62a8885e81f3fc1aa564de7
--- /dev/null
+++ b/tests/domlr/example_single_req_qty_comparison.domlr
@@ -0,0 +1,35 @@
+# vm, iface = get_consts(smtsorts, ["vm", "iface"])
+# return And(
+#     smtenc.element_class_fun(vm) == smtenc.classes["infrastructure_VirtualMachine"],
+#     Not(
+#         Exists(
+#             [iface],
+#             ENCODINGS.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], iface)
+#         )
+#     )
+# )
+
+# OLD SYNTAX
+# +   "All VMs have at least 512 MB of memory"
+#     forall vm (
+#         vm is class infrastructure.VirtualMachine
+#         implies
+#         (
+#             vm has abstract.ComputingNode.memory_mb Mem
+#             and
+#             Mem < 512
+#         )
+#     )
+    
+#     ---
+#     "All VMs have at least 256 MB of memory"
+
++   "All VMs have at least 512 MB of memory"
+    forall vm (
+        vm is class infrastructure.VirtualMachine
+        implies    
+        vm has abstract.ComputingNode.memory_mb >= 512
+        
+    )
+    
+    error: "All VMs have at least 256 MB of memory"
\ No newline at end of file
diff --git a/tests/domlr/example_vm_has_sizedesc_cpu_count.domlr b/tests/domlr/example_vm_has_sizedesc_cpu_count.domlr
new file mode 100644
index 0000000000000000000000000000000000000000..c48e812e1f15ed1a38e473fb56baf6e970b38fab
--- /dev/null
+++ b/tests/domlr/example_vm_has_sizedesc_cpu_count.domlr
@@ -0,0 +1,9 @@
++   "VM has size description and cpu_count >= 4"
+    forall vm (
+        vm is class infrastructure.VirtualMachine
+        implies
+            vm has infrastructure.VirtualMachine.sizeDescription == "EXAMPLE"
+            and
+            vm has infrastructure.ComputingNode.cpu_count >= 4
+    )
+    error: "Model is wrong..."
\ No newline at end of file
diff --git a/tests/test_mc_openapi.py b/tests/test_mc_openapi.py
index d96ac8938bb3fff770a35a40b8c5eca5b9c2f7b1..506b33b37590ea0f4f0cbfff748747b41559d4c5 100644
--- a/tests/test_mc_openapi.py
+++ b/tests/test_mc_openapi.py
@@ -3,11 +3,6 @@ from mc_openapi.doml_mc.common_reqs import CommonRequirements
 from mc_openapi.doml_mc import DOMLVersion
 import requests
 
-
-def test_version():
-    assert __version__ == '1.2.0'
-
-
 # V2_0 tests
 def test_post_nginx_sat_V2_0():
     with open("tests/doml/v2.0/nginx-openstack_v2.0.domlx", "r") as f:
@@ -74,3 +69,36 @@ def test_post_faas_unsat_V2_1():
     assert r.status_code == requests.codes.ok
     assert payload["result"] is not None
     assert payload["result"] == "unsat"
+
+# V2_2 tests
+def test_post_nginx_sat_V2_1():
+    with open("tests/doml/v2.2/nginx-aws-ec2.domlx", "r") as f:
+        doml = f.read()
+
+    r = requests.post("http://0.0.0.0:8080/modelcheck", data=doml)
+    payload = r.json()
+    assert r.status_code == requests.codes.ok
+    assert payload["result"] is not None
+    assert payload["result"] == "sat"
+
+
+def test_post_faas_unsat_V2_2():
+    with open("tests/doml/v2.2/faas.domlx", "r") as f:
+        doml = f.read()
+
+    r = requests.post("http://0.0.0.0:8080/modelcheck", data=doml)
+    payload = r.json()
+    assert r.status_code == requests.codes.ok
+    assert payload["result"] is not None
+    assert payload["result"] == "unsat"
+
+
+def test_post_nginx_with_func_reqs_unsat_V2_2():
+    with open("tests/doml/v2.2/nginx_func_req.domlx", "r") as f:
+        doml = f.read()
+
+    r = requests.post("http://0.0.0.0:8080/modelcheck", data=doml)
+    payload = r.json()
+    assert r.status_code == requests.codes.ok
+    assert payload["result"] is not None
+    assert payload["result"] == "unsat"
\ No newline at end of file