diff --git a/.gitignore b/.gitignore
index b55dbcf0e38887f7d1621023301e0ec0e91fc116..22992efc664d9e6281434e7c3ef85fb5c79eef2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 *~
 *__pycache__*
+.vscode
diff --git a/mc_openapi/assets/__init__.py b/mc_openapi/assets/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/mc_openapi/assets/doml.ecore b/mc_openapi/assets/doml.ecore
new file mode 100644
index 0000000000000000000000000000000000000000..e8cc0d6e555f08f8fcf9b10522f40ffaecbcca7d
--- /dev/null
+++ b/mc_openapi/assets/doml.ecore
@@ -0,0 +1,349 @@
+<?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: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">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="key" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="type" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" 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="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="Deployment">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="component" lowerBound="1"
+          eType="#//application/ApplicationComponent"/>
+      <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="identifier" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <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>
+  </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"/>
+    <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:EAttribute" name="configFile" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <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"/>
+    </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="networks" upperBound="-1"
+          eType="#//infrastructure/VPC" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="secGroups" upperBound="-1"
+          eType="#//infrastructure/SecurityGroup" 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="#//infrastructure/Credentials" containment="true"/>
+    </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/ComputingNode">
+      <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="deploymentNetwork" eType="#//infrastructure/Network"/>
+      <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="addressRanges" 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="#//infrastructure/ComputingGroup">
+      <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"/>
+    <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" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <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" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <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="#//infrastructure/Credentials"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="group" eType="#//infrastructure/ComputingGroup"
+          eOpposite="#//infrastructure/ComputingGroup/groupedNodes"/>
+    </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="Container" eSuperTypes="#//infrastructure/ComputingNode">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/ContainerImage"
+          eOpposite="#//infrastructure/ContainerImage/generatedContainers"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="host" eType="#//infrastructure/ComputingNode"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Network" abstract="true" 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"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VPC" eSuperTypes="#//infrastructure/Network">
+      <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="storage" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <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:EClass" name="Credentials" abstract="true" eSuperTypes="#//commons/DOMLElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="KeyPair" eSuperTypes="#//infrastructure/Credentials">
+      <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="#//infrastructure/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="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"/>
+    </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="OptimizationSolution" eSuperTypes="#//commons/Configuration"/>
+    <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_meta.yaml b/mc_openapi/assets/doml_meta.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..111096e50e9741d8e37f292a4edfa17069b8b9b9
--- /dev/null
+++ b/mc_openapi/assets/doml_meta.yaml
@@ -0,0 +1,334 @@
+commons:
+    DOMLElement:
+        attributes:
+            name:
+                type: String
+                multiplicity: "1"
+            description:
+                type: String
+                multiplicity: "0..1"
+    Configuration:
+        superclass: commons_DOMLElement
+        associations:
+            deployments:
+                class: commons_Deployment
+                multiplicity: "0..*"
+    Deployment:
+        associations:
+            source:
+                class: application_ApplicationComponent
+                multiplicity: "1"
+            target:
+                class: infrastructure_InfrastructureElement
+                multiplicity: "1"
+
+application:
+    ApplicationLayer:
+        superclass: commons_DOMLElement
+        associations:
+            components:
+                class: application_ApplicationComponent
+                multiplicity: "0..*"
+    ApplicationComponent:
+        superclass: commons_DOMLElement
+    SoftwareComponent:
+        superclass: application_ApplicationComponent
+        attributes:
+            isPersistent:
+                type: Boolean
+                multiplicity: "1"
+                default: false
+        associations:
+            exposedInterfaces:
+                class: application_SoftwareInterface
+                mutiplicity: "0..*"
+            consumedInterfaces:
+                class: application_SoftwareInterface
+                mutiplicity: "0..*"
+    SaaS:
+        superclass: application_ApplicationComponent
+        associations:
+            exposedInterfaces:
+                class: application_SoftwareInterface
+                mutiplicity: "0..*"
+    SoftwareInterface:
+        superclass: application_ApplicationComponent
+        attributes:
+            endPoint:
+                type: String
+                multiplicity: "1"
+    DBMS:
+        superclass: application_SoftwarePackage
+    SaaSDBMS:
+        superclass: application_SaaS
+
+infrastructure:
+    InfrastructureLayer:
+        superclass: commons_DOMLElement
+        associations:
+            nodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+            generators:
+                class: infrastructure_ComputingNodeGenerator
+                multiplicity: "0..*"
+            asGroups:
+                class: infrastructure_AutoScalingGroup
+                multiplicity: "0..*"
+            networks:
+                class: infrastructure_Network
+                multiplicity: "0..*"
+            firewalls:
+                class: infrastructure_Firewall
+                multiplicity: "0..*"
+            storages:
+                class: infrastructure_Storage
+                multiplicity: "0..*"
+            faas:
+                class: infrastructure_FunctionAsAService
+                multiplicity: "0..*"
+    InfrastructureElement:
+        superclass: commons_DOMLElement
+    ComputingNode:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            architecture: 
+                type: String 
+                multiplicity: "0..1"
+            os: 
+                type: String 
+                multiplicity: "0..1"
+            memory: 
+                type: String 
+                multiplicity: "0..1"
+            storage: 
+                type: String 
+                multiplicity: "0..1"
+            cpu: 
+                type: String 
+                multiplicity: "0..1"
+            cost: 
+                type: Integer  # in cents 
+                multiplicity: "0..1"
+        associations:
+            group:
+                class: infrastructure_AutoScalingGroup
+                multiplicity: "0..1"
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+            location:
+                class: infrastructure_Location
+                multiplicity: "0..1"
+    PhysicalComputingNode:
+        superclass: infrastructure_ComputingNode
+    VirtualMachine:
+        superclass: infrastructure_ComputingNode
+        attributes:
+            sizeDescription:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            generatedFrom:
+                class: infrastructure_VMImage
+                multiplicity: "0..1"
+            location:
+                class: infrastructure_Location
+                multiplicity: "0..1"
+    Location:
+        superclass: commons_DOMLElement
+        attributes:
+            region:
+                type: String
+                multiplicity: "1"
+            zone:
+                type: String
+                multiplicity: "0..1"
+    Container:
+        superclass: infrastructure_ComputingNode
+        associations:
+            generatedFrom:
+                class: infrastructure_ContainerImage
+                multiplicity: "0..1"
+            host:
+                class: infrastructure_ComputingNode
+                multiplicity: "1"
+    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: commons_DOMLElement
+        associations:
+            # runtimeProvider
+            groupedNodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+                inverse_of: infrastructure_ComputingNode::group
+    SecurityGroup:
+        superclass: commons_DOMLElement
+        associations:
+            # runtimeProvider
+            groupedNodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+                inverse_of: infrastructure_ComputingNode::group
+    Storage:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            storage:
+                type: Integer  # in MBs
+                multiplicity: "0..1"
+            cost: 
+                type: Integer  # in cents 
+                multiplicity: "0..1"
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..1"
+    FunctionAsAService:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            cost:
+                type: Integer  # in cents
+                multiplicity: "0..1"
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..1"
+    Network:
+        superclass: commons_DOMLElement
+        attributes:
+            protocol:
+                type: String
+                multiplicity: "0..1"
+            address_lb:
+                type: Integer
+                multiplicity: "0..1"
+            address_ub:
+                type: Integer
+                multiplicity: "0..1"
+        associations:
+            connectedIfaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+                inverse_of: infrastructure_NetworkInterface::belongsTo
+            subnets: 
+                class: infrastructure_Subnet
+                multiplicity: "0..*"
+    Subnet:
+        superclass: infrastructure_Network
+    NetworkInterface:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            endPoint:
+                type: Integer
+                multiplicity: "0..1"
+            speed:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            belongsTo:
+                class: infrastructure_Network
+                multiplicity: "1"
+    Firewall:
+        superclass: infrastructure_DOMLElement
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+
+concrete:
+    ConcreteInfrastructure:
+        superclass: commons_DOMLElement
+        associations:
+            providers:
+                class: concrete_RuntimeProvider
+                multiplicity: "0..*"
+            nodes:
+                class: concrete_VirtualMachine
+                multiplicity: "0..*"
+            asGroups:
+                class: concrete_AutoScalingGroup
+                multiplicity: "0..*"
+            networks:
+                class: concrete_Network
+                multiplicity: "0..*"
+            storages:
+                class: concrete_Storage
+                multiplicity: "0..*"
+            faas:
+                class: concrete_FunctionAsAService
+                multiplicity: "0..*"
+    ConcreteElement:
+        superclass: commons_DOMLElement
+        attributes:
+            configurationScript:
+                type: String
+                multiplicity: "0..1"
+    RuntimeProvider:
+        superclass: commons_DOMLElement
+        associations:
+            supportedGroups:
+                class: concrete_AutoScalingGroup
+                multiplicity: "0..*"
+            vms:
+                class: concrete_VirtualMachine
+                multiplicity: "0..*"
+            networks:
+                class: concrete_Network
+                multiplicity: "0..*"
+            storages:
+                class: concrete_Storage
+                multiplicity: "0..*"
+            faas:
+                class: concrete_FunctionAsAService
+                multiplicity: "0..*"
+    VirtualMachine:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_VirtualMachine
+                multiplicity: "1"
+    Network:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_Network
+                multiplicity: "1"
+    Storage:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_Storage
+                multiplicity: "1"
+    FunctionAsAService:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_FunctionAsAService
+                multiplicity: "1"
+    AutoScalingGroup:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_AutoScalingGroup
+                multiplicity: "1"
\ No newline at end of file
diff --git a/mc_openapi/string_uri.py b/mc_openapi/bytes_uri.py
similarity index 61%
rename from mc_openapi/string_uri.py
rename to mc_openapi/bytes_uri.py
index c8d0e92742f90213ab32f6e3bd1d4bce9c54c08b..b6b3cbb2e97c4499aa544b00777f127455b536f4 100644
--- a/mc_openapi/string_uri.py
+++ b/mc_openapi/bytes_uri.py
@@ -1,11 +1,11 @@
 from pyecore.resources import URI
 from io import BytesIO
 
-class StringURI(URI):
-    def __init__(self, uri, text=None):
-        super(StringURI, self).__init__(uri)
-        if text is not None:
-            self.__stream = BytesIO(text)
+class BytesURI(URI):
+    def __init__(self, uri, bytes=None):
+        super(BytesURI, self).__init__(uri)
+        if bytes is not None:
+            self.__stream = BytesIO(bytes)
 
     def getvalue(self):
         return self.__stream.getvalue()
diff --git a/mc_openapi/doml_mc/__init__.py b/mc_openapi/doml_mc/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..49ecc4d3eea9c907a11df234f7725ee65dad74f2
--- /dev/null
+++ b/mc_openapi/doml_mc/__init__.py
@@ -0,0 +1,4 @@
+from .mc import SMTEncoding, ModelChecker  # noqa: F401
+
+# Load metamodel
+ModelChecker.init_metamodel()
diff --git a/mc_openapi/doml_mc/_utils.py b/mc_openapi/doml_mc/_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..458c453bc55b6d4975d1cb4c61bd836f206177f6
--- /dev/null
+++ b/mc_openapi/doml_mc/_utils.py
@@ -0,0 +1,10 @@
+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())
diff --git a/mc_openapi/doml_mc/example.ipynb b/mc_openapi/doml_mc/example.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..b025bd121a6a206fd63a84bcc9db382a0ff2d524
--- /dev/null
+++ b/mc_openapi/doml_mc/example.ipynb
@@ -0,0 +1,706 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from mc_openapi.doml_mc.intermediate_model.metamodel import parse_metamodel, parse_inverse_associations\n",
+    "import yaml\n",
+    "with open(\"../assets/doml_meta.yaml\") as mmf:\n",
+    "    mmdoc = yaml.load(mmf, yaml.Loader)\n",
+    "mm = parse_metamodel(mmdoc)\n",
+    "inv_assoc = parse_inverse_associations(mmdoc)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import prettyprinter as pp\n",
+    "from prettyprinter.prettyprinter import IMPLICIT_MODULES\n",
+    "pp.install_extras(include=['dataclasses'])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "mc_openapi.doml_mc.intermediate_model.metamodel.DOMLClass(\n",
+      "    name='application_SoftwareComponent',\n",
+      "    superclass='application_ApplicationComponent',\n",
+      "    attributes={\n",
+      "        'isPersistent': mc_openapi.doml_mc.intermediate_model.metamodel.DOMLAttribute(\n",
+      "            name='isPersistent',\n",
+      "            type='Boolean',\n",
+      "            multiplicity=('1', '1'),\n",
+      "            default=False\n",
+      "        )\n",
+      "    },\n",
+      "    associations={\n",
+      "        'exposedInterfaces': mc_openapi.doml_mc.intermediate_model.metamodel.DOMLAssociation(\n",
+      "            name='exposedInterfaces',\n",
+      "            class_='application_SoftwareInterface',\n",
+      "            multiplicity=('0', '*')\n",
+      "        ),\n",
+      "        'consumedInterfaces': mc_openapi.doml_mc.intermediate_model.metamodel.DOMLAssociation(\n",
+      "            name='consumedInterfaces',\n",
+      "            class_='application_SoftwareInterface',\n",
+      "            multiplicity=('0', '*')\n",
+      "        )\n",
+      "    }\n",
+      ")\n"
+     ]
+    }
+   ],
+   "source": [
+    "IMPLICIT_MODULES.add('doml_mc.intermediate_model.metamodel')\n",
+    "pp.pprint(mm[\"application_SoftwareComponent\"])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Load the DOML document here:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from mc_openapi.doml_mc.xmi_parser.doml_model import parse_doml_model\n",
+    "# doml_document_path = \"../../tests/doml/nginx-openstack_v2.domlx\"\n",
+    "doml_document_path = \"../../tests/doml/nginx-openstack_v2_wrong.domlx\"\n",
+    "with open(doml_document_path, \"rb\") as xmif:\n",
+    "    doc = xmif.read()\n",
+    "\n",
+    "doml_model = parse_doml_model(doc, mm)\n",
+    "print(doml_model)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from mc_openapi.doml_mc.intermediate_model.doml_model2im import doml_model_to_im\n",
+    "from mc_openapi.doml_mc.intermediate_model.doml_element import reciprocate_inverse_associations\n",
+    "im = doml_model_to_im(doml_model, mm)\n",
+    "reciprocate_inverse_associations(im, inv_assoc)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    'nginx': mc_openapi.doml_mc.intermediate_model.doml_element.DOMLElement(\n",
+      "        name='nginx',\n",
+      "        class_='application_SoftwareComponent',\n",
+      "        attributes={'commons_DOMLElement::name': 'nginx'},\n",
+      "        associations={\n",
+      "            'application_SoftwarePackage::consumedInterfaces': set(),\n",
+      "            'application_SoftwarePackage::exposedInterfaces': set()\n",
+      "        }\n",
+      "    ),\n",
+      "    'vm1': mc_openapi.doml_mc.intermediate_model.doml_element.DOMLElement(\n",
+      "        name='vm1',\n",
+      "        class_='infrastructure_VirtualMachine',\n",
+      "        attributes={'commons_DOMLElement::name': 'vm1'},\n",
+      "        associations={'infrastructure_ComputingNode::ifaces': set()}\n",
+      "    ),\n",
+      "    'net1': mc_openapi.doml_mc.intermediate_model.doml_element.DOMLElement(\n",
+      "        name='net1',\n",
+      "        class_='infrastructure_Network',\n",
+      "        attributes={\n",
+      "            'commons_DOMLElement::name': 'net1',\n",
+      "            'infrastructure_Network::address_lb': 268435456,\n",
+      "            'infrastructure_Network::address_ub': 268435711\n",
+      "        },\n",
+      "        associations={}\n",
+      "    ),\n",
+      "    'sg': mc_openapi.doml_mc.intermediate_model.doml_element.DOMLElement(\n",
+      "        name='sg',\n",
+      "        class_='infrastructure_SecurityGroup',\n",
+      "        attributes={'commons_DOMLElement::name': 'sg'},\n",
+      "        associations={}\n",
+      "    ),\n",
+      "    'con_infra': mc_openapi.doml_mc.intermediate_model.doml_element.DOMLElement(\n",
+      "        name='con_infra',\n",
+      "        class_='concrete_ConcreteInfrastructure',\n",
+      "        attributes={'commons_DOMLElement::name': 'con_infra'},\n",
+      "        associations={\n",
+      "            'concrete_ConcreteInfrastructure::providers': {'openstack'},\n",
+      "            'concrete_ConcreteInfrastructure::nodes': {'concrete_vm'},\n",
+      "            'concrete_ConcreteInfrastructure::asGroups': set(),\n",
+      "            'concrete_ConcreteInfrastructure::networks': {'concrete_net'},\n",
+      "            'concrete_ConcreteInfrastructure::storages': set()\n",
+      "        }\n",
+      "    ),\n",
+      "    'concrete_vm': mc_openapi.doml_mc.intermediate_model.doml_element.DOMLElement(\n",
+      "        name='concrete_vm',\n",
+      "        class_='concrete_VirtualMachine',\n",
+      "        attributes={'commons_DOMLElement::name': 'concrete_vm'},\n",
+      "        associations={'concrete_VirtualMachine::maps': {'vm1'}}\n",
+      "    ),\n",
+      "    'openstack': mc_openapi.doml_mc.intermediate_model.doml_element.DOMLElement(\n",
+      "        name='openstack',\n",
+      "        class_='concrete_RuntimeProvider',\n",
+      "        attributes={'commons_DOMLElement::name': 'openstack'},\n",
+      "        associations={\n",
+      "            'concrete_RuntimeProvider::supportedGroups': set(),\n",
+      "            'concrete_RuntimeProvider::vms': {'concrete_vm'},\n",
+      "            'concrete_RuntimeProvider::networks': {'concrete_net'},\n",
+      "            'concrete_RuntimeProvider::storages': set()\n",
+      "        }\n",
+      "    ),\n",
+      "    'concrete_net': mc_openapi.doml_mc.intermediate_model.doml_element.DOMLElement(\n",
+      "        name='concrete_net',\n",
+      "        class_='concrete_Network',\n",
+      "        attributes={'commons_DOMLElement::name': 'concrete_net'},\n",
+      "        associations={'concrete_Network::maps': {'net1'}}\n",
+      "    )\n",
+      "}\n"
+     ]
+    }
+   ],
+   "source": [
+    "IMPLICIT_MODULES.add('doml_mc.intermediate_model.doml_element')\n",
+    "pp.pprint(im)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "unbound_elems_n = 1\n",
+    "unbound_elems = [f\"unbound{i}\" for i in range(unbound_elems_n)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from z3 import Solver\n",
+    "\n",
+    "from mc_openapi.doml_mc.z3.metamodel_encoding import (\n",
+    "    def_association_rel_and_assert_constraints,\n",
+    "    def_attribute_rel_and_assert_constraints,\n",
+    "    mk_association_sort_dict,\n",
+    "    mk_attribute_sort_dict,\n",
+    "    mk_class_sort_dict\n",
+    ")\n",
+    "from mc_openapi.doml_mc.z3.im_encoding import (\n",
+    "    assert_im_associations_q,\n",
+    "    assert_im_attributes,\n",
+    "    def_elem_class_f_and_assert_classes,\n",
+    "    mk_elem_sort_dict,\n",
+    "    mk_stringsym_sort_dict\n",
+    ")\n",
+    "from mc_openapi.doml_mc.z3.utils import mk_adata_sort\n",
+    "\n",
+    "solver = Solver()\n",
+    "\n",
+    "class_sort, class_ = mk_class_sort_dict(mm)\n",
+    "assoc_sort, assoc = mk_association_sort_dict(mm)\n",
+    "attr_sort, attr = mk_attribute_sort_dict(mm)\n",
+    "elem_sort, elem = mk_elem_sort_dict(im, unbound_elems)\n",
+    "ss_sort, ss = mk_stringsym_sort_dict(im, mm)\n",
+    "AData = mk_adata_sort(ss_sort)\n",
+    "elem_class_f = def_elem_class_f_and_assert_classes(\n",
+    "    im,\n",
+    "    solver,\n",
+    "    elem_sort,\n",
+    "    elem,\n",
+    "    class_sort,\n",
+    "    class_\n",
+    ")\n",
+    "attr_rel = def_attribute_rel_and_assert_constraints(\n",
+    "    mm,\n",
+    "    solver,\n",
+    "    attr_sort,\n",
+    "    attr,\n",
+    "    class_,\n",
+    "    elem_class_f,\n",
+    "    elem_sort,\n",
+    "    AData,\n",
+    "    ss\n",
+    ")\n",
+    "assert_im_attributes(\n",
+    "    attr_rel,\n",
+    "    solver,\n",
+    "    im,\n",
+    "    mm,\n",
+    "    elem,\n",
+    "    attr_sort,\n",
+    "    attr,\n",
+    "    AData,\n",
+    "    ss\n",
+    ")\n",
+    "assoc_rel = def_association_rel_and_assert_constraints(\n",
+    "    mm,\n",
+    "    solver,\n",
+    "    assoc_sort,\n",
+    "    assoc,\n",
+    "    class_,\n",
+    "    elem_class_f,\n",
+    "    elem_sort,\n",
+    "    inv_assoc\n",
+    ")\n",
+    "assert_im_associations_q(\n",
+    "    assoc_rel,\n",
+    "    solver,\n",
+    "    {k: v for k, v in im.items() if k not in unbound_elems},\n",
+    "    elem,\n",
+    "    assoc_sort,\n",
+    "    assoc,\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# solver.push()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Metamodel statistics"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Number of classes: 36\n",
+      "Number of tuples in the subclass relation: 91\n",
+      "Number of attributes: 24\n",
+      "Number of attribute assertions: 72\n",
+      "Number of associations: 47\n",
+      "Number of associations assertions: 146\n"
+     ]
+    }
+   ],
+   "source": [
+    "from mc_openapi.doml_mc.intermediate_model.metamodel import get_subclasses_dict\n",
+    "\n",
+    "print(\"Number of classes:\", len(mm))\n",
+    "print(\n",
+    "    \"Number of tuples in the subclass relation:\",\n",
+    "    sum(len(s) for s in get_subclasses_dict(mm).values())\n",
+    ")\n",
+    "n_attrs = sum(len(c.attributes) for c in mm.values())\n",
+    "print(\"Number of attributes:\", n_attrs)\n",
+    "print(\"Number of attribute assertions:\", 3 * n_attrs)\n",
+    "n_assocs = sum(len(c.associations) for c in mm.values())\n",
+    "print(\"Number of associations:\", n_assocs)\n",
+    "print(\"Number of associations assertions:\", 3 * n_assocs + len(inv_assoc))\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### DOML model statistics"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Number of elements: 8\n",
+      "Number of attributes (IM): 10\n",
+      "Number of associations (IM): 7\n",
+      "Number of string symbols: 10\n",
+      "Number of IM attribute assertions: 8\n",
+      "Number of IM association assertions: 64\n"
+     ]
+    }
+   ],
+   "source": [
+    "n_elems = len(im)\n",
+    "print(\"Number of elements:\", n_elems)\n",
+    "n_attrs_im = sum(len(e.attributes) for e in im.values())\n",
+    "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 IM attribute assertions:\", n_elems)\n",
+    "print(\"Number of IM association assertions:\", n_elems ** 2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<b>sat</b>"
+      ],
+      "text/plain": [
+       "sat"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "solver.check()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(:added-eqs               4046\n",
+       " :arith-make-feasible     5\n",
+       " :arith-max-columns       6\n",
+       " :binary-propagations     208\n",
+       " :conflicts               26\n",
+       " :datatype-accessor-ax    246\n",
+       " :datatype-constructor-ax 1534\n",
+       " :datatype-splits         249\n",
+       " :decisions               7349\n",
+       " :del-clause              14\n",
+       " :final-checks            8\n",
+       " :max-generation          4\n",
+       " :max-memory              22.49\n",
+       " :memory                  22.49\n",
+       " :mk-bool-var             1342\n",
+       " :mk-clause               473\n",
+       " :num-allocs              2766758\n",
+       " :num-checks              1\n",
+       " :propagations            1442\n",
+       " :quant-instantiations    339\n",
+       " :restarts                3\n",
+       " :rlimit-count            958188\n",
+       " :time                    0.16)"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "solver.statistics()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from z3 import Consts, ForAll, Exists, Implies, And, Or"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# All VMs have a network interface.\n",
+    "vm, iface = Consts(\n",
+    "    \"vm iface\", elem_sort\n",
+    ")\n",
+    "vmIfaceAssertion = ForAll(\n",
+    "    [vm],\n",
+    "    Implies(\n",
+    "        elem_class_f(vm) == class_[\"infrastructure_VirtualMachine\"],\n",
+    "        Exists(\n",
+    "            [iface],\n",
+    "            And(\n",
+    "                assoc_rel(vm, assoc[\"infrastructure_ComputingNode::ifaces\"], iface)\n",
+    "            )\n",
+    "        )\n",
+    "    )\n",
+    ")\n",
+    "solver.assert_and_track(vmIfaceAssertion, \"vm_iface\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<b>sat</b>"
+      ],
+      "text/plain": [
+       "sat"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "solver.check()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "23.16"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "solver.statistics().memory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[attribute_st_types infrastructure_VirtualMachine::sizeDescription = True,\n",
+      " attribute_mult_ub infrastructure_Network::address_ub = True,\n",
+      " attribute_values vm1 = True,\n",
+      " association_st_classes concrete_ConcreteInfrastructure::storages = True,\n",
+      " association_st_classes concrete_VirtualMachine::maps = True,\n",
+      " attribute_mult_ub infrastructure_Storage::cost = True,\n",
+      " attribute_st_types commons_DOMLElement::name = True,\n",
+      " attribute_st_types infrastructure_Network::address_lb = True,\n",
+      " association_mult_ub concrete_FunctionAsAService::maps = True,\n",
+      " associations con_infra con_infra = True,\n",
+      " association_inverse infrastructure_Container::generatedFrom infrastructure_ContainerImage::generatedContainers = True,\n",
+      " associations concrete_vm sg = True,\n",
+      " association_mult_ub infrastructure_Container::generatedFrom = True,\n",
+      " association_st_classes infrastructure_FunctionAsAService::ifaces = True,\n",
+      " association_mult_ub infrastructure_VirtualMachine::location = True,\n",
+      " association_st_classes concrete_Storage::maps = True,\n",
+      " elem_class vm1 infrastructure_VirtualMachine = True,\n",
+      " attribute_values concrete_vm = True,\n",
+      " elem_class nginx application_SoftwareComponent = True,\n",
+      " attribute_values nginx = True,\n",
+      " association_st_classes infrastructure_Storage::ifaces = True,\n",
+      " associations nginx nginx = True,\n",
+      " attribute_st_types infrastructure_Storage::storage = True,\n",
+      " associations nginx openstack = True,\n",
+      " association_st_classes concrete_RuntimeProvider::vms = True,\n",
+      " attribute_st_types infrastructure_Network::protocol = True,\n",
+      " associations concrete_net openstack = True,\n",
+      " associations sg nginx = True,\n",
+      " attribute_mult_ub infrastructure_ComputingNodeGenerator::uri = True,\n",
+      " association_mult_ub commons_Deployment::source = True,\n",
+      " attribute_st_types infrastructure_ComputingNode::os = True,\n",
+      " attribute_values sg = True,\n",
+      " associations net1 vm1 = True,\n",
+      " elem_class concrete_vm concrete_VirtualMachine = True,\n",
+      " attribute_mult_ub application_SoftwareComponent::isPersistent = True,\n",
+      " attribute_values concrete_net = True,\n",
+      " association_st_classes infrastructure_ContainerImage::generatedContainers = True,\n",
+      " association_mult_lb infrastructure_NetworkInterface::belongsTo = True,\n",
+      " association_mult_lb concrete_VirtualMachine::maps = True,\n",
+      " association_st_classes concrete_ConcreteInfrastructure::nodes = True,\n",
+      " association_mult_ub concrete_VirtualMachine::maps = True,\n",
+      " association_st_classes commons_Deployment::target = True,\n",
+      " association_st_classes concrete_ConcreteInfrastructure::faas = True,\n",
+      " associations net1 con_infra = True,\n",
+      " attribute_st_types concrete_ConcreteElement::configurationScript = True,\n",
+      " association_mult_ub infrastructure_VirtualMachine::generatedFrom = True,\n",
+      " associations nginx net1 = True,\n",
+      " attribute_st_types infrastructure_Network::address_ub = True,\n",
+      " attribute_values openstack = True,\n",
+      " attribute_st_types infrastructure_ComputingNode::cost = True,\n",
+      " association_mult_ub infrastructure_NetworkInterface::belongsTo = True,\n",
+      " associations nginx vm1 = True,\n",
+      " associations con_infra concrete_vm = True,\n",
+      " association_mult_ub infrastructure_ComputingNode::location = True,\n",
+      " association_mult_lb concrete_AutoScalingGroup::maps = True,\n",
+      " attribute_values net1 = True,\n",
+      " association_mult_ub infrastructure_Storage::ifaces = True,\n",
+      " attribute_mult_ub infrastructure_Location::zone = True,\n",
+      " associations vm1 openstack = True,\n",
+      " association_mult_ub infrastructure_ComputingNode::group = True,\n",
+      " associations sg concrete_net = True,\n",
+      " association_st_classes infrastructure_VirtualMachine::generatedFrom = True,\n",
+      " association_st_classes concrete_FunctionAsAService::maps = True,\n",
+      " associations concrete_vm net1 = True,\n",
+      " associations net1 openstack = True,\n",
+      " associations concrete_vm concrete_vm = True,\n",
+      " association_st_classes concrete_ConcreteInfrastructure::networks = True,\n",
+      " associations openstack vm1 = True,\n",
+      " associations con_infra concrete_net = True,\n",
+      " association_inverse infrastructure_ComputingNode::group infrastructure_AutoScalingGroup::groupedNodes = True,\n",
+      " association_mult_ub commons_Deployment::target = True,\n",
+      " associations con_infra vm1 = True,\n",
+      " attribute_mult_lb commons_DOMLElement::name = True,\n",
+      " associations vm1 nginx = True,\n",
+      " association_mult_ub infrastructure_FunctionAsAService::ifaces = True,\n",
+      " association_st_classes infrastructure_SecurityGroup::groupedNodes = True,\n",
+      " attribute_mult_ub infrastructure_Network::address_lb = True,\n",
+      " association_st_classes infrastructure_ComputingNode::location = True,\n",
+      " association_st_classes infrastructure_VirtualMachine::location = True,\n",
+      " attribute_mult_lb application_SoftwareInterface::endPoint = True,\n",
+      " association_st_classes concrete_RuntimeProvider::networks = True,\n",
+      " vm_iface = True,\n",
+      " associations net1 nginx = True,\n",
+      " attribute_mult_ub infrastructure_Location::region = True,\n",
+      " associations con_infra nginx = True,\n",
+      " association_mult_ub concrete_Storage::maps = True,\n",
+      " association_st_classes commons_Deployment::source = True,\n",
+      " associations con_infra net1 = True,\n",
+      " attribute_mult_ub commons_DOMLElement::description = True,\n",
+      " association_st_classes application_SoftwareComponent::exposedInterfaces = True,\n",
+      " association_inverse infrastructure_ComputingNode::group infrastructure_SecurityGroup::groupedNodes = True,\n",
+      " association_mult_lb commons_Deployment::target = True,\n",
+      " associations nginx concrete_net = True,\n",
+      " elem_class con_infra concrete_ConcreteInfrastructure = True,\n",
+      " association_mult_lb infrastructure_Container::host = True,\n",
+      " association_st_classes concrete_AutoScalingGroup::maps = True,\n",
+      " attribute_values con_infra = True,\n",
+      " associations sg openstack = True,\n",
+      " associations sg sg = True,\n",
+      " association_st_classes concrete_ConcreteInfrastructure::providers = True,\n",
+      " attribute_mult_ub infrastructure_ComputingNode::memory = True,\n",
+      " attribute_mult_ub infrastructure_Network::protocol = True,\n",
+      " elem_class concrete_net concrete_Network = True,\n",
+      " attribute_st_types infrastructure_ComputingNode::cpu = True,\n",
+      " association_mult_ub infrastructure_Container::host = True,\n",
+      " associations openstack openstack = True,\n",
+      " association_st_classes infrastructure_InfrastructureLayer::generators = True,\n",
+      " attribute_mult_lb infrastructure_Location::region = True,\n",
+      " attribute_mult_ub infrastructure_ComputingNode::cost = True,\n",
+      " attribute_st_types application_SoftwareComponent::isPersistent = True,\n",
+      " association_st_classes infrastructure_Network::subnets = True,\n",
+      " association_st_classes infrastructure_InfrastructureLayer::nodes = True,\n",
+      " association_st_classes infrastructure_VMImage::generatedVMs = True,\n",
+      " associations net1 sg = True,\n",
+      " associations nginx con_infra = True,\n",
+      " associations concrete_net nginx = True,\n",
+      " elem_class sg infrastructure_SecurityGroup = True,\n",
+      " associations con_infra sg = True,\n",
+      " association_st_classes concrete_RuntimeProvider::faas = True,\n",
+      " associations openstack nginx = True,\n",
+      " associations concrete_net con_infra = True,\n",
+      " associations nginx concrete_vm = True,\n",
+      " associations sg net1 = True,\n",
+      " association_mult_lb commons_Deployment::source = True,\n",
+      " associations net1 concrete_vm = True,\n",
+      " association_st_classes infrastructure_Firewall::ifaces = True,\n",
+      " associations con_infra openstack = True,\n",
+      " attribute_st_types infrastructure_Location::region = True,\n",
+      " associations vm1 concrete_net = True,\n",
+      " ...]\n"
+     ]
+    }
+   ],
+   "source": [
+    "m = solver.model()\n",
+    "print(m)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "vm1 infrastructure_ComputingNode::ifaces unbound0\n",
+      "net1 infrastructure_Network::connectedIfaces unbound0\n",
+      "unbound0 infrastructure_NetworkInterface::belongsTo net1\n"
+     ]
+    }
+   ],
+   "source": [
+    "from itertools import product\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 m.eval(assoc_rel(e1, a, e2)):\n",
+    "        print(e1, a, e2)"
+   ]
+  }
+ ],
+ "metadata": {
+  "interpreter": {
+   "hash": "a6678cf6b5907da3ee1c64f7f36cf1b3f0e5fe51f4038e28403f1c01345fc5bd"
+  },
+  "kernelspec": {
+   "display_name": "Python 3.9.9 64-bit",
+   "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.9.12"
+  },
+  "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/mc_openapi/doml_mc/intermediate_model/__init__.py b/mc_openapi/doml_mc/intermediate_model/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/mc_openapi/doml_mc/intermediate_model/application2im.py b/mc_openapi/doml_mc/intermediate_model/application2im.py
new file mode 100644
index 0000000000000000000000000000000000000000..eee31cc0c23924fe45cf95699d7c62948258e39d
--- /dev/null
+++ b/mc_openapi/doml_mc/intermediate_model/application2im.py
@@ -0,0 +1,45 @@
+from ..model.application import Application, ApplicationComponent
+from .._utils import merge_dicts
+
+from .types import IntermediateModel
+from .doml_element import DOMLElement
+
+
+def application_to_im(app: Application) -> IntermediateModel:
+    def app_comp_to_im(
+        app_comp: ApplicationComponent,
+    ) -> IntermediateModel:
+        comp_elem = DOMLElement(
+            name=app_comp.name,
+            class_=app_comp.typeId,
+            attributes={"commons_DOMLElement::name": app_comp.name},
+            associations={
+                "application_SoftwarePackage::consumedInterfaces": {
+                    f"{cn}_{ifacen}"
+                    for cn, ifacens in app_comp.consumedInterfaces.items()
+                    for ifacen in ifacens
+                },
+                "application_SoftwarePackage::exposedInterfaces": {
+                    f"{app_comp.name}_{ifacen}"
+                    for ifacen in app_comp.exposedInterfaces
+                },
+            },
+        )
+
+        iface_elems = {
+            elem_n: DOMLElement(
+                name=elem_n,
+                class_="application_SoftwareInterface",
+                attributes={
+                    "commons_DOMLElement::name": elem_n,
+                    "application_SoftwareInterface::endPoint": iface.endPoint,
+                },
+                associations={},
+            )
+            for ifacen, iface in app_comp.exposedInterfaces.items()
+            for elem_n in [f"{app_comp.name}_{ifacen}"]
+        }
+
+        return {app_comp.name: comp_elem} | iface_elems
+
+    return merge_dicts(app_comp_to_im(comp) for comp in app.children.values())
diff --git a/mc_openapi/doml_mc/intermediate_model/concrete2im.py b/mc_openapi/doml_mc/intermediate_model/concrete2im.py
new file mode 100644
index 0000000000000000000000000000000000000000..04e7ffd2157c4d77ddee6ba498e8666ed340e68c
--- /dev/null
+++ b/mc_openapi/doml_mc/intermediate_model/concrete2im.py
@@ -0,0 +1,111 @@
+from .._utils import merge_dicts
+from ..model.concretization import (
+    Concretization,
+    Group,
+    Network,
+    Provider,
+    Storage,
+    VirtualMachine,
+)
+
+from .doml_element import DOMLElement
+from .types import IntermediateModel
+
+
+def concretization_to_im(conc: Concretization) -> IntermediateModel:
+    def group_to_im(g: Group) -> IntermediateModel:
+        return {
+            g.name: DOMLElement(
+                name=g.name,
+                class_="concrete_AutoScalingGroup",
+                attributes={"commons_DOMLElement::name": g.name},
+                associations={"concrete_AutoScalingGroup::maps": {g.maps}},
+            )
+        }
+
+    def vm_to_im(vm: VirtualMachine) -> IntermediateModel:
+        return {
+            vm.name: DOMLElement(
+                name=vm.name,
+                class_="concrete_VirtualMachine",
+                attributes={"commons_DOMLElement::name": vm.name},
+                associations={"concrete_VirtualMachine::maps": {vm.maps}},
+            )
+        }
+
+    def storage_to_im(s: Storage) -> IntermediateModel:
+        return {
+            s.name: DOMLElement(
+                name=s.name,
+                class_="concrete_Storage",
+                attributes={"commons_DOMLElement::name": s.name},
+                associations={"concrete_Storage::maps": {s.maps}},
+            )
+        }
+
+    def network_to_im(n: Network) -> IntermediateModel:
+        return {
+            n.name: DOMLElement(
+                name=n.name,
+                class_="concrete_Network",
+                attributes={"commons_DOMLElement::name": n.name},
+                associations={"concrete_Network::maps": {n.maps}},
+            )
+        }
+
+    def provider_to_im(p: Provider) -> IntermediateModel:
+        return {
+            p.name: DOMLElement(
+                name=p.name,
+                class_="concrete_RuntimeProvider",
+                attributes={"commons_DOMLElement::name": p.name},
+                associations={
+                    "concrete_RuntimeProvider::supportedGroups": set(
+                        p.supportedGroups
+                    ),
+                    "concrete_RuntimeProvider::vms": set(p.providedVMs),
+                    "concrete_RuntimeProvider::networks": set(
+                        p.providedNetworks
+                    ),
+                    "concrete_RuntimeProvider::storages": set(p.storages),
+                },
+            )
+        }
+
+    im_groups = merge_dicts(group_to_im(g) for g in conc.groups.values())
+    im_vms = merge_dicts(vm_to_im(vm) for vm in conc.vms.values())
+    im_providers = merge_dicts(
+        provider_to_im(p) for p in conc.providers.values()
+    )
+    im_storages = merge_dicts(storage_to_im(s) for s in conc.storages.values())
+    im_networks = merge_dicts(network_to_im(n) for n in conc.networks.values())
+
+    return (
+        {
+            conc.name: DOMLElement(
+                name=conc.name,
+                class_="concrete_ConcreteInfrastructure",
+                attributes={"commons_DOMLElement::name": conc.name},
+                associations={
+                    "concrete_ConcreteInfrastructure::providers": set(
+                        im_providers
+                    ),
+                    "concrete_ConcreteInfrastructure::nodes": set(im_vms),
+                    "concrete_ConcreteInfrastructure::asGroups": set(
+                        im_groups
+                    ),
+                    "concrete_ConcreteInfrastructure::networks": set(
+                        im_networks
+                    ),
+                    "concrete_ConcreteInfrastructure::storages": set(
+                        im_storages
+                    ),
+                },
+            )
+        }
+        | im_groups
+        | im_vms
+        | im_providers
+        | im_storages
+        | im_networks
+    )
diff --git a/mc_openapi/doml_mc/intermediate_model/doml_element.py b/mc_openapi/doml_mc/intermediate_model/doml_element.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f532b9fa1dae54fc7ab06d9a5d8d4eb8b150adb
--- /dev/null
+++ b/mc_openapi/doml_mc/intermediate_model/doml_element.py
@@ -0,0 +1,69 @@
+from typing import Union
+from dataclasses import dataclass
+
+from .metamodel import (
+    AssociationNotFound,
+    AttributeNotFound,
+    MetaModel,
+    get_mangled_attribute_name,
+    get_mangled_association_name,
+)
+
+Attributes = dict[str, Union[str, int, bool]]
+Associations = dict[str, set[str]]
+
+
+@dataclass
+class DOMLElement:
+    name: str
+    class_: str
+    # the keys of the `attributes`/`associations` dicts are
+    # attribute/association names mangled with the type that declares them,
+    # e.g., `"application_SoftwarePackage::isPersistent"`.
+    attributes: Attributes
+    associations: Associations
+
+
+IntermediateModel = dict[str, "DOMLElement"]
+
+
+def parse_attrs_and_assocs_from_doc(
+    doc: dict,
+    cname: str,
+    mm: MetaModel,
+) -> tuple[Attributes, Associations]:
+    attrs = {}
+    assocs = {}
+    for k, v in doc.items():
+        try:
+            man = get_mangled_attribute_name(mm, cname, k)
+            attrs[man] = v
+        except AttributeNotFound:
+            try:
+                man = get_mangled_association_name(mm, cname, k)
+                # Only single target associations are found
+                # with this function. Change otherwise.
+                assocs[man] = {v}
+            except AssociationNotFound:
+                pass
+    return attrs, assocs
+
+
+def reciprocate_inverse_associations(
+    im: IntermediateModel,
+    invs: list[tuple[str, str]],
+) -> None:
+    """
+    ### Effects
+    This procedure is effectful on `im`.
+    """
+    # A dict for inverse lookup where inverse relationships are mapped both
+    # ways.
+    inv_dict = dict(invs) | {an2: an1 for an1, an2 in invs}
+    for ename, elem in im.items():
+        for aname, atgts in elem.associations.items():
+            if aname in inv_dict:
+                for atgt in atgts:
+                    im[atgt].associations[inv_dict[aname]] = im[
+                        atgt
+                    ].associations.get(inv_dict[aname], set()) | {ename}
diff --git a/mc_openapi/doml_mc/intermediate_model/doml_model2im.py b/mc_openapi/doml_mc/intermediate_model/doml_model2im.py
new file mode 100644
index 0000000000000000000000000000000000000000..1014dc3bd20568265b2cdaa0408f58122b4159e1
--- /dev/null
+++ b/mc_openapi/doml_mc/intermediate_model/doml_model2im.py
@@ -0,0 +1,18 @@
+from .._utils import merge_dicts
+from ..model.doml_model import DOMLModel
+
+from .types import IntermediateModel, MetaModel
+from .application2im import application_to_im
+from .infrastructure2im import infrastructure_to_im
+from .concrete2im import concretization_to_im
+
+
+def doml_model_to_im(model: DOMLModel, mm: MetaModel) -> IntermediateModel:
+    return (
+        application_to_im(model.application)
+        | infrastructure_to_im(model.infrastructure, mm)
+        | merge_dicts(
+            concretization_to_im(conc)
+            for conc in model.concretizations.values()
+        )
+    )
diff --git a/mc_openapi/doml_mc/intermediate_model/infrastructure2im.py b/mc_openapi/doml_mc/intermediate_model/infrastructure2im.py
new file mode 100644
index 0000000000000000000000000000000000000000..5e826734697520ad538e61a1d92f2b42069c8158
--- /dev/null
+++ b/mc_openapi/doml_mc/intermediate_model/infrastructure2im.py
@@ -0,0 +1,92 @@
+from ipaddress import ip_address, ip_network
+
+from ..model.infrastructure import (
+    Infrastructure,
+    InfrastructureNode,
+    Network,
+    Group,
+)
+from .._utils import merge_dicts
+
+from .types import IntermediateModel, MetaModel
+from .doml_element import DOMLElement
+from .metamodel import get_subclasses_dict
+
+
+def infrastructure_to_im(
+    infra: Infrastructure, mm: MetaModel
+) -> IntermediateModel:
+    subclasses_dict = get_subclasses_dict(mm)
+
+    def infra_node_to_im(
+        infra_node: InfrastructureNode,
+    ) -> IntermediateModel:
+        nifacereln = (
+            "infrastructure_Storage::ifaces"
+            if infra_node.typeId in subclasses_dict["infrastructure_Storage"]
+            else "infrastructure_FunctionAsAService::ifaces"
+            if infra_node.typeId
+            in subclasses_dict["infrastructure_FunctionAsAService"]
+            else "infrastructure_ComputingNode::ifaces"
+        )
+        node_elem = DOMLElement(
+            name=infra_node.name,
+            class_=infra_node.typeId,
+            attributes=infra_node.attributes
+            | {"commons_DOMLElement::name": infra_node.name},
+            associations=infra_node.associations
+            | {nifacereln: set(infra_node.network_interfaces.keys())},
+        )
+        niface_elems = {
+            nifacen: DOMLElement(
+                name=nifacen,
+                class_="infrastructure_NetworkInterface",
+                attributes={
+                    "commons_DOMLElement::name": nifacen,
+                    "infrastructure_NetworkInterface::endPoint": int(
+                        ip_address(niface.endPoint)
+                    ),
+                },
+                associations={
+                    "infrastructure_NetworkInterface::belongsTo": {
+                        niface.belongsTo
+                    }
+                },
+            )
+            for nifacen, niface in infra_node.network_interfaces.items()
+        }
+        return {node_elem.name: node_elem} | niface_elems
+
+    def network_to_im(net: Network) -> IntermediateModel:
+        return {
+            net.name: DOMLElement(
+                name=net.name,
+                class_="infrastructure_Network",
+                attributes={
+                    "commons_DOMLElement::name": net.name,
+                    "infrastructure_Network::address_lb": int(
+                        ip_network(net.addressRange)[0]
+                    ),
+                    "infrastructure_Network::address_ub": int(
+                        ip_network(net.addressRange)[-1]
+                    ),
+                },
+                associations={},
+            )
+        }
+
+    def group_to_im(group: Group) -> IntermediateModel:
+        return {
+            group.name: DOMLElement(
+                name=group.name,
+                class_=group.typeId,
+                attributes={"commons_DOMLElement::name": group.name},
+                associations={},
+            )
+        }
+
+    return (
+        merge_dicts(infra_node_to_im(inode) for inode in infra.nodes.values())
+        | merge_dicts(network_to_im(net) for net in infra.networks.values())
+        | merge_dicts(group_to_im(group) for group in infra.groups.values())
+    )
diff --git a/mc_openapi/doml_mc/intermediate_model/metamodel.py b/mc_openapi/doml_mc/intermediate_model/metamodel.py
new file mode 100644
index 0000000000000000000000000000000000000000..cfb25248ee183f1e86c401dd11532658f6ed18a9
--- /dev/null
+++ b/mc_openapi/doml_mc/intermediate_model/metamodel.py
@@ -0,0 +1,229 @@
+from dataclasses import dataclass
+from typing import cast, Literal, Optional, Union
+
+import networkx as nx
+
+from .._utils import merge_dicts
+
+Multiplicity = tuple[Literal["0", "1"], Literal["1", "*"]]
+
+
+class AttributeNotFound(Exception):
+    pass
+
+
+class AssociationNotFound(Exception):
+    pass
+
+
+@dataclass
+class DOMLClass:
+    name: str
+    superclass: Optional[str]
+    attributes: dict[str, "DOMLAttribute"]
+    associations: dict[str, "DOMLAssociation"]
+
+
+@dataclass
+class DOMLAttribute:
+    name: str
+    type: Literal["Boolean", "Integer", "String", "GeneratorKind"]
+    multiplicity: Multiplicity
+    default: Optional[Union[str, int, bool]]
+
+
+@dataclass
+class DOMLAssociation:
+    name: str
+    class_: str
+    multiplicity: Multiplicity
+
+
+MetaModel = dict[str, DOMLClass]
+
+
+def parse_metamodel(mmdoc: dict) -> MetaModel:
+    def parse_class(cname: str, cdoc: dict) -> DOMLClass:
+        def parse_mult(
+            mults: Literal["0..1", "0..*", "1", "1..*"]
+        ) -> Multiplicity:
+            if mults == "0..1":
+                return ("0", "1")
+            elif mults == "1":
+                return ("1", "1")
+            elif mults == "1..*":
+                return ("1", "*")
+            else:
+                return ("0", "*")
+
+        def parse_attribute(aname: str, adoc: dict) -> DOMLAttribute:
+            # sourcery skip: merge-comparisons
+            type_: str = adoc["type"]
+            assert (
+                type_ == "Boolean"
+                or type_ == "Integer"
+                or type_ == "String"
+                or type_ == "GeneratorKind"
+            )
+            mults: str = adoc.get("multiplicity", "0..*")
+            assert (
+                mults == "0..1"
+                or mults == "0..*"
+                or mults == "1"
+                or mults == "1..*"
+            )
+            return DOMLAttribute(
+                name=aname,
+                type=type_,
+                multiplicity=parse_mult(mults),
+                default=adoc.get("default"),
+            )
+
+        def parse_association(aname: str, adoc: dict) -> DOMLAssociation:
+            # sourcery skip: merge-comparisons
+            mults: str = adoc.get("multiplicity", "0..*")
+            assert (
+                mults == "0..1"
+                or mults == "0..*"
+                or mults == "1"
+                or mults == "1..*"
+            )
+            return DOMLAssociation(
+                name=aname,
+                class_=adoc["class"],
+                multiplicity=parse_mult(mults),
+            )
+
+        return DOMLClass(
+            name=cname,
+            superclass=cdoc.get("superclass"),
+            attributes={
+                aname: parse_attribute(aname, adoc)
+                for aname, adoc in cdoc.get("attributes", {}).items()
+            },
+            associations={
+                aname: parse_association(aname, adoc)
+                for aname, adoc in cdoc.get("associations", {}).items()
+            },
+        )
+
+    assert set(mmdoc.keys()) <= {
+        "commons",
+        "application",
+        "infrastructure",
+        "concrete",
+    }
+
+    return merge_dicts(
+        {
+            prefixed_name: parse_class(prefixed_name, cdoc)
+            for cname, cdoc in csdoc.items()
+            for prefixed_name in [f"{prefix}_{cname}"]
+        }
+        for prefix, csdoc in mmdoc.items()
+    )
+
+
+def parse_inverse_associations(doc: dict) -> list[tuple[str, str]]:
+    return [
+        (inv_of, f"{layer}_{cname}::{aname}")
+        for layer, ldoc in doc.items()
+        for cname, cdoc in ldoc.items()
+        for aname, adoc in cdoc.get("associations", {}).items()
+        for inv_of in [adoc.get("inverse_of")]
+        if inv_of is not None
+    ]
+
+
+def _find_association_class(
+    mm: MetaModel,
+    cname: str,
+    aname: str,
+) -> DOMLClass:
+    c = mm[cname]
+    if aname in c.associations:
+        return c
+    elif c.superclass is None:
+        raise AssociationNotFound(
+            f"Association {aname} not found in subclasses of {cname}."
+        )
+    else:
+        return _find_association_class(mm, c.superclass, aname)
+
+
+def get_mangled_association_name(
+    mm: MetaModel,
+    cname: str,
+    aname: str,
+) -> str:
+    return f"{_find_association_class(mm, cname, aname).name}::{aname}"
+
+
+def get_mangled_attribute_defaults(
+    mm: MetaModel,
+    cname: str,
+) -> dict[str, Union[str, int, bool]]:
+    c = mm[cname]
+    defaults = {
+        f"{cname}::{aname}": a.default
+        for aname, a in c.attributes.items()
+        if a.default is not None
+    }
+    if c.superclass is None:
+        return defaults
+    else:
+        return get_mangled_attribute_defaults(mm, c.superclass) | defaults
+
+
+def _find_attribute_class(
+    mm: MetaModel,
+    cname: str,
+    aname: str,
+) -> DOMLClass:
+    c = mm[cname]
+    if aname in c.attributes:
+        return c
+    elif c.superclass is None:
+        raise AttributeNotFound(
+            f"Attribute {aname} not found in subclasses of {cname}."
+        )
+    else:
+        return _find_attribute_class(mm, c.superclass, aname)
+
+
+def get_mangled_attribute_name(
+    mm: MetaModel,
+    cname: str,
+    aname: str,
+) -> str:
+    return f"{_find_attribute_class(mm, cname, aname).name}::{aname}"
+
+
+def get_subclasses_dict(mm: MetaModel) -> dict[str, set[str]]:
+    inherits_dg = nx.DiGraph(
+        [
+            (c.name, c.superclass)
+            for c in mm.values()
+            if c.superclass is not None
+        ]
+    )
+    inherits_dg.add_nodes_from(mm)
+    inherits_dg_trans = cast(
+        nx.DiGraph, nx.transitive_closure(inherits_dg, reflexive=True)
+    )
+    return {cname: set(inherits_dg_trans.predecessors(cname)) for cname in mm}
+
+
+def get_superclasses_dict(mm: MetaModel) -> dict[str, set[str]]:
+    inherits_dg = nx.DiGraph(
+        [
+            (c.name, c.superclass)
+            for c in mm.values()
+            if c.superclass is not None
+        ]
+    )
+    inherits_dg.add_nodes_from(mm)
+    inherits_dg_trans = cast(
+        nx.DiGraph, nx.transitive_closure(inherits_dg, reflexive=True)
+    )
+    return {cname: set(inherits_dg_trans.successors(cname)) for cname in mm}
diff --git a/mc_openapi/doml_mc/intermediate_model/types.py b/mc_openapi/doml_mc/intermediate_model/types.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ca340b68f2d29708d852e599cc6a0eb09abd2bc
--- /dev/null
+++ b/mc_openapi/doml_mc/intermediate_model/types.py
@@ -0,0 +1,2 @@
+from .metamodel import MetaModel  # noqa: F401
+from .doml_element import IntermediateModel  # noqa: F401
diff --git a/mc_openapi/doml_mc/mc.py b/mc_openapi/doml_mc/mc.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b7180351ae432150797f952c7d3411ade0d60b4
--- /dev/null
+++ b/mc_openapi/doml_mc/mc.py
@@ -0,0 +1,172 @@
+import importlib.resources as ilres
+
+import yaml
+from dataclasses import dataclass
+
+from z3 import (
+    CheckSatResult, Consts, ExprRef, FuncDeclRef, Solver, SortRef,
+    ForAll, Exists, Implies, And
+)
+
+from .. import assets
+from .intermediate_model.doml_element import reciprocate_inverse_associations
+from .intermediate_model.doml_model2im import doml_model_to_im
+from .intermediate_model.metamodel import (
+    parse_inverse_associations,
+    parse_metamodel
+)
+from .xmi_parser.doml_model import parse_doml_model
+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_and_assert_constraints,
+    def_attribute_rel_and_assert_constraints,
+    mk_association_sort_dict,
+    mk_attribute_sort_dict, mk_class_sort_dict
+)
+from .z3encoding.types import Refs
+from .z3encoding.utils import mk_adata_sort
+
+
+@dataclass
+class SMTEncoding:
+    classes: Refs
+    associations: Refs
+    attributes: Refs
+    elements: Refs
+    str_symbols: Refs
+    element_class_fun: FuncDeclRef
+    attribute_rel: FuncDeclRef
+    association_rel: FuncDeclRef
+
+
+@dataclass
+class SMTSorts:
+    class_sort: SortRef
+    association_sort: SortRef
+    attribute_sort: SortRef
+    element_sort: SortRef
+    str_symbols_sort: SortRef
+
+
+class ModelChecker:
+    metamodel = None
+    inv_assoc = None
+
+    @staticmethod
+    def init_metamodel():
+        mmdoc = yaml.load(ilres.read_text(assets, "doml_meta.yaml"), yaml.Loader)
+        ModelChecker.metamodel = parse_metamodel(mmdoc)
+        ModelChecker.inv_assoc = parse_inverse_associations(mmdoc)
+
+    def __init__(self, xmi_model: bytes):
+        def instantiate_solver():
+            unbound_elems = []  # TODO: add this later
+            self.solver = Solver()
+
+            class_sort, class_ = mk_class_sort_dict(ModelChecker.metamodel)
+            assoc_sort, assoc = mk_association_sort_dict(ModelChecker.metamodel)
+            attr_sort, attr = mk_attribute_sort_dict(ModelChecker.metamodel)
+            elem_sort, elem = mk_elem_sort_dict(self.intermediate_model, unbound_elems)
+            ss_sort, ss = mk_stringsym_sort_dict(self.intermediate_model, ModelChecker.metamodel)
+            AData = mk_adata_sort(ss_sort)
+            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_and_assert_constraints(
+                ModelChecker.metamodel,
+                self.solver,
+                attr_sort,
+                attr,
+                class_,
+                elem_class_f,
+                elem_sort,
+                AData,
+                ss
+            )
+            assert_im_attributes(
+                attr_rel,
+                self.solver,
+                self.intermediate_model,
+                ModelChecker.metamodel,
+                elem,
+                attr_sort,
+                attr,
+                AData,
+                ss
+            )
+            assoc_rel = def_association_rel_and_assert_constraints(
+                ModelChecker.metamodel,
+                self.solver,
+                assoc_sort,
+                assoc,
+                class_,
+                elem_class_f,
+                elem_sort,
+                ModelChecker.inv_assoc
+            )
+            assert_im_associations_q(
+                assoc_rel,
+                self.solver,
+                {k: v for k, v in self.intermediate_model.items() if k not in unbound_elems},
+                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
+            )
+
+        assert ModelChecker.metamodel and ModelChecker.inv_assoc
+        doml_model = parse_doml_model(xmi_model, ModelChecker.metamodel)
+        self.intermediate_model = doml_model_to_im(doml_model, ModelChecker.metamodel)
+        reciprocate_inverse_associations(self.intermediate_model, ModelChecker.inv_assoc)
+        instantiate_solver()
+
+    def get_consts(self, consts: list[str]) -> list[ExprRef]:
+        return Consts(" ".join(consts), self.smt_sorts.element_sort)
+
+    def check(self) -> CheckSatResult:
+        return self.solver.check()
+
+    def add_requirement(self, assertion: ExprRef, description: str):
+        self.solver.assert_and_track(assertion, description)
+
+    def add_common_requirements(self):
+        vm, iface = self.get_consts(["vm", "iface"])
+        smtenc = self.smt_encoding
+        vmIfaceAssertion = 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)
+                    )
+                )
+            )
+        )
+        self.add_requirement(vmIfaceAssertion, "vm_iface")
diff --git a/mc_openapi/doml_mc/model/__init__.py b/mc_openapi/doml_mc/model/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/mc_openapi/doml_mc/model/application.py b/mc_openapi/doml_mc/model/application.py
new file mode 100644
index 0000000000000000000000000000000000000000..162cff5e67ae1b7f31f6cf7896f02608169b8665
--- /dev/null
+++ b/mc_openapi/doml_mc/model/application.py
@@ -0,0 +1,63 @@
+from dataclasses import dataclass
+
+
+@dataclass
+class Application:
+    name: str
+    children: dict[str, "ApplicationComponent"]
+
+
+@dataclass
+class ApplicationComponent:
+    typeId: str
+    name: str
+    consumedInterfaces: dict[str, list[str]]
+    exposedInterfaces: dict[str, "ApplicationInterface"]
+
+
+@dataclass
+class ApplicationInterface:
+    name: str
+    componentName: str
+    typeId: str
+    endPoint: str
+
+
+def parse_application(doc: dict) -> Application:
+    def parse_application_component(doc: dict) -> ApplicationComponent:
+        def remove_prefix(s: str, prefix: str) -> str:
+            return s[len(prefix) :] if s.startswith(prefix) else s
+
+        def parse_application_interface(
+            doc: dict, componentName: str
+        ) -> ApplicationInterface:
+            return ApplicationInterface(
+                name=doc["name"],
+                componentName=componentName,
+                typeId=doc["typeId"],
+                endPoint=doc["endPoint"],
+            )
+
+        return ApplicationComponent(
+            name=doc["name"],
+            typeId=doc["typeId"],
+            consumedInterfaces={
+                remove_prefix(k, "consumedInterfaces->"): d
+                for k, d in doc.items()
+                if k.startswith("consumedInterfaces->")
+            },
+            exposedInterfaces={
+                intdoc["name"]: parse_application_interface(
+                    intdoc, doc["name"]
+                )
+                for intdoc in doc.get("exposedInterfaces", [])
+            },
+        )
+
+    return Application(
+        name=doc["name"],
+        children={
+            compdoc["name"]: parse_application_component(compdoc)
+            for compdoc in doc["children"]
+        },
+    )
diff --git a/mc_openapi/doml_mc/model/concretization.py b/mc_openapi/doml_mc/model/concretization.py
new file mode 100644
index 0000000000000000000000000000000000000000..2769d8b663806267989841d7df50358823d4828e
--- /dev/null
+++ b/mc_openapi/doml_mc/model/concretization.py
@@ -0,0 +1,102 @@
+from dataclasses import dataclass
+
+
+@dataclass
+class Concretization:
+    name: str
+    groups: dict[str, "Group"]
+    vms: dict[str, "VirtualMachine"]
+    providers: dict[str, "Provider"]
+    storages: dict[str, "Storage"]
+    networks: dict[str, "Network"]
+
+
+@dataclass
+class Group:
+    name: str
+    maps: str
+
+
+@dataclass
+class VirtualMachine:
+    name: str
+    maps: str
+
+
+@dataclass
+class Provider:
+    name: str
+    supportedGroups: list[str]
+    providedVMs: list[str]
+    storages: list[str]
+    providedNetworks: list[str]
+    description: str
+
+
+@dataclass
+class Storage:
+    name: str
+    maps: str
+
+
+@dataclass
+class Network:
+    name: str
+    maps: str
+
+
+def parse_concretization(doc: dict) -> Concretization:
+    def parse_group(doc: dict) -> Group:
+        return Group(
+            name=doc["name"],
+            maps=doc["maps"],
+        )
+
+    def parse_virtual_machine(doc: dict) -> VirtualMachine:
+        return VirtualMachine(
+            name=doc["name"],
+            maps=doc["maps"],
+        )
+
+    def parse_provider(doc: dict) -> Provider:
+        return Provider(
+            name=doc["name"],
+            supportedGroups=doc.get("supportedGroups", []),
+            providedVMs=doc["providedVMs"],
+            storages=doc.get("storages", []),
+            providedNetworks=doc["providedNetworks"],
+            description=doc.get("description", ""),
+        )
+
+    def parse_storage(doc: dict) -> Storage:
+        return Storage(
+            name=doc["name"],
+            maps=doc["maps"],
+        )
+
+    def parse_network(doc: dict) -> Network:
+        return Network(
+            name=doc["name"],
+            maps=doc["maps"],
+        )
+
+    return Concretization(
+        name=doc["name"],
+        groups={
+            gdoc["name"]: parse_group(gdoc) for gdoc in doc.get("asGroups", [])
+        },
+        vms={
+            vmdooc["name"]: parse_virtual_machine(vmdooc)
+            for vmdooc in doc["vms"]
+        },
+        providers={
+            pdoc["name"]: parse_provider(pdoc) for pdoc in doc["providers"]
+        },
+        storages={
+            sdoc["name"]: parse_storage(sdoc)
+            for sdoc in doc.get("storages", [])
+        },
+        networks={
+            ndoc["name"]: parse_network(ndoc) for ndoc in doc["networks"]
+        },
+    )
diff --git a/mc_openapi/doml_mc/model/doml_model.py b/mc_openapi/doml_mc/model/doml_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..4088d4e734938cbf8f5ccfe3d4856499c703b71d
--- /dev/null
+++ b/mc_openapi/doml_mc/model/doml_model.py
@@ -0,0 +1,39 @@
+from dataclasses import dataclass
+from typing import Optional
+
+from ..intermediate_model.metamodel import MetaModel
+
+from .application import Application, parse_application
+from .infrastructure import Infrastructure, parse_infrastructure
+from .optimization import Optimization, parse_optimization
+from .concretization import Concretization, parse_concretization
+
+
+@dataclass
+class DOMLModel:
+    name: str
+    modelname: str
+    id: str
+    version: str
+    application: Application
+    infrastructure: Infrastructure
+    optimization: Optional[Optimization]
+    concretizations: dict[str, Concretization]
+
+
+def parse_doml_model(doc: dict, mm: MetaModel) -> DOMLModel:
+    return DOMLModel(
+        name=doc["name"],
+        modelname=doc["modelname"],
+        id=doc["id"],
+        version=doc["version"],
+        application=parse_application(doc["application"]),
+        infrastructure=parse_infrastructure(doc["infrastructure"], mm),
+        optimization=parse_optimization(doc["optimization"])
+        if "optimization" in doc
+        else None,
+        concretizations={
+            concdoc["name"]: parse_concretization(concdoc)
+            for concdoc in doc["concretizations"]
+        },
+    )
diff --git a/mc_openapi/doml_mc/model/infrastructure.py b/mc_openapi/doml_mc/model/infrastructure.py
new file mode 100644
index 0000000000000000000000000000000000000000..829345a42784b567889b530800602cd45a67ebee
--- /dev/null
+++ b/mc_openapi/doml_mc/model/infrastructure.py
@@ -0,0 +1,96 @@
+from dataclasses import dataclass
+from typing import Union
+
+from mc_openapi.doml_mc.intermediate_model.doml_element import (
+    parse_attrs_and_assocs_from_doc,
+)
+
+from ..intermediate_model.metamodel import MetaModel
+
+Attributes = dict[str, Union[str, int, bool]]
+Associations = dict[str, set[str]]
+
+
+@dataclass
+class Infrastructure:
+    nodes: dict[str, "InfrastructureNode"]
+    networks: dict[str, "Network"]
+    groups: dict[str, "Group"]
+
+
+@dataclass
+class InfrastructureNode:
+    name: str
+    typeId: str
+    network_interfaces: dict[str, "NetworkInterface"]
+    attributes: Attributes
+    associations: Associations
+
+
+@dataclass
+class Network:
+    name: str
+    protocol: str
+    addressRange: str
+
+
+@dataclass
+class NetworkInterface:
+    name: str
+    belongsTo: str
+    endPoint: str
+
+
+@dataclass
+class Group:
+    name: str
+    typeId: str
+
+
+def parse_infrastructure(doc: dict, mm: MetaModel) -> Infrastructure:
+    def parse_infrastructure_node(doc: dict) -> InfrastructureNode:
+        def parse_network_interface(doc: dict) -> NetworkInterface:
+            return NetworkInterface(
+                name=doc["name"],
+                belongsTo=doc["belongsTo"],
+                endPoint=doc["endPoint"],
+            )
+
+        typeId = doc["typeId"]
+        attrs, assocs = parse_attrs_and_assocs_from_doc(doc, typeId, mm)
+        return InfrastructureNode(
+            name=doc["name"],
+            typeId=typeId,
+            network_interfaces={
+                niface_doc["name"]: parse_network_interface(niface_doc)
+                for niface_doc in doc.get("interfaces", [])
+            },
+            attributes=attrs,
+            associations=assocs,
+        )
+
+    def parse_network(doc: dict) -> Network:
+        return Network(
+            name=doc["name"],
+            protocol=doc["protocol"],
+            addressRange=doc["addressRange"],
+        )
+
+    def parse_group(doc: dict) -> Group:
+        return Group(
+            name=doc["name"],
+            typeId=doc["typeId"],
+        )
+
+    return Infrastructure(
+        nodes={
+            ndoc["name"]: parse_infrastructure_node(ndoc)
+            for ndoc in doc["nodes"]
+        },
+        networks={
+            ndoc["name"]: parse_network(ndoc) for ndoc in doc["networks"]
+        },
+        groups={
+            gdoc["name"]: parse_group(gdoc) for gdoc in doc.get("groups", [])
+        },
+    )
diff --git a/mc_openapi/doml_mc/model/optimization.py b/mc_openapi/doml_mc/model/optimization.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d104d535e2a9d90a1263ed21690cbff9d525ed5
--- /dev/null
+++ b/mc_openapi/doml_mc/model/optimization.py
@@ -0,0 +1,12 @@
+from dataclasses import dataclass
+
+
+@dataclass
+class Optimization:
+    typeId: str
+
+
+def parse_optimization(doc: dict) -> Optimization:
+    return Optimization(
+        typeId=doc["typeId"],
+    )
diff --git a/mc_openapi/doml_mc/test.ipynb b/mc_openapi/doml_mc/test.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..fde0a33ebb02c98f28959ae07c9bf6c99de7abba
--- /dev/null
+++ b/mc_openapi/doml_mc/test.ipynb
@@ -0,0 +1,52 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import mc\n",
+    "\n",
+    "doml_document_path = \"../../tests/doml/nginx-openstack_v2.domlx\"\n",
+    "# doml_document_path = \"../../tests/doml/nginx-openstack_v2_wrong.domlx\"\n",
+    "with open(doml_document_path, \"rb\") as xmif:\n",
+    "    doc = xmif.read()\n",
+    "\n",
+    "dmc = mc.ModelChecker(doc)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "vm, iface = dmc.get_consts([\"vm\", \"iface\"])\n",
+    "smtenc = dmc.smt_encoding\n",
+    "vmIfaceAssertion = ForAll(\n",
+    "    [vm],\n",
+    "    Implies(\n",
+    "        smt_enc.element_class_fun(vm) == smt_enc.classes[\"infrastructure_VirtualMachine\"],\n",
+    "        Exists(\n",
+    "            [iface],\n",
+    "            And(\n",
+    "                smt_enc.association_rel(vm, smt_enc.associations[\"infrastructure_ComputingNode::ifaces\"], iface)\n",
+    "            )\n",
+    "        )\n",
+    "    )\n",
+    ")\n",
+    "dmc.add_requirement(vmIfaceAssertion, \"vm_iface\")\n",
+    "dmc.check()"
+   ]
+  }
+ ],
+ "metadata": {
+  "language_info": {
+   "name": "python"
+  },
+  "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/mc_openapi/doml_mc/xmi_parser/__init__.py b/mc_openapi/doml_mc/xmi_parser/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..381f99a5015e215f99c790d736aaf19381518b65
--- /dev/null
+++ b/mc_openapi/doml_mc/xmi_parser/__init__.py
@@ -0,0 +1,3 @@
+from .doml_model import parse_doml_model, init_doml_rset  # noqa: F401
+
+init_doml_rset()
diff --git a/mc_openapi/doml_mc/xmi_parser/application.py b/mc_openapi/doml_mc/xmi_parser/application.py
new file mode 100644
index 0000000000000000000000000000000000000000..d945af6d063b33760b52c2a8717fe4baa9feb2bf
--- /dev/null
+++ b/mc_openapi/doml_mc/xmi_parser/application.py
@@ -0,0 +1,63 @@
+from dataclasses import dataclass
+from pyecore.ecore import EObject
+
+from ..model.application import Application, ApplicationComponent, ApplicationInterface
+
+
+# @dataclass
+# class Property:
+#     key: str
+#     value: str
+#     typeId: str
+#
+# def parse_property(doc: ecore.Property) -> Property:
+#     return Property(
+#         key=doc.key,
+#         value=doc.value,
+#         typeId=doc.type
+#     )
+
+def parse_application(doc: EObject) -> Application:
+    # TODO: consider full ApplicationComponent class hierarchy
+    def parse_application_interface(doc: EObject, componentName: str) -> ApplicationInterface:
+        return ApplicationInterface(
+            name=doc.endPoint,
+            componentName=componentName,
+            typeId="application_" + doc.eClass.name,
+            endPoint=doc.endPoint,
+        )
+    def parse_application_component(doc: EObject, interfaces: dict) -> ApplicationComponent:
+        consumed = {}
+        for cif in doc.consumedInterfaces:
+            cifProvider = interfaces[cif.endPoint].componentName
+            if cifProvider in consumed:
+                consumed[cifProvider].append(cif.endPoint)
+            else:
+                consumed[cifProvider] = [cif.endPoint]
+
+        return ApplicationComponent(
+            name=doc.name,
+            typeId="application_" + doc.eClass.name,
+            consumedInterfaces=consumed,
+            exposedInterfaces={
+                intdoc.endpoint: parse_application_interface(
+                    intdoc, doc.name
+                )
+                for intdoc in doc.exposedInterfaces
+            },
+        )
+
+    # Parse all interfaces first
+    interfaces = {
+        iface.name: parse_application_interface(iface)
+        for comp in doc.components
+        for iface in comp.exposedInterfaces
+    }
+
+    return Application(
+        name=doc.name,
+        children={
+            compdoc.name: parse_application_component(compdoc, interfaces)
+            for compdoc in doc.components
+        },
+    )
diff --git a/mc_openapi/doml_mc/xmi_parser/concretization.py b/mc_openapi/doml_mc/xmi_parser/concretization.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c0919fed823a016806a499fc5c4a2371f60a7f1
--- /dev/null
+++ b/mc_openapi/doml_mc/xmi_parser/concretization.py
@@ -0,0 +1,62 @@
+from pyecore.ecore import EObject
+
+from ..model.concretization import Concretization, Group, VirtualMachine, Provider, Storage, Network
+
+
+def parse_concretization(doc: dict) -> Concretization:
+    def parse_provider(doc: EObject) -> (Provider, list[VirtualMachine], list[Group], list[Storage], list[Network]):
+        def parse_group(doc: EObject) -> Group:
+            return Group(
+                name=doc.name,
+                maps=doc.maps.name,
+            )
+
+        def parse_virtual_machine(doc: EObject) -> VirtualMachine:
+            return VirtualMachine(
+                name=doc.name,
+                maps=doc.maps.name,
+            )
+
+        def parse_storage(doc: EObject) -> Storage:
+            return Storage(
+                name=doc.name,
+                maps=doc.maps,
+            )
+
+        def parse_network(doc: EObject) -> Network:
+            return Network(
+                name=doc.name,
+                maps=doc.maps.name,
+            )
+
+        groups = list(map(parse_group, doc.group))
+        vms = list(map(parse_virtual_machine, doc.vms))
+        storages = list(map(parse_storage, doc.storages))
+        networks = list(map(parse_network, doc.networks))
+        provider = Provider(
+            name=doc.name,
+            supportedGroups=[g.name for g in groups],
+            providedVMs=[vm.name for vm in vms],
+            storages=[st.name for st in storages],
+            providedNetworks=[net.name for net in networks],
+            description=doc.description,
+        )
+        return (provider, vms, groups, storages, networks)
+
+    groups, vms, providers, storages, networks = ({}, {}, {}, {}, {})
+    for provdoc in doc.providers:
+        prov, pvms, pgroups, pstorages, pnets = parse_provider(provdoc)
+        providers[prov.name] = prov
+        vms |= {vm.name: vm for vm in pvms}
+        groups |= {gr.name: gr for gr in pgroups}
+        storages |= {st.name: st for st in pstorages}
+        networks |= {net.name: net for net in pnets}
+
+    return Concretization(
+        name=doc.name,
+        groups=groups,
+        vms=vms,
+        providers=providers,
+        storages=storages,
+        networks=networks,
+    )
diff --git a/mc_openapi/doml_mc/xmi_parser/doml_model.py b/mc_openapi/doml_mc/xmi_parser/doml_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7fe649041f06a12479722ab742373a79fe4ac45
--- /dev/null
+++ b/mc_openapi/doml_mc/xmi_parser/doml_model.py
@@ -0,0 +1,66 @@
+import copy
+import importlib.resources as ilres
+
+from mc_openapi import assets
+from mc_openapi.bytes_uri import BytesURI
+from pyecore.ecore import EObject
+from pyecore.resources import ResourceSet
+
+from ..intermediate_model.metamodel import MetaModel
+from ..model.doml_model import DOMLModel
+from .application import parse_application
+from .concretization import parse_concretization
+from .infrastructure import parse_infrastructure
+from .optimization import parse_optimization
+
+doml_rset = None
+def init_doml_rset():
+    global doml_rset
+    rset = ResourceSet()
+    resource = rset.get_resource(BytesURI(
+        "doml", bytes=ilres.read_binary(assets, "doml.ecore")
+    ))
+    doml_metamodel = resource.contents[0]
+
+    rset.metamodel_registry[doml_metamodel.nsURI] = doml_metamodel
+    for subp in doml_metamodel.eSubpackages:
+        rset.metamodel_registry[subp.nsURI] = subp
+
+    doml_rset = rset
+
+
+def get_rset():
+    assert doml_rset is not None
+    return copy.copy(doml_rset)
+
+
+def parse_xmi_model(raw_model: bytes) -> EObject:
+    try:
+        rset = get_rset()
+        doml_uri = BytesURI("user_doml", bytes=raw_model)
+        resource = rset.create_resource(doml_uri)
+        resource.load()
+        return resource.contents[0]
+
+    except Exception:
+        # TODO: do something meaningful
+        raise
+
+
+def parse_doml_model(raw_model: bytes, mm: MetaModel) -> DOMLModel:
+    model = parse_xmi_model(raw_model)
+
+    return DOMLModel(
+        name=model.name,
+        modelname=model.name,
+        id=model.name,
+        version="",
+        application=parse_application(model.application),
+        infrastructure=parse_infrastructure(model.infrastructure, mm),
+        optimization=parse_optimization(model.optimization)
+        if model.optimization is not None else None,
+        concretizations={
+            concdoc.name: parse_concretization(concdoc)
+            for concdoc in model.concretizations
+        },
+    )
diff --git a/mc_openapi/doml_mc/xmi_parser/infrastructure.py b/mc_openapi/doml_mc/xmi_parser/infrastructure.py
new file mode 100644
index 0000000000000000000000000000000000000000..c4428f3ab09a43cca0bb37b8ef1e083a35465e1b
--- /dev/null
+++ b/mc_openapi/doml_mc/xmi_parser/infrastructure.py
@@ -0,0 +1,59 @@
+from pyecore.ecore import EObject
+
+from mc_openapi.doml_mc.intermediate_model.doml_element import parse_attrs_and_assocs_from_doc
+
+from ..intermediate_model.metamodel import MetaModel
+from ..model.infrastructure import Infrastructure, InfrastructureNode, Network, NetworkInterface, Group
+
+
+def parse_infrastructure(doc: EObject, mm: MetaModel) -> Infrastructure:
+    def parse_infrastructure_node(doc: EObject) -> InfrastructureNode:
+        def parse_network_interface(doc: EObject) -> NetworkInterface:
+            return NetworkInterface(
+                name=doc.name,
+                belongsTo=doc.belongsTo.name,
+                endPoint=doc.endPoint,
+            )
+
+        if doc.eClass.name == "AutoScalingGroup":
+            doc = doc.machineDefinition
+
+        typeId = "infrastructure_" + doc.eClass.name
+        annotations_dict = {a.key: a.value for a in doc.annotations}
+        attrs, assocs = parse_attrs_and_assocs_from_doc(annotations_dict, typeId, mm)
+        return InfrastructureNode(
+            name=doc.name,
+            typeId=typeId,
+            network_interfaces={
+                niface_doc.name: parse_network_interface(niface_doc)
+                for niface_doc in doc.ifaces
+            },
+            attributes=attrs,
+            associations=assocs,
+        )
+
+    def parse_network(doc: EObject) -> Network:
+        return Network(
+            name=doc.name,
+            protocol=doc.protocol,
+            addressRange=doc.addressRange,
+        )
+
+    def parse_group(doc: EObject) -> Group:
+        return Group(
+            name=doc.name,
+            typeId="infrastructure_" + doc.eClass.name,
+        )
+
+    return Infrastructure(
+        nodes={
+            inode.name: inode
+            for inode in map(parse_infrastructure_node, doc.nodes)
+        },
+        networks={
+            ndoc.name: parse_network(ndoc) for ndoc in doc.networks
+        },
+        groups={
+            gdoc.name: parse_group(gdoc) for gdoc in doc.secGroups
+        },
+    )
diff --git a/mc_openapi/doml_mc/xmi_parser/optimization.py b/mc_openapi/doml_mc/xmi_parser/optimization.py
new file mode 100644
index 0000000000000000000000000000000000000000..4b4e4ea0f2e956e22b162911d1bde4b3a0752e65
--- /dev/null
+++ b/mc_openapi/doml_mc/xmi_parser/optimization.py
@@ -0,0 +1,9 @@
+from dataclasses import dataclass
+from pyecore.ecore import EObject
+
+from ..model.optimization import Optimization
+
+def parse_optimization(doc: EObject) -> Optimization:
+    return Optimization(
+        typeId="optimization_" + doc.eClass.name,
+    )
diff --git a/mc_openapi/doml_mc/z3encoding/__init__.py b/mc_openapi/doml_mc/z3encoding/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/mc_openapi/doml_mc/z3encoding/im_encoding.py b/mc_openapi/doml_mc/z3encoding/im_encoding.py
new file mode 100644
index 0000000000000000000000000000000000000000..084f1f4e56619da9a1449f24c08b21f4728106d9
--- /dev/null
+++ b/mc_openapi/doml_mc/z3encoding/im_encoding.py
@@ -0,0 +1,181 @@
+from typing import Union
+from itertools import product
+
+from z3 import (
+    And,
+    Const,
+    DatatypeRef,
+    DatatypeSortRef,
+    ForAll,
+    FuncDeclRef,
+    Function,
+    Or,
+    Solver,
+)
+
+from ..intermediate_model.types 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,
+)
+
+
+def mk_elem_sort_dict(
+    im: IntermediateModel, additional_elems: list[str] = []
+) -> SortAndRefs:
+    return mk_enum_sort_dict("Element", list(im) + additional_elems)
+
+
+def def_elem_class_f_and_assert_classes(
+    im: IntermediateModel,
+    solver: Solver,
+    elem_sort: DatatypeSortRef,
+    elem: Refs,
+    class_sort: DatatypeSortRef,
+    class_: Refs,
+) -> FuncDeclRef:
+    """
+    ### Effects
+    This procedure is effectful on `solver`.
+    """
+    elem_class_f = Function("elem_class", elem_sort, class_sort)
+    for ename, e in im.items():
+        solver.assert_and_track(
+            elem_class_f(elem[ename]) == class_[e.class_],
+            f"elem_class {ename} {e.class_}",
+        )
+    return elem_class_f
+
+
+def assert_im_attributes(
+    attr_rel: FuncDeclRef,
+    solver: Solver,
+    im: IntermediateModel,
+    mm: MetaModel,
+    elem: Refs,
+    attr_sort: DatatypeSortRef,
+    attr: Refs,
+    AData: DatatypeSortRef,
+    ss: Refs,
+) -> None:
+    """
+    ### Effects
+    This procedure is effectful on `solver`.
+    """
+
+    def encode_adata(v: Union[str, int, bool]) -> DatatypeRef:
+        if type(v) is str:
+            return AData.ss(ss[v])  # type: ignore
+        elif type(v) is int:
+            return AData.int(v)  # type: ignore
+        else:  # type(v) is bool
+            return AData.bool(v)  # type: ignore
+
+    a = Const("a", attr_sort)
+    d = Const("d", AData)
+    for esn, im_es in im.items():
+        mangled_attrs = (
+            get_mangled_attribute_defaults(mm, im_es.class_) | im_es.attributes
+        )
+        assn = ForAll(
+            [a, d],
+            Iff(
+                attr_rel(elem[esn], a, d),
+                Or(
+                    *(
+                        And(
+                            a == attr[amn],
+                            d == encode_adata(avalue),
+                        )
+                        for amn, avalue in mangled_attrs.items()
+                    )
+                ),
+            ),
+        )
+        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,
+    elem: Refs,
+    assoc_sort: DatatypeSortRef,
+    assoc: Refs,
+) -> None:
+    """
+    ### Effects
+    This procedure is effectful on `solver`.
+    """
+
+    a = Const("a", assoc_sort)
+    for (esn, im_es), etn in product(im.items(), im):
+        assn = ForAll(
+            [a],
+            Iff(
+                assoc_rel(elem[esn], a, elem[etn]),
+                Or(
+                    *(
+                        a == assoc[amn]
+                        for amn, etns in im_es.associations.items()
+                        if etn in etns
+                    )
+                ),
+            ),
+        )
+        solver.assert_and_track(assn, f"associations {esn} {etn}")
+
+
+def mk_stringsym_sort_dict(
+    im: IntermediateModel,
+    mm: MetaModel,
+) -> SortAndRefs:
+    strings = (
+        {
+            v
+            for e in im.values()
+            for v in e.attributes.values()
+            if type(v) is str
+        }
+        | {
+            a.default
+            for c in mm.values()
+            for a in c.attributes.values()
+            if type(a.default) is str
+        }
+        | {"SCRIPT", "IMAGE"}  # GeneratorKind values
+    )
+    return mk_stringsym_sort_from_strings(list(strings))
diff --git a/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py b/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py
new file mode 100644
index 0000000000000000000000000000000000000000..5cbd6fbd58b3ab33f3bca1271c0cf0b57d8a9dc7
--- /dev/null
+++ b/mc_openapi/doml_mc/z3encoding/metamodel_encoding.py
@@ -0,0 +1,240 @@
+from z3 import (
+    And,
+    BoolSort,
+    Const,
+    Consts,
+    DatatypeSortRef,
+    Exists,
+    ForAll,
+    FuncDeclRef,
+    Function,
+    Implies,
+    Or,
+    Solver,
+)
+from ..intermediate_model.types import MetaModel
+from ..intermediate_model.metamodel import get_subclasses_dict
+
+from .types import Refs, SortAndRefs
+from .utils import Iff, mk_enum_sort_dict
+
+
+def mk_class_sort_dict(
+    mm: MetaModel,
+) -> SortAndRefs:
+    return mk_enum_sort_dict("Class", list(mm))
+
+
+def mk_attribute_sort_dict(
+    mm: MetaModel,
+) -> SortAndRefs:
+    atts = [
+        f"{cname}::{aname}"
+        for cname, c in mm.items()
+        for aname in c.attributes
+    ]
+    return mk_enum_sort_dict("Attribute", atts)
+
+
+def mk_association_sort_dict(
+    mm: MetaModel,
+) -> SortAndRefs:
+    assocs = [
+        f"{cname}::{aname}"
+        for cname, c in mm.items()
+        for aname in c.associations
+    ]
+    return mk_enum_sort_dict("Association", assocs)
+
+
+def def_attribute_rel_and_assert_constraints(
+    mm: MetaModel,
+    solver: Solver,
+    attr_sort: DatatypeSortRef,
+    attr: Refs,
+    class_: Refs,
+    elem_class_f: FuncDeclRef,
+    elem_sort: DatatypeSortRef,
+    AData: DatatypeSortRef,
+    ss: Refs,
+) -> FuncDeclRef:
+    """
+    ### Effects
+    This procedure is effectful on `solver`.
+    """
+    attr_rel = Function("attribute", elem_sort, attr_sort, AData, BoolSort())
+    subclasses_dict = get_subclasses_dict(mm)
+    es = Const("es", elem_sort)
+    ad, ad_ = Consts("ad ad_", AData)
+    # A type validity constraint is added for every attribute:
+    for cname, c in mm.items():
+        src_subclass_cond = Or(  # Source subclass condition
+            *(
+                elem_class_f(es) == class_[scname]
+                for scname in subclasses_dict[cname]
+            )
+        )
+        for mm_attr in c.attributes.values():
+            # For all source elements and attribute data, their classes must be
+            # a subtype of the source class, and the data must be of the data
+            # type of the attribute.
+            if mm_attr.type == "Boolean":
+                tgt_type_cond = AData.is_bool(ad)  # type: ignore
+            elif mm_attr.type == "Integer":
+                tgt_type_cond = AData.is_int(ad)  # type: ignore
+            elif mm_attr.type == "String":
+                tgt_type_cond = AData.is_ss(ad)  # type: ignore
+            else:  # mm_attr.type == "GeneratorKind"
+                tgt_type_cond = Or(
+                    ad == AData.ss(ss["IMAGE"]),  # type: ignore
+                    ad == AData.ss(ss["SCRIPT"]),  # type: ignore
+                )
+            assn = ForAll(
+                [es, ad],
+                Implies(
+                    attr_rel(es, attr[f"{cname}::{mm_attr.name}"], ad),
+                    And(
+                        src_subclass_cond,
+                        tgt_type_cond,
+                    ),
+                ),
+            )
+            solver.assert_and_track(
+                assn, f"attribute_st_types {cname}::{mm_attr.name}"
+            )
+
+            # Multiplicity constraints
+            lb, ub = mm_attr.multiplicity
+            if lb == "1":
+                mult_lb_assn = ForAll(
+                    [es],
+                    Implies(
+                        src_subclass_cond,
+                        Exists(
+                            [ad],
+                            attr_rel(es, attr[f"{cname}::{mm_attr.name}"], ad),
+                        ),
+                    ),
+                )
+                solver.assert_and_track(
+                    mult_lb_assn,
+                    f"attribute_mult_lb {cname}::{mm_attr.name}",
+                )
+            if ub == "1":
+                mult_ub_assn = ForAll(
+                    [es, ad, ad_],
+                    Implies(
+                        And(
+                            attr_rel(es, attr[f"{cname}::{mm_attr.name}"], ad),
+                            attr_rel(
+                                es, attr[f"{cname}::{mm_attr.name}"], ad_
+                            ),
+                        ),
+                        ad == ad_,
+                    ),
+                )
+                solver.assert_and_track(
+                    mult_ub_assn,
+                    f"attribute_mult_ub {cname}::{mm_attr.name}",
+                )
+    return attr_rel
+
+
+def def_association_rel_and_assert_constraints(
+    mm: MetaModel,
+    solver: Solver,
+    assoc_sort: DatatypeSortRef,
+    assoc: Refs,
+    class_: Refs,
+    elem_class_f: FuncDeclRef,
+    elem_sort: DatatypeSortRef,
+    inv_assoc: list[tuple[str, str]],
+) -> FuncDeclRef:
+    """
+    ### Effects
+    This procedure is effectful on `solver`.
+    """
+    assoc_rel = Function(
+        "association", elem_sort, assoc_sort, elem_sort, BoolSort()
+    )
+    subclasses_dict = get_subclasses_dict(mm)
+    es, et, et_ = Consts("es et et_", elem_sort)
+    # A type validity constraint is added for every association:
+    for cname, c in mm.items():
+        src_subclass_cond = Or(  # Source subclass condition
+            *(
+                elem_class_f(es) == class_[scname]
+                for scname in subclasses_dict[cname]
+            )
+        )
+        for mm_assoc in c.associations.values():
+            # For all source and target elements that are associated, their
+            # classes must be a subtype of the source and target classes resp.
+            # of the association.
+            class_assn = ForAll(
+                [es, et],
+                Implies(
+                    assoc_rel(es, assoc[f"{cname}::{mm_assoc.name}"], et),
+                    And(
+                        src_subclass_cond,
+                        Or(  # Target subclass condition
+                            *(
+                                elem_class_f(et) == class_[scname]
+                                for scname in subclasses_dict[mm_assoc.class_]
+                            )
+                        ),
+                    ),
+                ),
+            )
+            solver.assert_and_track(
+                class_assn, f"association_st_classes {cname}::{mm_assoc.name}"
+            )
+
+            # Multiplicity constraints
+            lb, ub = mm_assoc.multiplicity
+            if lb == "1":
+                mult_lb_assn = ForAll(
+                    [es],
+                    Implies(
+                        src_subclass_cond,
+                        Exists(
+                            [et],
+                            assoc_rel(
+                                es, assoc[f"{cname}::{mm_assoc.name}"], et
+                            ),
+                        ),
+                    ),
+                )
+                solver.assert_and_track(
+                    mult_lb_assn,
+                    f"association_mult_lb {cname}::{mm_assoc.name}",
+                )
+            if ub == "1":
+                mult_ub_assn = ForAll(
+                    [es, et, et_],
+                    Implies(
+                        And(
+                            assoc_rel(
+                                es, assoc[f"{cname}::{mm_assoc.name}"], et
+                            ),
+                            assoc_rel(
+                                es, assoc[f"{cname}::{mm_assoc.name}"], et_
+                            ),
+                        ),
+                        et == et_,
+                    ),
+                )
+                solver.assert_and_track(
+                    mult_ub_assn,
+                    f"association_mult_ub {cname}::{mm_assoc.name}",
+                )
+
+    # Inverse association assertions
+    for an1, an2 in inv_assoc:
+        inv_assn = ForAll(
+            [es, et],
+            Iff(assoc_rel(es, assoc[an1], et), assoc_rel(et, assoc[an2], es)),
+        )
+        solver.assert_and_track(inv_assn, f"association_inverse {an1} {an2}")
+
+    return assoc_rel
diff --git a/mc_openapi/doml_mc/z3encoding/types.py b/mc_openapi/doml_mc/z3encoding/types.py
new file mode 100644
index 0000000000000000000000000000000000000000..9107a492bc789d6bd9f96c3f95d9add502d22fc1
--- /dev/null
+++ b/mc_openapi/doml_mc/z3encoding/types.py
@@ -0,0 +1,4 @@
+from z3 import DatatypeRef, DatatypeSortRef
+
+Refs = dict[str, DatatypeRef]
+SortAndRefs = tuple[DatatypeSortRef, Refs]
diff --git a/mc_openapi/doml_mc/z3encoding/utils.py b/mc_openapi/doml_mc/z3encoding/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..5e2f0b6d5e53d1940e54d19e208226d909b80db2
--- /dev/null
+++ b/mc_openapi/doml_mc/z3encoding/utils.py
@@ -0,0 +1,147 @@
+from typing import cast
+from collections.abc import Sequence
+from itertools import product
+
+from z3 import (
+    BoolSort,
+    BoolVal,
+    Datatype,
+    DatatypeSortRef,
+    ExprRef,
+    EnumSort,
+    FuncDeclRef,
+    IntSort,
+    Solver,
+)
+
+from .types import Refs, SortAndRefs
+
+
+def mk_enum_sort_dict(name: str, values: list[str]) -> SortAndRefs:
+    """Makes a Z3 sort and a dict indexing sort values by their name"""
+
+    sort, dtrefs = EnumSort(name, values)
+    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)]
+        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],
+) -> 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)
+    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,
+) -> DatatypeSortRef:
+    AData = Datatype("AttributeData")
+    AData.declare("int", ("get_int", IntSort()))
+    AData.declare("bool", ("get_bool", BoolSort()))
+    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 9e467c82b8cab77a43979138b43a7680cdfac8b1..641cc4165ea42da97cc75200d9e5084a9f1f5a9d 100644
--- a/mc_openapi/handlers.py
+++ b/mc_openapi/handlers.py
@@ -1,44 +1,30 @@
 import datetime
-import copy
-from pyecore.resources import ResourceSet, URI
-from mc_openapi.string_uri import StringURI
+from z3 import sat, unsat
+from .doml_mc import ModelChecker
 
-def get_rset():
-    if get_rset.doml_rset is None:
-        rset = ResourceSet()
-        resource = rset.get_resource(URI("mc_openapi/doml/doml.ecore"))
-        doml_metamodel = resource.contents[0]
-
-        rset.metamodel_registry[doml_metamodel.nsURI] = doml_metamodel
-        for subp in doml_metamodel.eSubpackages:
-            rset.metamodel_registry[subp.nsURI] = subp
-
-        get_rset.doml_rset = rset
-
-    assert get_rset.doml_rset is not None
-    return copy.copy(get_rset.doml_rset)
-get_rset.doml_rset = None
 
 def make_error(user_msg, debug_msg=None):
-    result = { "message": user_msg, "timestamp": datetime.datetime.now() }
+    result = {"message": user_msg, "timestamp": datetime.datetime.now()}
     if debug_msg is not None:
         result["debug_message"] = debug_msg
     return result
 
+
 def post(body, requirement=None):
     doml_xmi = body
     try:
-        rset = get_rset()
-        doml_uri = StringURI("user_doml", text=doml_xmi)
-        resource = rset.create_resource(doml_uri)
-        resource.load()
-        doml = resource.contents[0]
-
-        if doml.infrastructure.nodes[0].machineDefinition.ifaces[0].belongsTo is None:
-            return { "result": "unsat",
-                     "description": "Virtual machine is not linked to any network." }
-
-        return  { "result": "sat" }
+        dmc = ModelChecker(doml_xmi)
+        dmc.add_common_requirements()
+
+        result = dmc.check()
+
+        if result == sat:
+            return {"result": "sat"}
+        elif result == unsat:
+            return {"result": "unsat",
+                    "description": "Virtual machine is not linked to any network."}
+        else:
+            return {"result": "dontknow"}
 
     except Exception as e:
         return make_error("Supplied with malformed DOML XMI model.", debug_msg=str(e)), 400
diff --git a/poetry.lock b/poetry.lock
index c532720446b09c97e8966afbd396d8fb825a4056..30b284ea5e3b654c519c2b67cf7dda4a73001734 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,3 +1,25 @@
+[[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.5"
+description = "Annotate AST trees with source code positions"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+six = "*"
+
+[package.extras]
+test = ["astroid", "pytest"]
+
 [[package]]
 name = "atomicwrites"
 version = "1.4.0"
@@ -8,17 +30,25 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "attrs"
-version = "21.2.0"
+version = "21.4.0"
 description = "Classes Without Boilerplate"
 category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
 [package.extras]
-dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
 docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
-tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
-tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
+
+[[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"
@@ -28,9 +58,20 @@ category = "main"
 optional = false
 python-versions = "*"
 
+[[package]]
+name = "cffi"
+version = "1.15.0"
+description = "Foreign Function Interface for Python calling C code."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+pycparser = "*"
+
 [[package]]
 name = "charset-normalizer"
-version = "2.0.9"
+version = "2.0.12"
 description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
 category = "main"
 optional = false
@@ -41,11 +82,14 @@ unicode_backport = ["unicodedata2"]
 
 [[package]]
 name = "click"
-version = "7.1.2"
+version = "8.1.2"
 description = "Composable command line interface toolkit"
 category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.7"
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
 
 [[package]]
 name = "clickclick"
@@ -63,13 +107,24 @@ PyYAML = ">=3.11"
 name = "colorama"
 version = "0.4.4"
 description = "Cross-platform colored terminal text."
-category = "dev"
+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.12.0"
+version = "2.13.0"
 description = "Connexion - API first applications with OpenAPI/Swagger and Flask"
 category = "main"
 optional = false
@@ -81,7 +136,8 @@ flask = ">=1.0.4,<3"
 inflection = ">=0.3.1,<0.6"
 itsdangerous = ">=0.24"
 jsonschema = ">=2.5.1,<5"
-PyYAML = ">=5.1,<6"
+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"
@@ -93,23 +149,55 @@ flask = ["flask (>=1.0.4,<3)", "itsdangerous (>=0.24)"]
 swagger-ui = ["swagger-ui-bundle (>=0.0.2,<0.1)"]
 tests = ["decorator (>=5,<6)", "pytest (>=6,<7)", "pytest-cov (>=2,<3)", "testfixtures (>=6,<7)", "flask (>=1.0.4,<3)", "itsdangerous (>=0.24)", "swagger-ui-bundle (>=0.0.2,<0.1)", "aiohttp (>=2.3.10,<4)", "aiohttp-jinja2 (>=0.14.0,<2)", "MarkupSafe (>=0.23)", "pytest-aiohttp", "aiohttp-remotes"]
 
+[[package]]
+name = "debugpy"
+version = "1.6.0"
+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 = "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 = "0.8.3"
+description = "Get the currently executing AST node of a frame, and other information"
+category = "dev"
+optional = false
+python-versions = "*"
+
 [[package]]
 name = "flask"
-version = "1.1.4"
+version = "2.1.1"
 description = "A simple framework for building complex web applications."
 category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.7"
 
 [package.dependencies]
-click = ">=5.1,<8.0"
-itsdangerous = ">=0.24,<2.0"
-Jinja2 = ">=2.10.1,<3.0"
-Werkzeug = ">=0.15,<2.0"
+click = ">=8.0"
+importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""}
+itsdangerous = ">=2.0"
+Jinja2 = ">=3.0"
+Werkzeug = ">=2.0"
 
 [package.extras]
-dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
-docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
+async = ["asgiref (>=3.2)"]
 dotenv = ["python-dotenv"]
 
 [[package]]
@@ -131,6 +219,22 @@ category = "main"
 optional = false
 python-versions = ">=3.5"
 
+[[package]]
+name = "importlib-metadata"
+version = "4.11.3"
+description = "Read metadata from Python packages"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+
+[package.dependencies]
+zipp = ">=0.5"
+
+[package.extras]
+docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
+perf = ["ipython"]
+testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
+
 [[package]]
 name = "inflection"
 version = "0.5.1"
@@ -139,44 +243,149 @@ category = "main"
 optional = false
 python-versions = ">=3.5"
 
+[[package]]
+name = "ipykernel"
+version = "6.13.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 = "*"
+tornado = ">=6.1"
+traitlets = ">=5.1.0"
+
+[package.extras]
+test = ["pytest (>=6.0)", "pytest-cov", "flaky", "ipyparallel", "pre-commit", "pytest-timeout"]
+
+[[package]]
+name = "ipython"
+version = "8.2.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 = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0"
+pygments = ">=2.4.0"
+stack-data = "*"
+traitlets = ">=5"
+
+[package.extras]
+all = ["black", "Sphinx (>=1.3)", "ipykernel", "nbconvert", "nbformat", "ipywidgets", "notebook", "ipyparallel", "qtconsole", "pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "numpy (>=1.19)", "pandas", "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 = ["pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "trio"]
+
 [[package]]
 name = "itsdangerous"
-version = "1.1.0"
-description = "Various helpers to pass data to untrusted environments and back."
+version = "2.1.2"
+description = "Safely pass data to untrusted environments and back."
 category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+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 = "2.11.3"
+version = "3.1.1"
 description = "A very fast and expressive template engine."
 category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.7"
 
 [package.dependencies]
-MarkupSafe = ">=0.23"
+MarkupSafe = ">=2.0"
 
 [package.extras]
-i18n = ["Babel (>=0.8)"]
+i18n = ["Babel (>=2.7)"]
 
 [[package]]
 name = "jsonschema"
-version = "3.2.0"
+version = "4.4.0"
 description = "An implementation of JSON Schema validation for Python"
 category = "main"
 optional = false
-python-versions = "*"
+python-versions = ">=3.7"
 
 [package.dependencies]
 attrs = ">=17.4.0"
-pyrsistent = ">=0.14.0"
-six = ">=1.11.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 = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"]
-format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"]
+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.2.2"
+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 = ">=22.3"
+tornado = ">=6.0"
+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.9.2"
+description = "Jupyter core package. A base package on which Jupyter projects rely."
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""}
+traitlets = "*"
 
 [[package]]
 name = "lxml"
@@ -194,11 +403,22 @@ source = ["Cython (>=0.29.7)"]
 
 [[package]]
 name = "markupsafe"
-version = "2.0.1"
+version = "2.1.1"
 description = "Safely add untrusted strings to HTML/XML markup."
 category = "main"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
+
+[[package]]
+name = "matplotlib-inline"
+version = "0.1.3"
+description = "Inline Matplotlib backend for Jupyter"
+category = "dev"
+optional = false
+python-versions = ">=3.5"
+
+[package.dependencies]
+traitlets = "*"
 
 [[package]]
 name = "more-itertools"
@@ -208,6 +428,29 @@ category = "dev"
 optional = false
 python-versions = ">=3.5"
 
+[[package]]
+name = "nest-asyncio"
+version = "1.5.5"
+description = "Patch asyncio to allow nested event loops"
+category = "dev"
+optional = false
+python-versions = ">=3.5"
+
+[[package]]
+name = "networkx"
+version = "2.8"
+description = "Python package for creating and manipulating graphs and networks"
+category = "main"
+optional = false
+python-versions = ">=3.8"
+
+[package.extras]
+default = ["numpy (>=1.19)", "scipy (>=1.8)", "matplotlib (>=3.4)", "pandas (>=1.3)"]
+developer = ["pre-commit (>=2.18)", "mypy (>=0.942)"]
+doc = ["sphinx (>=4.5)", "pydata-sphinx-theme (>=0.8.1)", "sphinx-gallery (>=0.10)", "numpydoc (>=1.2)", "pillow (>=9.1)", "nb2plots (>=0.6)", "texext (>=0.6.6)"]
+extra = ["lxml (>=4.6)", "pygraphviz (>=1.9)", "pydot (>=1.4.2)", "sympy (>=1.10)"]
+test = ["pytest (>=7.1)", "pytest-cov (>=3.0)", "codecov (>=2.1)"]
+
 [[package]]
 name = "ordered-set"
 version = "4.1.0"
@@ -223,13 +466,44 @@ dev = ["pytest", "black", "mypy"]
 name = "packaging"
 version = "21.3"
 description = "Core utilities for Python packages"
-category = "dev"
+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 = "0.13.1"
@@ -241,6 +515,59 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 [package.extras]
 dev = ["pre-commit", "tox"]
 
+[[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.29"
+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.0"
+description = "Cross-platform lib for process and system monitoring in Python."
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.extras]
+test = ["ipaddress", "mock", "unittest2", "enum34", "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"
@@ -249,6 +576,14 @@ 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"
@@ -264,23 +599,31 @@ ordered-set = ">=4.0.1"
 restrictedpython = ">=4.0b6"
 
 [[package]]
-name = "pyparsing"
-version = "3.0.6"
-description = "Python parsing module"
+name = "pygments"
+version = "2.11.2"
+description = "Pygments is a syntax highlighting package written in Python."
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.5"
+
+[[package]]
+name = "pyparsing"
+version = "3.0.8"
+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"]
+diagrams = ["railroad-diagrams", "jinja2"]
 
 [[package]]
 name = "pyrsistent"
-version = "0.18.0"
+version = "0.18.1"
 description = "Persistent/Functional/Immutable data structures"
 category = "main"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [[package]]
 name = "pytest"
@@ -304,17 +647,48 @@ wcwidth = "*"
 checkqa-mypy = ["mypy (==v0.761)"]
 testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "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 = "pywin32"
+version = "303"
+description = "Python for Window Extensions"
+category = "dev"
+optional = false
+python-versions = "*"
+
 [[package]]
 name = "pyyaml"
-version = "5.4.1"
+version = "6.0"
 description = "YAML parser and emitter for Python"
 category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+python-versions = ">=3.6"
+
+[[package]]
+name = "pyzmq"
+version = "22.3.0"
+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.26.0"
+version = "2.27.1"
 description = "Python HTTP for Humans."
 category = "main"
 optional = false
@@ -345,10 +719,26 @@ test = ["pytest", "pytest-mock"]
 name = "six"
 version = "1.16.0"
 description = "Python 2 and 3 compatibility utilities"
-category = "main"
+category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
 
+[[package]]
+name = "stack-data"
+version = "0.2.0"
+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 = ["pytest", "typeguard", "pygments", "littleutils", "cython"]
+
 [[package]]
 name = "swagger-ui-bundle"
 version = "0.0.9"
@@ -360,16 +750,35 @@ python-versions = "*"
 [package.dependencies]
 Jinja2 = ">=2.0"
 
+[[package]]
+name = "tornado"
+version = "6.1"
+description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
+category = "dev"
+optional = false
+python-versions = ">= 3.5"
+
+[[package]]
+name = "traitlets"
+version = "5.1.1"
+description = "Traitlets Python configuration system"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+test = ["pytest"]
+
 [[package]]
 name = "urllib3"
-version = "1.26.7"
+version = "1.26.9"
 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.*, <4"
 
 [package.extras]
-brotli = ["brotlipy (>=0.6.0)"]
+brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"]
 secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
 socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
 
@@ -391,41 +800,124 @@ python-versions = "*"
 
 [[package]]
 name = "werkzeug"
-version = "1.0.1"
+version = "2.1.1"
 description = "The comprehensive WSGI web application library."
 category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.7"
 
 [package.extras]
-dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"]
 watchdog = ["watchdog"]
 
+[[package]]
+name = "z3-solver"
+version = "4.8.15.0"
+description = "an efficient SMT solver library"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "zipp"
+version = "3.8.0"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
+testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
+
 [metadata]
 lock-version = "1.1"
-python-versions = "^3.8"
-content-hash = "230a5aa6082d4f5282cacd6b28dc9e65a0564056fc42ad904ede0d3956d7fdb8"
+python-versions = "^3.9"
+content-hash = "72a3672221767f9290b32103d450d8eef559efdbdad5c2775ba3e13f40d4b0ba"
 
 [metadata.files]
+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.5-py2.py3-none-any.whl", hash = "sha256:0844691e88552595a6f4a4281a9f7f79b8dd45ca4ccea82e5e05b4bbdb76705c"},
+    {file = "asttokens-2.0.5.tar.gz", hash = "sha256:9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5"},
+]
 atomicwrites = [
     {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
     {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
 ]
 attrs = [
-    {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
-    {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
+    {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
+    {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
+]
+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-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
     {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
 ]
+cffi = [
+    {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"},
+    {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"},
+    {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"},
+    {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"},
+    {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"},
+    {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"},
+    {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"},
+    {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"},
+    {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"},
+    {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"},
+    {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"},
+    {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"},
+    {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"},
+    {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"},
+    {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"},
+    {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"},
+    {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"},
+    {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"},
+    {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"},
+    {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"},
+    {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"},
+    {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"},
+    {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"},
+    {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"},
+    {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"},
+]
 charset-normalizer = [
-    {file = "charset-normalizer-2.0.9.tar.gz", hash = "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c"},
-    {file = "charset_normalizer-2.0.9-py3-none-any.whl", hash = "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721"},
+    {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
+    {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
 ]
 click = [
-    {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
-    {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
+    {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"},
+    {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"},
 ]
 clickclick = [
     {file = "clickclick-20.10.2-py2.py3-none-any.whl", hash = "sha256:c8f33e6d9ec83f68416dd2136a7950125bd256ec39ccc9a85c6e280a16be2bb5"},
@@ -435,13 +927,49 @@ colorama = [
     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
     {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
 ]
+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.12.0-py2.py3-none-any.whl", hash = "sha256:2d163976fbc8766038d71f4232ace07826be7dd0a8fe7a539ce5fc8a80f1ab35"},
-    {file = "connexion-2.12.0.tar.gz", hash = "sha256:c08b530418a1c448d34cd142713ddd1b245e7694f45cd80533fe8538b64aa7eb"},
+    {file = "connexion-2.13.0-py2.py3-none-any.whl", hash = "sha256:26a570a0283bbe4cdaf5d90dfb3441aaf8e18cb9de10f3f96bbc128a8a3d8b47"},
+    {file = "connexion-2.13.0.tar.gz", hash = "sha256:0ba5c163d34cb3cb3bf597d5b95fc14bad5d3596bf10ec86e32cdb63f68d0c8a"},
+]
+debugpy = [
+    {file = "debugpy-1.6.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:eb1946efac0c0c3d411cea0b5ac772fbde744109fd9520fb0c5a51979faf05ad"},
+    {file = "debugpy-1.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e3513399177dd37af4c1332df52da5da1d0c387e5927dc4c0709e26ee7302e8f"},
+    {file = "debugpy-1.6.0-cp310-cp310-win32.whl", hash = "sha256:5c492235d6b68f879df3bdbdb01f25c15be15682665517c2c7d0420e5658d71f"},
+    {file = "debugpy-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:40de9ba137d355538432209d05e0f5fe5d0498dce761c39119ad4b950b51db31"},
+    {file = "debugpy-1.6.0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:0d383b91efee57dbb923ba20801130cf60450a0eda60bce25bccd937de8e323a"},
+    {file = "debugpy-1.6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1ff853e60e77e1c16f85a31adb8360bb2d98ca588d7ed645b7f0985b240bdb5e"},
+    {file = "debugpy-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:8e972c717d95f56b6a3a7a29a5ede1ee8f2c3802f6f0e678203b0778eb322bf1"},
+    {file = "debugpy-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a8aaeb53e87225141fda7b9081bd87155c1debc13e2f5a532d341112d1983b65"},
+    {file = "debugpy-1.6.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:132defb585b518955358321d0f42f6aa815aa15b432be27db654807707c70b2f"},
+    {file = "debugpy-1.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ee75844242b4537beb5899f3e60a578454d1f136b99e8d57ac424573797b94a"},
+    {file = "debugpy-1.6.0-cp38-cp38-win32.whl", hash = "sha256:a65a2499761d47df3e9ea9567109be6e73d412e00ac3ffcf74839f3ddfcdf028"},
+    {file = "debugpy-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:bd980d533d0ddfc451e03a3bb32acb2900049fec39afc3425b944ebf0889be62"},
+    {file = "debugpy-1.6.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:245c7789a012f86210847ec7ee9f38c30a30d4c2223c3e111829a76c9006a5d0"},
+    {file = "debugpy-1.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e3aa2368883e83e7b689ddff3cafb595f7b711f6a065886b46a96a7fef874e7"},
+    {file = "debugpy-1.6.0-cp39-cp39-win32.whl", hash = "sha256:72bcfa97f3afa0064afc77ab811f48ad4a06ac330f290b675082c24437730366"},
+    {file = "debugpy-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:30abefefd2ff5a5481162d613cb70e60e2fa80a5eb4c994717c0f008ed25d2e1"},
+    {file = "debugpy-1.6.0-py2.py3-none-any.whl", hash = "sha256:4de7777842da7e08652f2776c552070bbdd758557fdec73a15d7be0e4aab95ce"},
+    {file = "debugpy-1.6.0.zip", hash = "sha256:7b79c40852991f7b6c3ea65845ed0f5f6b731c37f4f9ad9c61e2ab4bd48a9275"},
+]
+decorator = [
+    {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
+    {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
+]
+entrypoints = [
+    {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"},
+    {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"},
+]
+executing = [
+    {file = "executing-0.8.3-py2.py3-none-any.whl", hash = "sha256:d1eef132db1b83649a3905ca6dd8897f71ac6f8cac79a7e58a1a09cf137546c9"},
+    {file = "executing-0.8.3.tar.gz", hash = "sha256:c6554e21c6b060590a6d3be4b82fb78f8f0194d809de5ea7df1c093763311501"},
 ]
 flask = [
-    {file = "Flask-1.1.4-py2.py3-none-any.whl", hash = "sha256:c34f04500f2cbbea882b1acb02002ad6fe6b7ffa64a6164577995657f50aed22"},
-    {file = "Flask-1.1.4.tar.gz", hash = "sha256:0fbeb6180d383a9186d0d6ed954e0042ad9f18e0e8de088b2b419d526927d196"},
+    {file = "Flask-2.1.1-py3-none-any.whl", hash = "sha256:8a4cf32d904cf5621db9f0c9fbcd7efabf3003f22a04e4d0ce790c7137ec5264"},
+    {file = "Flask-2.1.1.tar.gz", hash = "sha256:a8c9bd3e558ec99646d177a9739c41df1ded0629480b4c8d2975412f3c9519c8"},
 ]
 future-fstrings = [
     {file = "future_fstrings-1.2.0-py2.py3-none-any.whl", hash = "sha256:90e49598b553d8746c4dc7d9442e0359d038c3039d802c91c0a55505da318c63"},
@@ -451,21 +979,45 @@ idna = [
     {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
     {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
 ]
+importlib-metadata = [
+    {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"},
+    {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"},
+]
 inflection = [
     {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"},
     {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"},
 ]
+ipykernel = [
+    {file = "ipykernel-6.13.0-py3-none-any.whl", hash = "sha256:2b0987af43c0d4b62cecb13c592755f599f96f29aafe36c01731aaa96df30d39"},
+    {file = "ipykernel-6.13.0.tar.gz", hash = "sha256:0e28273e290858393e86e152b104e5506a79c13d25b951ac6eca220051b4be60"},
+]
+ipython = [
+    {file = "ipython-8.2.0-py3-none-any.whl", hash = "sha256:1b672bfd7a48d87ab203d9af8727a3b0174a4566b4091e9447c22fb63ea32857"},
+    {file = "ipython-8.2.0.tar.gz", hash = "sha256:70e5eb132cac594a34b5f799bd252589009905f05104728aea6a403ec2519dc1"},
+]
 itsdangerous = [
-    {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"},
-    {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"},
+    {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-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"},
-    {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"},
+    {file = "Jinja2-3.1.1-py3-none-any.whl", hash = "sha256:539835f51a74a69f41b848a9645dbdc35b4f20a3b601e2d9a7e22947b15ff119"},
+    {file = "Jinja2-3.1.1.tar.gz", hash = "sha256:640bed4bb501cbd17194b3cace1dc2126f5b619cf068a726b98192a0fde74ae9"},
 ]
 jsonschema = [
-    {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"},
-    {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"},
+    {file = "jsonschema-4.4.0-py3-none-any.whl", hash = "sha256:77281a1f71684953ee8b3d488371b162419767973789272434bbc3f29d9c8823"},
+    {file = "jsonschema-4.4.0.tar.gz", hash = "sha256:636694eb41b3535ed608fe04129f26542b59ed99808b4f688aa32dcf55317a83"},
+]
+jupyter-client = [
+    {file = "jupyter_client-7.2.2-py3-none-any.whl", hash = "sha256:44045448eadc12493d819d965eb1dc9d10d1927698adbb9b14eb9a3a4a45ba53"},
+    {file = "jupyter_client-7.2.2.tar.gz", hash = "sha256:8fdbad344a8baa6a413d86d25bbf87ce21cb2b4aa5a8e0413863b9754eb8eb8a"},
+]
+jupyter-core = [
+    {file = "jupyter_core-4.9.2-py3-none-any.whl", hash = "sha256:f875e4d27e202590311d468fa55f90c575f201490bd0c18acabe4e318db4a46d"},
+    {file = "jupyter_core-4.9.2.tar.gz", hash = "sha256:d69baeb9ffb128b8cd2657fcf2703f89c769d1673c851812119e3a2a0e93ad9a"},
 ]
 lxml = [
     {file = "lxml-4.8.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:e1ab2fac607842ac36864e358c42feb0960ae62c34aa4caaf12ada0a1fb5d99b"},
@@ -531,80 +1083,63 @@ lxml = [
     {file = "lxml-4.8.0.tar.gz", hash = "sha256:f63f62fc60e6228a4ca9abae28228f35e1bd3ce675013d1dfb828688d50c6e23"},
 ]
 markupsafe = [
-    {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"},
-    {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
+    {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.3.tar.gz", hash = "sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee"},
+    {file = "matplotlib_inline-0.1.3-py3-none-any.whl", hash = "sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c"},
 ]
 more-itertools = [
     {file = "more-itertools-8.12.0.tar.gz", hash = "sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"},
     {file = "more_itertools-8.12.0-py3-none-any.whl", hash = "sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b"},
 ]
+nest-asyncio = [
+    {file = "nest_asyncio-1.5.5-py3-none-any.whl", hash = "sha256:b98e3ec1b246135e4642eceffa5a6c23a3ab12c82ff816a92c612d68205813b2"},
+    {file = "nest_asyncio-1.5.5.tar.gz", hash = "sha256:e442291cd942698be619823a17a86a5759eabe1f8613084790de189fe9e16d65"},
+]
+networkx = [
+    {file = "networkx-2.8-py3-none-any.whl", hash = "sha256:1a1e8fe052cc1b4e0339b998f6795099562a264a13a5af7a32cad45ab9d4e126"},
+    {file = "networkx-2.8.tar.gz", hash = "sha256:4a52cf66aed221955420e11b3e2e05ca44196b4829aab9576d4d439212b0a14f"},
+]
 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"},
@@ -613,83 +1148,224 @@ 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-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
     {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
 ]
+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.29-py3-none-any.whl", hash = "sha256:62291dad495e665fca0bda814e342c69952086afb0f4094d0893d357e5c78752"},
+    {file = "prompt_toolkit-3.0.29.tar.gz", hash = "sha256:bd640f60e8cecd74f0dc249713d433ace2ddc62b65ee07f96d358e0b152b6ea7"},
+]
+psutil = [
+    {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:55ce319452e3d139e25d6c3f85a1acf12d1607ddedea5e35fb47a552c051161b"},
+    {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7336292a13a80eb93c21f36bde4328aa748a04b68c13d01dfddd67fc13fd0618"},
+    {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2"},
+    {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:7641300de73e4909e5d148e90cc3142fb890079e1525a840cf0dfd39195239fd"},
+    {file = "psutil-5.9.0-cp27-none-win32.whl", hash = "sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3"},
+    {file = "psutil-5.9.0-cp27-none-win_amd64.whl", hash = "sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c"},
+    {file = "psutil-5.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90a58b9fcae2dbfe4ba852b57bd4a1dded6b990a33d6428c7614b7d48eccb492"},
+    {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3"},
+    {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:742c34fff804f34f62659279ed5c5b723bb0195e9d7bd9907591de9f8f6558e2"},
+    {file = "psutil-5.9.0-cp310-cp310-win32.whl", hash = "sha256:8293942e4ce0c5689821f65ce6522ce4786d02af57f13c0195b40e1edb1db61d"},
+    {file = "psutil-5.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b"},
+    {file = "psutil-5.9.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e9805fed4f2a81de98ae5fe38b75a74c6e6ad2df8a5c479594c7629a1fe35f56"},
+    {file = "psutil-5.9.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c51f1af02334e4b516ec221ee26b8fdf105032418ca5a5ab9737e8c87dafe203"},
+    {file = "psutil-5.9.0-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32acf55cb9a8cbfb29167cd005951df81b567099295291bcfd1027365b36591d"},
+    {file = "psutil-5.9.0-cp36-cp36m-win32.whl", hash = "sha256:e5c783d0b1ad6ca8a5d3e7b680468c9c926b804be83a3a8e95141b05c39c9f64"},
+    {file = "psutil-5.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:d62a2796e08dd024b8179bd441cb714e0f81226c352c802fca0fd3f89eeacd94"},
+    {file = "psutil-5.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0"},
+    {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7779be4025c540d1d65a2de3f30caeacc49ae7a2152108adeaf42c7534a115ce"},
+    {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072664401ae6e7c1bfb878c65d7282d4b4391f1bc9a56d5e03b5a490403271b5"},
+    {file = "psutil-5.9.0-cp37-cp37m-win32.whl", hash = "sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9"},
+    {file = "psutil-5.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4"},
+    {file = "psutil-5.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2"},
+    {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d"},
+    {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a"},
+    {file = "psutil-5.9.0-cp38-cp38-win32.whl", hash = "sha256:76cebf84aac1d6da5b63df11fe0d377b46b7b500d892284068bacccf12f20666"},
+    {file = "psutil-5.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841"},
+    {file = "psutil-5.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:539e429da49c5d27d5a58e3563886057f8fc3868a5547b4f1876d9c0f007bccf"},
+    {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58c7d923dc209225600aec73aa2c4ae8ea33b1ab31bc11ef8a5933b027476f07"},
+    {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d"},
+    {file = "psutil-5.9.0-cp39-cp39-win32.whl", hash = "sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845"},
+    {file = "psutil-5.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:7d190ee2eaef7831163f254dc58f6d2e2a22e27382b936aab51c835fc080c3d3"},
+    {file = "psutil-5.9.0.tar.gz", hash = "sha256:869842dbd66bb80c3217158e629d6fceaecc3a3166d3d1faee515b05dd26ca25"},
+]
+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.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"},
+    {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"},
+]
 pyparsing = [
-    {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
-    {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
+    {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"},
+    {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"},
 ]
 pyrsistent = [
-    {file = "pyrsistent-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"},
-    {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d"},
-    {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2"},
-    {file = "pyrsistent-0.18.0-cp36-cp36m-win32.whl", hash = "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1"},
-    {file = "pyrsistent-0.18.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7"},
-    {file = "pyrsistent-0.18.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396"},
-    {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710"},
-    {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35"},
-    {file = "pyrsistent-0.18.0-cp37-cp37m-win32.whl", hash = "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f"},
-    {file = "pyrsistent-0.18.0-cp37-cp37m-win_amd64.whl", hash = "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2"},
-    {file = "pyrsistent-0.18.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427"},
-    {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef"},
-    {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c"},
-    {file = "pyrsistent-0.18.0-cp38-cp38-win32.whl", hash = "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78"},
-    {file = "pyrsistent-0.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b"},
-    {file = "pyrsistent-0.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4"},
-    {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680"},
-    {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426"},
-    {file = "pyrsistent-0.18.0-cp39-cp39-win32.whl", hash = "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b"},
-    {file = "pyrsistent-0.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea"},
-    {file = "pyrsistent-0.18.0.tar.gz", hash = "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b"},
+    {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-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"},
     {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"},
 ]
+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"},
+]
+pywin32 = [
+    {file = "pywin32-303-cp310-cp310-win32.whl", hash = "sha256:6fed4af057039f309263fd3285d7b8042d41507343cd5fa781d98fcc5b90e8bb"},
+    {file = "pywin32-303-cp310-cp310-win_amd64.whl", hash = "sha256:51cb52c5ec6709f96c3f26e7795b0bf169ee0d8395b2c1d7eb2c029a5008ed51"},
+    {file = "pywin32-303-cp311-cp311-win32.whl", hash = "sha256:d9b5d87ca944eb3aa4cd45516203ead4b37ab06b8b777c54aedc35975dec0dee"},
+    {file = "pywin32-303-cp311-cp311-win_amd64.whl", hash = "sha256:fcf44032f5b14fcda86028cdf49b6ebdaea091230eb0a757282aa656e4732439"},
+    {file = "pywin32-303-cp36-cp36m-win32.whl", hash = "sha256:aad484d52ec58008ca36bd4ad14a71d7dd0a99db1a4ca71072213f63bf49c7d9"},
+    {file = "pywin32-303-cp36-cp36m-win_amd64.whl", hash = "sha256:2a09632916b6bb231ba49983fe989f2f625cea237219530e81a69239cd0c4559"},
+    {file = "pywin32-303-cp37-cp37m-win32.whl", hash = "sha256:b1675d82bcf6dbc96363fca747bac8bff6f6e4a447a4287ac652aa4b9adc796e"},
+    {file = "pywin32-303-cp37-cp37m-win_amd64.whl", hash = "sha256:c268040769b48a13367221fced6d4232ed52f044ffafeda247bd9d2c6bdc29ca"},
+    {file = "pywin32-303-cp38-cp38-win32.whl", hash = "sha256:5f9ec054f5a46a0f4dfd72af2ce1372f3d5a6e4052af20b858aa7df2df7d355b"},
+    {file = "pywin32-303-cp38-cp38-win_amd64.whl", hash = "sha256:793bf74fce164bcffd9d57bb13c2c15d56e43c9542a7b9687b4fccf8f8a41aba"},
+    {file = "pywin32-303-cp39-cp39-win32.whl", hash = "sha256:7d3271c98434617a11921c5ccf74615794d97b079e22ed7773790822735cc352"},
+    {file = "pywin32-303-cp39-cp39-win_amd64.whl", hash = "sha256:79cbb862c11b9af19bcb682891c1b91942ec2ff7de8151e2aea2e175899cda34"},
+]
 pyyaml = [
-    {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"},
-    {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"},
-    {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"},
-    {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"},
-    {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"},
-    {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"},
-    {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"},
-    {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"},
-    {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"},
-    {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"},
-    {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"},
-    {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"},
-    {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"},
-    {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"},
-    {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"},
-    {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"},
-    {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"},
-    {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"},
-    {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"},
-    {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"},
-    {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"},
-    {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"},
-    {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"},
-    {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"},
-    {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"},
-    {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"},
-    {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"},
-    {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"},
-    {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"},
+    {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-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-22.3.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:6b217b8f9dfb6628f74b94bdaf9f7408708cb02167d644edca33f38746ca12dd"},
+    {file = "pyzmq-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2841997a0d85b998cbafecb4183caf51fd19c4357075dfd33eb7efea57e4c149"},
+    {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f89468059ebc519a7acde1ee50b779019535db8dcf9b8c162ef669257fef7a93"},
+    {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea12133df25e3a6918718fbb9a510c6ee5d3fdd5a346320421aac3882f4feeea"},
+    {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c532fd68b93998aab92356be280deec5de8f8fe59cd28763d2cc8a58747b7f"},
+    {file = "pyzmq-22.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f907c7359ce8bf7f7e63c82f75ad0223384105f5126f313400b7e8004d9b33c3"},
+    {file = "pyzmq-22.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:902319cfe23366595d3fa769b5b751e6ee6750a0a64c5d9f757d624b2ac3519e"},
+    {file = "pyzmq-22.3.0-cp310-cp310-win32.whl", hash = "sha256:67db33bea0a29d03e6eeec55a8190e033318cee3cbc732ba8fd939617cbf762d"},
+    {file = "pyzmq-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:7661fc1d5cb73481cf710a1418a4e1e301ed7d5d924f91c67ba84b2a1b89defd"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79244b9e97948eaf38695f4b8e6fc63b14b78cc37f403c6642ba555517ac1268"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab888624ed68930442a3f3b0b921ad7439c51ba122dbc8c386e6487a658e4a4e"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18cd854b423fce44951c3a4d3e686bac8f1243d954f579e120a1714096637cc0"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:de8df0684398bd74ad160afdc2a118ca28384ac6f5e234eb0508858d8d2d9364"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:62bcade20813796c426409a3e7423862d50ff0639f5a2a95be4b85b09a618666"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:ea5a79e808baef98c48c884effce05c31a0698c1057de8fc1c688891043c1ce1"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-win32.whl", hash = "sha256:3c1895c95be92600233e476fe283f042e71cf8f0b938aabf21b7aafa62a8dac9"},
+    {file = "pyzmq-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:851977788b9caa8ed011f5f643d3ee8653af02c5fc723fa350db5125abf2be7b"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b4ebed0977f92320f6686c96e9e8dd29eed199eb8d066936bac991afc37cbb70"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42abddebe2c6a35180ca549fadc7228d23c1e1f76167c5ebc8a936b5804ea2df"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1e41b32d6f7f9c26bc731a8b529ff592f31fc8b6ef2be9fa74abd05c8a342d7"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:be4e0f229cf3a71f9ecd633566bd6f80d9fa6afaaff5489492be63fe459ef98c"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08c4e315a76ef26eb833511ebf3fa87d182152adf43dedee8d79f998a2162a0b"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:badb868fff14cfd0e200eaa845887b1011146a7d26d579aaa7f966c203736b92"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-win32.whl", hash = "sha256:7c58f598d9fcc52772b89a92d72bf8829c12d09746a6d2c724c5b30076c1f11d"},
+    {file = "pyzmq-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2b97502c16a5ec611cd52410bdfaab264997c627a46b0f98d3f666227fd1ea2d"},
+    {file = "pyzmq-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d728b08448e5ac3e4d886b165385a262883c34b84a7fe1166277fe675e1c197a"},
+    {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:480b9931bfb08bf8b094edd4836271d4d6b44150da051547d8c7113bf947a8b0"},
+    {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7dc09198e4073e6015d9a8ea093fc348d4e59de49382476940c3dd9ae156fba8"},
+    {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ca6cd58f62a2751728016d40082008d3b3412a7f28ddfb4a2f0d3c130f69e74"},
+    {file = "pyzmq-22.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:468bd59a588e276961a918a3060948ae68f6ff5a7fa10bb2f9160c18fe341067"},
+    {file = "pyzmq-22.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c88fa7410e9fc471e0858638f403739ee869924dd8e4ae26748496466e27ac59"},
+    {file = "pyzmq-22.3.0-cp38-cp38-win32.whl", hash = "sha256:c0f84360dcca3481e8674393bdf931f9f10470988f87311b19d23cda869bb6b7"},
+    {file = "pyzmq-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:f762442bab706fd874064ca218b33a1d8e40d4938e96c24dafd9b12e28017f45"},
+    {file = "pyzmq-22.3.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:954e73c9cd4d6ae319f1c936ad159072b6d356a92dcbbabfd6e6204b9a79d356"},
+    {file = "pyzmq-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f43b4a2e6218371dd4f41e547bd919ceeb6ebf4abf31a7a0669cd11cd91ea973"},
+    {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:acebba1a23fb9d72b42471c3771b6f2f18dcd46df77482612054bd45c07dfa36"},
+    {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cf98fd7a6c8aaa08dbc699ffae33fd71175696d78028281bc7b832b26f00ca57"},
+    {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d072f7dfbdb184f0786d63bda26e8a0882041b1e393fbe98940395f7fab4c5e2"},
+    {file = "pyzmq-22.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:53f4fd13976789ffafedd4d46f954c7bb01146121812b72b4ddca286034df966"},
+    {file = "pyzmq-22.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1b5d457acbadcf8b27561deeaa386b0217f47626b29672fa7bd31deb6e91e1b"},
+    {file = "pyzmq-22.3.0-cp39-cp39-win32.whl", hash = "sha256:e6a02cf7271ee94674a44f4e62aa061d2d049001c844657740e156596298b70b"},
+    {file = "pyzmq-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d3dcb5548ead4f1123851a5ced467791f6986d68c656bc63bfff1bf9e36671e2"},
+    {file = "pyzmq-22.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3a4c9886d61d386b2b493377d980f502186cd71d501fffdba52bd2a0880cef4f"},
+    {file = "pyzmq-22.3.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:80e043a89c6cadefd3a0712f8a1322038e819ebe9dbac7eca3bce1721bcb63bf"},
+    {file = "pyzmq-22.3.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1621e7a2af72cced1f6ec8ca8ca91d0f76ac236ab2e8828ac8fe909512d566cb"},
+    {file = "pyzmq-22.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d6157793719de168b199194f6b6173f0ccd3bf3499e6870fac17086072e39115"},
+    {file = "pyzmq-22.3.0.tar.gz", hash = "sha256:8eddc033e716f8c91c6a2112f0a8ebc5e00532b4a6ae1eb0ccc48e027f9c671c"},
 ]
 requests = [
-    {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
-    {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
+    {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
+    {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
 ]
 restrictedpython = [
     {file = "RestrictedPython-5.0-py2.py3-none-any.whl", hash = "sha256:9bd69505147b0ff8c68f4ff5a275975a3ab66fc43cbf3b61a195650ed767cd4e"},
@@ -699,13 +1375,64 @@ six = [
     {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
     {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
 ]
+stack-data = [
+    {file = "stack_data-0.2.0-py3-none-any.whl", hash = "sha256:999762f9c3132308789affa03e9271bbbe947bf78311851f4d485d8402ed858e"},
+    {file = "stack_data-0.2.0.tar.gz", hash = "sha256:45692d41bd633a9503a5195552df22b583caf16f0b27c4e58c98d88c8b648e12"},
+]
 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"},
 ]
+tornado = [
+    {file = "tornado-6.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32"},
+    {file = "tornado-6.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c"},
+    {file = "tornado-6.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05"},
+    {file = "tornado-6.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910"},
+    {file = "tornado-6.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b"},
+    {file = "tornado-6.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675"},
+    {file = "tornado-6.1-cp35-cp35m-win32.whl", hash = "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5"},
+    {file = "tornado-6.1-cp35-cp35m-win_amd64.whl", hash = "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68"},
+    {file = "tornado-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb"},
+    {file = "tornado-6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c"},
+    {file = "tornado-6.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921"},
+    {file = "tornado-6.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558"},
+    {file = "tornado-6.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c"},
+    {file = "tornado-6.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085"},
+    {file = "tornado-6.1-cp36-cp36m-win32.whl", hash = "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575"},
+    {file = "tornado-6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795"},
+    {file = "tornado-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f"},
+    {file = "tornado-6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102"},
+    {file = "tornado-6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4"},
+    {file = "tornado-6.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd"},
+    {file = "tornado-6.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01"},
+    {file = "tornado-6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d"},
+    {file = "tornado-6.1-cp37-cp37m-win32.whl", hash = "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df"},
+    {file = "tornado-6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37"},
+    {file = "tornado-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95"},
+    {file = "tornado-6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a"},
+    {file = "tornado-6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"},
+    {file = "tornado-6.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288"},
+    {file = "tornado-6.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f"},
+    {file = "tornado-6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6"},
+    {file = "tornado-6.1-cp38-cp38-win32.whl", hash = "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326"},
+    {file = "tornado-6.1-cp38-cp38-win_amd64.whl", hash = "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c"},
+    {file = "tornado-6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5"},
+    {file = "tornado-6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe"},
+    {file = "tornado-6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea"},
+    {file = "tornado-6.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2"},
+    {file = "tornado-6.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0"},
+    {file = "tornado-6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd"},
+    {file = "tornado-6.1-cp39-cp39-win32.whl", hash = "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c"},
+    {file = "tornado-6.1-cp39-cp39-win_amd64.whl", hash = "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4"},
+    {file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"},
+]
+traitlets = [
+    {file = "traitlets-5.1.1-py3-none-any.whl", hash = "sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033"},
+    {file = "traitlets-5.1.1.tar.gz", hash = "sha256:059f456c5a7c1c82b98c2e8c799f39c9b8128f6d0d46941ee118daace9eb70c7"},
+]
 urllib3 = [
-    {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"},
-    {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"},
+    {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"},
+    {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"},
 ]
 uwsgi = [
     {file = "uwsgi-2.0.20.tar.gz", hash = "sha256:88ab9867d8973d8ae84719cf233b7dafc54326fcaec89683c3f9f77c002cdff9"},
@@ -715,6 +1442,17 @@ wcwidth = [
     {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
 ]
 werkzeug = [
-    {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
-    {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
+    {file = "Werkzeug-2.1.1-py3-none-any.whl", hash = "sha256:3c5493ece8268fecdcdc9c0b112211acd006354723b280d643ec732b6d4063d6"},
+    {file = "Werkzeug-2.1.1.tar.gz", hash = "sha256:f8e89a20aeabbe8a893c24a461d3ee5dad2123b05cc6abd73ceed01d39c3ae74"},
+]
+z3-solver = [
+    {file = "z3-solver-4.8.15.0.tar.gz", hash = "sha256:4f1612fcca67eba92bb1752182e6e659d0607ae5d88d8db99a07451ed7f8ff49"},
+    {file = "z3_solver-4.8.15.0-py2.py3-none-macosx_10_16_x86_64.whl", hash = "sha256:f260b46db33a11d09d2a4bc720f418ca8059b9b59a392cc9e0d985e3dd4dc821"},
+    {file = "z3_solver-4.8.15.0-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:e743cf7e4f553a56fb26851555d1a5f1cbbadffcce2fa812f7cc997814cbdfc0"},
+    {file = "z3_solver-4.8.15.0-py2.py3-none-win32.whl", hash = "sha256:9916cc09dbae7e3d69b1fe2ce193a3e8ac17172795b56a11456c9452239792c6"},
+    {file = "z3_solver-4.8.15.0-py2.py3-none-win_amd64.whl", hash = "sha256:3a7918ff81d3af833cfda07925e6b14b9c851e2794cf69fc7353baaf5ae3e031"},
+]
+zipp = [
+    {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"},
+    {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"},
 ]
diff --git a/pyproject.toml b/pyproject.toml
index 992fc4b79fa3b9eaa4606cc14a01bc1ee2cfb8f7..415df653a8ff9993988f14b5327045e333947883 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,18 +2,23 @@
 name = "mc_openapi"
 version = "0.1.0"
 description = "OpenAPI interface for the PIACERE DOML model checker."
-authors = ["Michele Chiari <michele.chiari@polimi.it>"]
+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.8"
+python = "^3.9"
 connexion = {extras = ["swagger-ui"], version = "^2.9.0"}
 uWSGI = "^2.0.20"
 pyecore = "^0.12.2"
+z3-solver = "^4.8.15"
+PyYAML = "^6.0"
+networkx = "^2.7.1"
 
 [tool.poetry.dev-dependencies]
 pytest = "^5.2"
 requests = "^2.26.0"
+ipykernel = "^6.12.1"
+prettyprinter = "^0.18.0"
 
 [build-system]
 requires = ["poetry-core>=1.0.0"]
diff --git a/tests/doml/nginx-openstack_v2_wrong.domlx b/tests/doml/nginx-openstack_v2_wrong.domlx
index 70276c9fa13a283a9ab06fd88adc2a5849d49bf3..8aaa96b565829b42c1cbdd53fc6ea514f9a1ce25 100644
--- a/tests/doml/nginx-openstack_v2_wrong.domlx
+++ b/tests/doml/nginx-openstack_v2_wrong.domlx
@@ -7,12 +7,10 @@
   </application>
   <infrastructure name="infra">
     <nodes xsi:type="infra:AutoScalingGroup" name="ag" deploymentNetwork="//@infrastructure/@networks.0">
-      <machineDefinition name="vm1" credentials="//@infrastructure/@credentials.0" group="//@infrastructure/@secGroups.0" generatedFrom="//@infrastructure/@generators.0">
-        <ifaces name="i1" endPoint="16.0.0.1" />
-      </machineDefinition>
+      <machineDefinition name="vm1" credentials="//@infrastructure/@credentials.0" group="//@infrastructure/@secGroups.0" generatedFrom="//@infrastructure/@generators.0" />
     </nodes>
     <networks name="net1" protocol="tcp/ip" addressRange="16.0.0.0/24" />
-    <secGroups name="sg" groupedNodes="//@infrastructure/@nodes.0/@machineDefinition" ifaces="//@infrastructure/@nodes.0/@machineDefinition/@ifaces.0">
+    <secGroups name="sg" groupedNodes="//@infrastructure/@nodes.0/@machineDefinition">
       <rules name="out_all" protocol="-1" fromPort="0" toPort="0">
         <addressRanges>0.0.0.0/0</addressRanges>
         <addressRanges>::/0</addressRanges>
diff --git a/tests/test_mc_openapi.py b/tests/test_mc_openapi.py
index ce51dce8c9a1dd953cba51414e8a5e2ba3129736..7536bfacb730732aa3203f3675a8b1a78e7a4552 100644
--- a/tests/test_mc_openapi.py
+++ b/tests/test_mc_openapi.py
@@ -1,10 +1,11 @@
 from mc_openapi import __version__
 import requests
-import json
+
 
 def test_version():
     assert __version__ == '0.1.0'
 
+
 def test_post_sat():
     with open("tests/doml/nginx-openstack_v2.domlx", "r") as f:
         doml = f.read()
@@ -15,6 +16,7 @@ def test_post_sat():
     assert payload["result"] is not None
     assert payload["result"] == "sat"
 
+
 def test_post_unsat():
     with open("tests/doml/nginx-openstack_v2_wrong.domlx", "r") as f:
         doml = f.read()