diff --git a/.buildinfo b/.buildinfo
new file mode 100644
index 000000000..0eded35cc
--- /dev/null
+++ b/.buildinfo
@@ -0,0 +1,4 @@
+# Sphinx build info version 1
+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
+config: 68064a1fcd0610eaf6d75c9ccc1687cd
+tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/.nojekyll b/.nojekyll
new file mode 100644
index 000000000..e69de29bb
diff --git a/_images/2021-05-09_10-32.jpg b/_images/2021-05-09_10-32.jpg
new file mode 100644
index 000000000..d16a02951
Binary files /dev/null and b/_images/2021-05-09_10-32.jpg differ
diff --git a/_images/2021-05-09_10-36.jpg b/_images/2021-05-09_10-36.jpg
new file mode 100644
index 000000000..db2876cb3
Binary files /dev/null and b/_images/2021-05-09_10-36.jpg differ
diff --git a/_images/2021-05-09_10-50.jpg b/_images/2021-05-09_10-50.jpg
new file mode 100644
index 000000000..cd12ca5d9
Binary files /dev/null and b/_images/2021-05-09_10-50.jpg differ
diff --git a/_images/2021-05-09_17-36.jpg b/_images/2021-05-09_17-36.jpg
new file mode 100644
index 000000000..b5581088b
Binary files /dev/null and b/_images/2021-05-09_17-36.jpg differ
diff --git a/_images/2021-05-09_17-38.jpg b/_images/2021-05-09_17-38.jpg
new file mode 100644
index 000000000..60c056e85
Binary files /dev/null and b/_images/2021-05-09_17-38.jpg differ
diff --git a/_images/2021-05-09_17-44.jpg b/_images/2021-05-09_17-44.jpg
new file mode 100644
index 000000000..83b414d0f
Binary files /dev/null and b/_images/2021-05-09_17-44.jpg differ
diff --git a/_images/2021-05-09_17-57.jpg b/_images/2021-05-09_17-57.jpg
new file mode 100644
index 000000000..b9dd0947e
Binary files /dev/null and b/_images/2021-05-09_17-57.jpg differ
diff --git a/_images/2021-05-09_21-21.jpg b/_images/2021-05-09_21-21.jpg
new file mode 100644
index 000000000..1b27de5f0
Binary files /dev/null and b/_images/2021-05-09_21-21.jpg differ
diff --git a/_images/2021-05-09_21-46.jpg b/_images/2021-05-09_21-46.jpg
new file mode 100644
index 000000000..903bd8e92
Binary files /dev/null and b/_images/2021-05-09_21-46.jpg differ
diff --git a/_images/2021-05-09_22-09.jpg b/_images/2021-05-09_22-09.jpg
new file mode 100644
index 000000000..5b3a1fcd2
Binary files /dev/null and b/_images/2021-05-09_22-09.jpg differ
diff --git a/_images/2021-05-09_22-39.jpg b/_images/2021-05-09_22-39.jpg
new file mode 100644
index 000000000..d02b6668f
Binary files /dev/null and b/_images/2021-05-09_22-39.jpg differ
diff --git a/_images/2021-05-10_22-35.jpg b/_images/2021-05-10_22-35.jpg
new file mode 100644
index 000000000..9c3650585
Binary files /dev/null and b/_images/2021-05-10_22-35.jpg differ
diff --git a/_images/2021-05-10_22-59.jpg b/_images/2021-05-10_22-59.jpg
new file mode 100644
index 000000000..ca184bc6c
Binary files /dev/null and b/_images/2021-05-10_22-59.jpg differ
diff --git a/_images/2021-05-12_18-18.jpg b/_images/2021-05-12_18-18.jpg
new file mode 100644
index 000000000..5ee9dac5a
Binary files /dev/null and b/_images/2021-05-12_18-18.jpg differ
diff --git a/_images/2021-05-12_18-51.jpg b/_images/2021-05-12_18-51.jpg
new file mode 100644
index 000000000..afb248858
Binary files /dev/null and b/_images/2021-05-12_18-51.jpg differ
diff --git a/_images/2021-05-12_19-12.jpg b/_images/2021-05-12_19-12.jpg
new file mode 100644
index 000000000..cda80cf9d
Binary files /dev/null and b/_images/2021-05-12_19-12.jpg differ
diff --git a/_images/2021-05-12_20-06.jpg b/_images/2021-05-12_20-06.jpg
new file mode 100644
index 000000000..b34855edf
Binary files /dev/null and b/_images/2021-05-12_20-06.jpg differ
diff --git a/_images/2021-05-12_20-10.jpg b/_images/2021-05-12_20-10.jpg
new file mode 100644
index 000000000..04d6402f1
Binary files /dev/null and b/_images/2021-05-12_20-10.jpg differ
diff --git a/_images/2021-05-12_21-03.jpg b/_images/2021-05-12_21-03.jpg
new file mode 100644
index 000000000..384e2ba0d
Binary files /dev/null and b/_images/2021-05-12_21-03.jpg differ
diff --git a/_images/2021-05-13_20-46.jpg b/_images/2021-05-13_20-46.jpg
new file mode 100644
index 000000000..d3448b877
Binary files /dev/null and b/_images/2021-05-13_20-46.jpg differ
diff --git a/_images/2021-05-17_11-50.jpg b/_images/2021-05-17_11-50.jpg
new file mode 100644
index 000000000..3fb35b9c0
Binary files /dev/null and b/_images/2021-05-17_11-50.jpg differ
diff --git a/_images/crosslayer_intro.jpg b/_images/crosslayer_intro.jpg
new file mode 100644
index 000000000..41349a91a
Binary files /dev/null and b/_images/crosslayer_intro.jpg differ
diff --git a/_images/examples_11_Complexity_Assessment_2_1.svg b/_images/examples_11_Complexity_Assessment_2_1.svg
new file mode 100644
index 000000000..27079911d
--- /dev/null
+++ b/_images/examples_11_Complexity_Assessment_2_1.svg
@@ -0,0 +1,39 @@
+
+
+
+180
+objects
+
+
+31%
+
+16%
+
+27%
+
+27%
+
+18
+diagrams
+
+
+39%
+
+22%
+
+28%
+
+11%
+
+
+
+Operational Analysis
+
+System Analysis
+
+Logical Architecture
+
+Physical Architecture
+
+
+
\ No newline at end of file
diff --git a/_images/harrys_wand.png b/_images/harrys_wand.png
new file mode 100644
index 000000000..effece64b
Binary files /dev/null and b/_images/harrys_wand.png differ
diff --git a/_images/waypoints.png b/_images/waypoints.png
new file mode 100644
index 000000000..fd021c986
Binary files /dev/null and b/_images/waypoints.png differ
diff --git a/_sources/code/capellambse.aird.rst.txt b/_sources/code/capellambse.aird.rst.txt
new file mode 100644
index 000000000..1f1585a4a
--- /dev/null
+++ b/_sources/code/capellambse.aird.rst.txt
@@ -0,0 +1,7 @@
+capellambse.aird package
+========================
+
+.. automodule:: capellambse.aird
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.diagram.rst.txt b/_sources/code/capellambse.diagram.rst.txt
new file mode 100644
index 000000000..bf6ec497b
--- /dev/null
+++ b/_sources/code/capellambse.diagram.rst.txt
@@ -0,0 +1,18 @@
+capellambse.diagram package
+===========================
+
+.. automodule:: capellambse.diagram
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.diagram.capstyle module
+-----------------------------------
+
+.. automodule:: capellambse.diagram.capstyle
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.extensions.metrics.rst.txt b/_sources/code/capellambse.extensions.metrics.rst.txt
new file mode 100644
index 000000000..a81d6a574
--- /dev/null
+++ b/_sources/code/capellambse.extensions.metrics.rst.txt
@@ -0,0 +1,26 @@
+capellambse.extensions.metrics package
+======================================
+
+.. automodule:: capellambse.extensions.metrics
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.extensions.metrics.collector module
+-----------------------------------------------
+
+.. automodule:: capellambse.extensions.metrics.collector
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.extensions.metrics.composer module
+----------------------------------------------
+
+.. automodule:: capellambse.extensions.metrics.composer
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.extensions.reqif.rst.txt b/_sources/code/capellambse.extensions.reqif.rst.txt
new file mode 100644
index 000000000..f9b4452e8
--- /dev/null
+++ b/_sources/code/capellambse.extensions.reqif.rst.txt
@@ -0,0 +1,18 @@
+capellambse.extensions.reqif package
+====================================
+
+.. automodule:: capellambse.extensions.reqif
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.extensions.reqif.exporter module
+--------------------------------------------
+
+.. automodule:: capellambse.extensions.reqif.exporter
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.extensions.rst.txt b/_sources/code/capellambse.extensions.rst.txt
new file mode 100644
index 000000000..3f574cde4
--- /dev/null
+++ b/_sources/code/capellambse.extensions.rst.txt
@@ -0,0 +1,35 @@
+capellambse.extensions package
+==============================
+
+.. automodule:: capellambse.extensions
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Subpackages
+-----------
+
+.. toctree::
+ :maxdepth: 4
+
+ capellambse.extensions.metrics
+ capellambse.extensions.reqif
+
+Submodules
+----------
+
+capellambse.extensions.filtering module
+---------------------------------------
+
+.. automodule:: capellambse.extensions.filtering
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.extensions.pvmt module
+----------------------------------
+
+.. automodule:: capellambse.extensions.pvmt
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.filehandler.rst.txt b/_sources/code/capellambse.filehandler.rst.txt
new file mode 100644
index 000000000..695066a24
--- /dev/null
+++ b/_sources/code/capellambse.filehandler.rst.txt
@@ -0,0 +1,74 @@
+capellambse.filehandler package
+===============================
+
+.. automodule:: capellambse.filehandler
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.filehandler.abc module
+----------------------------------
+
+.. automodule:: capellambse.filehandler.abc
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.filehandler.git module
+----------------------------------
+
+.. automodule:: capellambse.filehandler.git
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.filehandler.git\_askpass module
+-------------------------------------------
+
+.. automodule:: capellambse.filehandler.git_askpass
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.filehandler.gitlab\_artifacts module
+------------------------------------------------
+
+.. automodule:: capellambse.filehandler.gitlab_artifacts
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.filehandler.http module
+-----------------------------------
+
+.. automodule:: capellambse.filehandler.http
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.filehandler.local module
+------------------------------------
+
+.. automodule:: capellambse.filehandler.local
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.filehandler.memory module
+-------------------------------------
+
+.. automodule:: capellambse.filehandler.memory
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.filehandler.zip module
+----------------------------------
+
+.. automodule:: capellambse.filehandler.zip
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.loader.rst.txt b/_sources/code/capellambse.loader.rst.txt
new file mode 100644
index 000000000..299b73166
--- /dev/null
+++ b/_sources/code/capellambse.loader.rst.txt
@@ -0,0 +1,50 @@
+capellambse.loader package
+==========================
+
+.. automodule:: capellambse.loader
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.loader.core module
+------------------------------
+
+.. automodule:: capellambse.loader.core
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.loader.exs module
+-----------------------------
+
+.. automodule:: capellambse.loader.exs
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.loader.filehandler module
+-------------------------------------
+
+.. automodule:: capellambse.loader.filehandler
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.loader.modelinfo module
+-----------------------------------
+
+.. automodule:: capellambse.loader.modelinfo
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.loader.xmltools module
+----------------------------------
+
+.. automodule:: capellambse.loader.xmltools
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.model.common.rst.txt b/_sources/code/capellambse.model.common.rst.txt
new file mode 100644
index 000000000..a6f7b8311
--- /dev/null
+++ b/_sources/code/capellambse.model.common.rst.txt
@@ -0,0 +1,34 @@
+capellambse.model.common package
+================================
+
+.. automodule:: capellambse.model.common
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.model.common.accessors module
+-----------------------------------------
+
+.. automodule:: capellambse.model.common.accessors
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.common.element module
+---------------------------------------
+
+.. automodule:: capellambse.model.common.element
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.common.properties module
+------------------------------------------
+
+.. automodule:: capellambse.model.common.properties
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.model.crosslayer.information.rst.txt b/_sources/code/capellambse.model.crosslayer.information.rst.txt
new file mode 100644
index 000000000..30846a88a
--- /dev/null
+++ b/_sources/code/capellambse.model.crosslayer.information.rst.txt
@@ -0,0 +1,26 @@
+capellambse.model.crosslayer.information package
+================================================
+
+.. automodule:: capellambse.model.crosslayer.information
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.model.crosslayer.information.datatype module
+--------------------------------------------------------
+
+.. automodule:: capellambse.model.crosslayer.information.datatype
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.crosslayer.information.datavalue module
+---------------------------------------------------------
+
+.. automodule:: capellambse.model.crosslayer.information.datavalue
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.model.crosslayer.rst.txt b/_sources/code/capellambse.model.crosslayer.rst.txt
new file mode 100644
index 000000000..20a2f2367
--- /dev/null
+++ b/_sources/code/capellambse.model.crosslayer.rst.txt
@@ -0,0 +1,66 @@
+capellambse.model.crosslayer package
+====================================
+
+.. automodule:: capellambse.model.crosslayer
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Subpackages
+-----------
+
+.. toctree::
+ :maxdepth: 4
+
+ capellambse.model.crosslayer.information
+
+Submodules
+----------
+
+capellambse.model.crosslayer.capellacommon module
+-------------------------------------------------
+
+.. automodule:: capellambse.model.crosslayer.capellacommon
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.crosslayer.capellacore module
+-----------------------------------------------
+
+.. automodule:: capellambse.model.crosslayer.capellacore
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.crosslayer.cs module
+--------------------------------------
+
+.. automodule:: capellambse.model.crosslayer.cs
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.crosslayer.fa module
+--------------------------------------
+
+.. automodule:: capellambse.model.crosslayer.fa
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.crosslayer.interaction module
+-----------------------------------------------
+
+.. automodule:: capellambse.model.crosslayer.interaction
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.crosslayer.modellingcore module
+-------------------------------------------------
+
+.. automodule:: capellambse.model.crosslayer.modellingcore
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.model.layers.rst.txt b/_sources/code/capellambse.model.layers.rst.txt
new file mode 100644
index 000000000..f07ab131d
--- /dev/null
+++ b/_sources/code/capellambse.model.layers.rst.txt
@@ -0,0 +1,42 @@
+capellambse.model.layers package
+================================
+
+.. automodule:: capellambse.model.layers
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.model.layers.ctx module
+-----------------------------------
+
+.. automodule:: capellambse.model.layers.ctx
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.layers.la module
+----------------------------------
+
+.. automodule:: capellambse.model.layers.la
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.layers.oa module
+----------------------------------
+
+.. automodule:: capellambse.model.layers.oa
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.layers.pa module
+----------------------------------
+
+.. automodule:: capellambse.model.layers.pa
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.model.rst.txt b/_sources/code/capellambse.model.rst.txt
new file mode 100644
index 000000000..ccce537f1
--- /dev/null
+++ b/_sources/code/capellambse.model.rst.txt
@@ -0,0 +1,36 @@
+capellambse.model package
+=========================
+
+.. automodule:: capellambse.model
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Subpackages
+-----------
+
+.. toctree::
+ :maxdepth: 4
+
+ capellambse.model.common
+ capellambse.model.crosslayer
+ capellambse.model.layers
+
+Submodules
+----------
+
+capellambse.model.diagram module
+--------------------------------
+
+.. automodule:: capellambse.model.diagram
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.model.modeltypes module
+-----------------------------------
+
+.. automodule:: capellambse.model.modeltypes
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.pvmt.rst.txt b/_sources/code/capellambse.pvmt.rst.txt
new file mode 100644
index 000000000..c52cb12f2
--- /dev/null
+++ b/_sources/code/capellambse.pvmt.rst.txt
@@ -0,0 +1,50 @@
+capellambse.pvmt package
+========================
+
+.. automodule:: capellambse.pvmt
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.pvmt.core module
+----------------------------
+
+.. automodule:: capellambse.pvmt.core
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.pvmt.exceptions module
+----------------------------------
+
+.. automodule:: capellambse.pvmt.exceptions
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.pvmt.model module
+-----------------------------
+
+.. automodule:: capellambse.pvmt.model
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.pvmt.types module
+-----------------------------
+
+.. automodule:: capellambse.pvmt.types
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.pvmt.validation module
+----------------------------------
+
+.. automodule:: capellambse.pvmt.validation
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.rst.txt b/_sources/code/capellambse.rst.txt
new file mode 100644
index 000000000..83c1eec45
--- /dev/null
+++ b/_sources/code/capellambse.rst.txt
@@ -0,0 +1,65 @@
+capellambse package
+===================
+
+.. automodule:: capellambse
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Subpackages
+-----------
+
+.. toctree::
+ :maxdepth: 4
+
+ capellambse.aird
+ capellambse.diagram
+ capellambse.extensions
+ capellambse.filehandler
+ capellambse.loader
+ capellambse.model
+ capellambse.pvmt
+ capellambse.svg
+
+Submodules
+----------
+
+capellambse.auditing module
+---------------------------
+
+.. automodule:: capellambse.auditing
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.cli\_helpers module
+-------------------------------
+
+.. automodule:: capellambse.cli_helpers
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.decl module
+-----------------------
+
+.. automodule:: capellambse.decl
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.diagram\_cache module
+---------------------------------
+
+.. automodule:: capellambse.diagram_cache
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.helpers module
+--------------------------
+
+.. automodule:: capellambse.helpers
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/capellambse.svg.rst.txt b/_sources/code/capellambse.svg.rst.txt
new file mode 100644
index 000000000..e8e2069f9
--- /dev/null
+++ b/_sources/code/capellambse.svg.rst.txt
@@ -0,0 +1,58 @@
+capellambse.svg package
+=======================
+
+.. automodule:: capellambse.svg
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Submodules
+----------
+
+capellambse.svg.decorations module
+----------------------------------
+
+.. automodule:: capellambse.svg.decorations
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.svg.drawing module
+------------------------------
+
+.. automodule:: capellambse.svg.drawing
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.svg.generate module
+-------------------------------
+
+.. automodule:: capellambse.svg.generate
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.svg.helpers module
+------------------------------
+
+.. automodule:: capellambse.svg.helpers
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.svg.style module
+----------------------------
+
+.. automodule:: capellambse.svg.style
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+capellambse.svg.symbols module
+------------------------------
+
+.. automodule:: capellambse.svg.symbols
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/_sources/code/modules.rst.txt b/_sources/code/modules.rst.txt
new file mode 100644
index 000000000..34442a353
--- /dev/null
+++ b/_sources/code/modules.rst.txt
@@ -0,0 +1,7 @@
+py-capellambse
+==============
+
+.. toctree::
+ :maxdepth: 4
+
+ capellambse
diff --git a/_sources/development/developing-docs.rst.txt b/_sources/development/developing-docs.rst.txt
new file mode 100644
index 000000000..f992b6159
--- /dev/null
+++ b/_sources/development/developing-docs.rst.txt
@@ -0,0 +1,23 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+*************************
+Documentation development
+*************************
+
+The following command deletes previous built documentation and derives
+docs out of code:
+
+.. code:: bash
+
+ make -C docs apidoc
+
+The following command builds the docs:
+
+.. code:: bash
+
+ make -C docs html
+
+The resulting documentation build should be available in `docs/build/html`,
+entry point is `index.html`
diff --git a/_sources/development/how-to-explore-capella-mm.rst.txt b/_sources/development/how-to-explore-capella-mm.rst.txt
new file mode 100644
index 000000000..963cba880
--- /dev/null
+++ b/_sources/development/how-to-explore-capella-mm.rst.txt
@@ -0,0 +1,225 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+*********************************
+How to explore Capella meta-model
+*********************************
+
+Initially the API design was mostly based on our understanding of XML files,
+however we soon moved on into exploring the Capella meta-model. Here is a short
+summary of how we do it.
+
+Getting the meta-model sources
+##############################
+
+First of all we need to get the data - the most straight-forward way is to
+clone the Capella source code:
+
+.. code-block:: bash
+
+ mkdir capella-mm && cd capella-mm
+ git clone https://github.com/eclipse/capella.git
+
+As there are quite a few files we may want to discover the packages of interest
+using ``find``:
+
+- ``find -name '*.ecore' -o -name '*.genmodel'`` lists all the ECore models and
+ Generation files and adds Generation viewpoint for related ecore
+- ``find -name '*.odesign'`` lists all the Sirius definitions (if you like to
+ see how the diagram look-and-feel is defined)
+
+You could open all the related projects right where they are but I'd prefer to
+have a clean sandbox.
+
+.. code-block:: bash
+
+ mkdir capella-metamodel
+ cp -r capella/common/plugins/org.polarsys.capella.common.data.activity.gen capella-metamodel
+ cp -r capella/common/plugins/org.polarsys.capella.common.data.behavior.gen capella-metamodel
+ cp -r capella/common/plugins/org.polarsys.capella.common.data.core.gen capella-metamodel
+ cp -r capella/common/plugins/org.polarsys.capella.common.libraries.gen capella-metamodel
+ cp -r capella/common/plugins/org.polarsys.capella.common.re.gen capella-metamodel
+ cp -r capella/core/plugins/org.polarsys.capella.core.data.gen capella-metamodel
+ cp -r capella/releng/cdo/plugins/org.polarsys.kitalpha.emde.model.cdo capella-metamodel
+ cp -r capella/tests/plugins/org.polarsys.capella.test.diagram.layout.ju capella-metamodel
+
+Now we have all of the meta-model dependencies in one place and can open it as
+a single Eclipse project. You could open those with any Eclipse that has EMF
+(like the Modeling bundle) but I'd advise using `Capella Studio`__ (open the
+link and search for "Studio") for the best experience - it is provisioned with
+all the extras that help you visualize / review the meta-model.
+
+__ https://www.eclipse.org/capella/download.html
+
+.. image:: ../_static/img/2021-05-09_10-32.jpg
+.. image:: ../_static/img/2021-05-09_10-36.jpg
+
+After import Eclipse may highlight some projects with error or warning sign -
+that's fine, we'll let it go for now.
+
+Before we dive into visualizations, let's have a quick look around. The core of
+Capella metamodel is provided by ``org.polarsys.capella.common.data.core.gen``
+project. There you'll find the definitions of the "Capella Layers" and the
+enabling "EnginereengConcerns" components. For example, the ``SystemAnalysis``
+is provided by ``ContextArchitecture.ecore``.
+
+.. image:: ../_static/img/2021-05-09_10-50.jpg
+
+Even though the default tree-view (triggered by double-click on a ``.core``) is
+already giving us something there are much better ways to review the models.
+We'll talk about that in the `Visualizing ECores`_ chapter. But first we
+should have a look into the package structure and interdependencies.
+
+Quick intro to package structure
+################################
+
+If you are unfamiliar with ECore you might be wondering what are those ECore
+files anyways. We could say that they act as UML Packages. Every package
+contains ontology elements (or UML Classes) and "local" element relationships
+(Associations). The packages depend on each-other as elements frequently build
+on top of each-other via Generalization relationship. Thats one of the best
+things about Capella metamodel - it is defined by UML (or well, structural
+subset, but still pretty cool)!
+
+So, from using Capella we know our model layers - Operational Analysis, System
+Analysis, Logical Architecture, Physical Architecture and EPBS. We can locate
+the corresponding ECores pretty quick, but what are all the other packages
+about? To answer that question we should visualize the package dependency - the
+quickest way to do so is to `create a new representation file`__. And after
+that follow the steps in `create package dependency overview`__. The result may
+look like what we have below:
+
+__ #create-new-representations-file
+__ #package-dependency-overview
+
+.. image:: ../_static/img/2021-05-09_17-38.jpg
+
+And even though there are not too many packages in the meta-model, when we
+visualize the inter-package dependency it may be a bit difficult to understand.
+By the way, the figure above `is also available in SVG`__ - you can open it in
+a new tab and zoom-in if you like or scroll down for a simplified one (but
+opinionated).
+
+__ core-pkg-deps-raw.svg
+
+It almost feels like everything depends on everything but that isn't true
+really. We could change perspective and look for the dependencies of an
+end-user exposed package, such as Operational Analysis (oa). I'll use Papyrus
+to visualize that:
+
+.. image:: ../_static/img/2021-05-09_17-44.jpg
+
+When we add all the Capella layers to that picture things get a bit more
+interesting. I added some artificial grouping on top of the existing packages
+that will help us later on - the artificial groups are: ``CapellaLayers`` -
+packages that cover the layers we used to see in the tool; ``CrossLayer`` -
+packages that define ontology and patterns that we see in almost every layer;
+``Enablers`` - the low level ontology that enables every element.
+
+.. image:: ../_static/img/2021-05-09_21-21.jpg
+
+To make a further point on ``CrossLayer``, lets have a closer look at a
+Function. We know that Functions are quite similar in how they look and feel
+across Capella layers and have a lot in common with OperationalActivity. When
+we open ``LogicalArchitecture.ecore`` we see it defines a ``LogicalFunction``
+as a specialization of ``AbstractFunction`` that comes from
+``FunctionalAnalysis.ecore``. There is a very nice feature provided by the
+`Ecore Tools`__ (that is also included in Capella Studio) - Class Inheritance
+view (there is also a tiny `how-to use it below`__). We'll use that to
+visualize the way the functions are made.
+
+__ https://www.eclipse.org/ecoretools/overview.html
+__ #
+
+.. image:: ../_static/img/2021-05-09_22-09.jpg
+
+Just to be on a safe side I've done the above exercise for
+``OperationalActivity``, ``SystemFunction``, ``LogicalFunction`` and
+``PhysicalFunction`` - the inheritance tree is exactly the same. I've done this
+check for a few other familiar ontology elements and got same result. I think
+this gives a feeling for what the ``CrossLayer`` is about - to me that's the
+place where most of the magic happens. And this is how the relationship between
+the ``CapellaLayers`` and ``CrossLayer`` looks like when we de-noise it a bit:
+
+.. image:: ../_static/img/2021-05-09_22-39.jpg
+
+It's been a lengthy chain of thought and to finish on a hopefully useful
+visualization - lets have a look at the Class contexts of some things that we
+use most frequently
+
+Visualizations of some frequently used ontology elements
+########################################################
+
+Below you'll find some quick visualizations for frequently used ontology
+elements, grouped by CrossLayer package
+
+Functional Analysis
+*******************
+
+.. image:: ../_static/img/2021-05-10_22-35.jpg
+
+.. image:: ../_static/img/2021-05-17_11-50.jpg
+
+.. image:: ../_static/img/2021-05-10_22-59.jpg
+
+.. image:: ../_static/img/2021-05-12_21-03.jpg
+
+State Machines
+**************
+
+.. image:: ../_static/img/2021-05-12_18-18.jpg
+
+.. image:: ../_static/img/2021-05-13_20-46.jpg
+
+The figure above is somewhat a "treasure map" to everything related to state
+machines. It is made in a semi-automatic way with the help of ECore Tools and
+ELK
+
+Composite Structure
+*******************
+
+.. image:: ../_static/img/2021-05-12_20-10.jpg
+
+.. image:: ../_static/img/2021-05-12_18-51.jpg
+
+You may also want to have a look at the Block context below as it defines some
+other useful things that a Component (or LogicalComponent) can do.
+
+.. image:: ../_static/img/2021-05-12_20-06.jpg
+
+.. image:: ../_static/img/2021-05-12_19-12.jpg
+
+.. _Visualizing ECores:
+
+Appendix: Visualizing ECores
+############################
+
+If you are new to CapellaStudio and Ecore, here are some practical hints for
+how to get stuff done, ignore the below otherwise:
+
+Create new representations file
+*******************************
+
+To start playing with visualizations we need a new representations file
+(.aird). It is pretty easy to get there but just in case, there is figure below
+to guide you through that.
+
+.. image:: ../_static/img/2021-05-09_17-36.jpg
+
+Package dependency overview
+***************************
+
+To create a package dependency overview for all packages you may follow the
+guidance in the figure below:
+
+.. image:: ../_static/img/2021-05-09_17-57.jpg
+
+Visualizing class inheritance
+*****************************
+
+There is a very nice feature that allows given a class to show all of its
+super-classes (generalizations) and specializations. The figure below gives you
+some hints for how to use it:
+
+.. image:: ../_static/img/2021-05-09_21-46.jpg
diff --git a/_sources/development/low-level-api.rst.txt b/_sources/development/low-level-api.rst.txt
new file mode 100644
index 000000000..38fdb634e
--- /dev/null
+++ b/_sources/development/low-level-api.rst.txt
@@ -0,0 +1,307 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+*************
+Low-level API
+*************
+
+.. py:currentmodule:: capellambse.loader.core
+
+The high level :py:class:`~capellambse.model.MelodyModel`-based API is largely
+manually designed, and therefore sometimes does not cover all interesting
+objects to a usable level. While we are constantly working on improving the
+situation, it's also possible to use the low-level API based directly on the
+XML files in order to temporarily work around these shortcomings. This
+documentation sheds some light on the inner workings of this low-level API.
+
+In order to effectively work with it, you need to understand the basics of XML.
+It also helps to be familiar with LXML_, which is used to parse and manipulate
+the XML trees in memory.
+
+Unfortunately it's not possible to use LXML's built-in XML serializer. It
+produces different whitespace in the XML tree, which confuses Capella's XML
+diff-merge algorithm. This is why |project| ships with a custom serializer that
+produces the same output format as Capella. It resides in the
+:py:mod:`capellambse.loader.exs` module.
+
+.. _LXML: https://lxml.de/
+
+The MelodyLoader object
+=======================
+
+While the main object of interest for the high-level API is the
+:py:class:`capellambse.model.MelodyModel` class, for the low-level API it is
+the :py:class:`capellambse.loader.core.MelodyLoader`. It offers numerous
+methods to search elements, resolve references, ensure model integrity during
+certain modifications, and many more.
+
+The following sections categorize and document the various methods.
+
+The ``MelodyLoader`` closely works together with its auxiliary class
+:py:class:`~capellambse.loader.core.ModelFile`. However, the ``ModelFile``
+mainly plays a role while loading or saving a model from/to disk (or other data
+stores), and isn't used much when interacting with an already loaded model.
+
+.. _api-level-shift:
+
+Shifting between API levels
+===========================
+
+High to low-level shift
+-----------------------
+
+Every model object (i.e. instance of ``GenericElement`` or one of its
+subclasses) has an attribute ``_element``, which holds a reference to the
+corresponding :py:class:`lxml.etree._Element` instance. The low-level API works
+directly with these ``_Element`` instances.
+
+The ``MelodyModel`` object stores a reference to the
+:py:class:`~capellambse.loader.core.MelodyLoader` instance.
+
+Low to high-level shift
+-----------------------
+
+The GenericElement class offers the
+:py:meth:`~capellambse.model.common.element.GenericElement.from_model` class
+method, which takes a ``MelodyModel`` instance and a low-level LXML
+``_Element`` as arguments and constructs a high-level API proxy object from
+them. This is the way "back up" to the high-level API.
+
+.. note::
+
+ Always call ``from_model`` on the base ``GenericElement`` class, not on its
+ subclasses. The base class automatically searches for the correct subclass
+ to instantiate, based on the ``xsi:type`` of the passed XML element. Calling
+ the method on a subclass directly may inadvertently cause the wrong class to
+ be picked.
+
+.. code-block:: python
+
+ >>> myfunc = model.search("LogicalFunction")[0]
+ >>> el = myfunc._element
+ >>> el
+
+ >>> from capellambse.model import GenericElement
+ >>> high_el = GenericElement.from_model(model, el)
+ >>> high_el == myfunc
+ True
+
+When working with multiple objects, it can be desirable to directly construct a
+high-level :py:class:`~capellambse.model.common.element.ElementList` with them.
+The ElementList constructor works similar to ``GenericElement.from_model``, but
+it takes a list of elements instead of only a single one.
+
+.. code-block:: python
+
+ >>> mycomp = model.search("LogicalComponent")[0]
+ >>> children = mycomp._element.getchildren()
+ >>> len(children)
+ 7
+ >>> mylist = ElementList(model, children)
+ >>> mylist
+ [0]
+ [1]
+ [2]
+ [3]
+ [4]
+ [5]
+ [6]
+
+Moving along the XML tree
+=========================
+
+In most simple cases, you can use the standard LXML methods in order to select
+parent, child and sibling elements.
+
+.. code-block:: python
+
+ >>> myfunc = model.search("LogicalFunction")[3]
+ >>> myfunc._element.getparent()
+
+ >>> myfunc._element.getchildren()
+ []
+ >>> myfunc._element.getprevious()
+
+ >>> myfunc._element.getnext()
+
+
+These elements and lists of elements can then be fed into
+``GenericElement.from_model`` or the ``ElementList`` constructor respectively
+in order to :ref:`return to the high-level API `.
+
+Capella models support fragmentation into multiple files, which results in
+multiple XML trees being loaded into memory. This makes it difficult to
+traverse up and down the hierarchy, because in theory every element can be a
+fragment boundary – in this case, it does not have a physical parent element,
+and ``getparent()`` will return ``None``. A call to ``getchildren()`` or
+similar on the (logical) parent element will yield a placeholder which only
+contains a reference to the real element, but does not hold any other
+information.
+
+``MelodyLoader`` provides methods to traverse upwards or downwards in the
+model's XML tree, while also taking into account fragment boundaries and the
+aforementioned placeholder elements.
+
+.. class:: MelodyLoader
+ :noindex:
+
+ .. automethod:: iterancestors
+ :noindex:
+ .. automethod:: iterchildren_xt
+ :noindex:
+ .. automethod:: iterdescendants
+ :noindex:
+ .. automethod:: iterdescendants_xt
+ :noindex:
+
+Resolving references
+====================
+
+You will often encounter attributes that contain references to other elements.
+
+The ``MelodyLoader`` provides the following methods to work with references:
+
+.. class:: MelodyLoader
+ :noindex:
+
+ .. automethod:: follow_link
+ :noindex:
+ .. automethod:: follow_links
+ :noindex:
+ .. automethod:: create_link
+ :noindex:
+
+Finding elements elsewhere
+==========================
+
+The low-level API implements the fundamentals for looking up model objects or
+finding them by their type. The following methods are involved in these
+operations:
+
+.. class:: MelodyLoader
+ :noindex:
+
+ .. automethod:: iterall
+ :noindex:
+ .. automethod:: iterall_xt
+ :noindex:
+ .. automethod:: xpath
+ :noindex:
+ .. automethod:: xpath2
+ :noindex:
+
+Manipulating objects
+====================
+
+.. warning::
+
+ The low-level API by itself does not do any consistency or validity checks
+ when modifying a model. Therefore it is very easy to break a model using it,
+ which can be very hard to recover from. Proceed with caution.
+
+As ``GenericElement`` instances are simply wrappers around the raw XML
+elements, any changes to their attributes are directly reflected by changes to
+the attributes or children of the underlying XML element and vice versa. This
+means that no special care needs to be taken to keep the high-level and
+low-level parts of the API synchronized.
+
+In many cases, the attribute names of the high-level API match those in the
+XML, with the difference that the former uses ``snake_case`` naming (as is
+conventional in the Python world), while the latter uses ``camelCase`` naming.
+This example shows how the name of a function is accessed and modified using
+the low-level API:
+
+.. code-block:: python
+
+ >>> myfunc = model.search("LogicalFunction")[3]
+ >>> myfunc.name
+ 'defend the surrounding area against Intruders'
+ >>> myfunc._element.attrib["name"]
+ 'defend the surrounding area against Intruders'
+ >>> myfunc._element.attrib["name"] = "My Function"
+ >>> myfunc.name
+ 'My Function'
+
+Be aware that the XML usually does not explicitly store attributes that are set
+to their default value (as defined by the meta model). In addition to that, the
+high-level API often offers convenience shortcuts and reverse lookups that are
+not directly reflected by XML attributes. Without at the detailed definitions,
+it can therefore be difficult to infer the correct attributes for the low-level
+API objects.
+
+Creating and deleting objects
+=============================
+
+.. warning::
+
+ Creating or deleting objects through the low-level API is highly
+ discouraged, as it bears a very high risk of breaking the model. It's
+ unlikely that we can support you with any breakage that you encounter as a
+ result of using the low-level API.
+
+ If you need access to model elements and relations that are not yet covered
+ by our high-level API, please consider contributing and extending it instead
+ – it's probably easier anyway. ;)
+
+The ID cache
+------------
+
+In order to provide instantaneous access to any model element via its UUID, the
+MelodyLoader maintains a hashmap containing all UUIDs. This hashmap needs to be
+updated when inserting or removing elements in the tree. The following methods
+take care of that:
+
+.. class:: MelodyLoader
+ :noindex:
+
+ .. automethod:: idcache_index
+ :noindex:
+ .. automethod:: idcache_remove
+ :noindex:
+ .. automethod:: idcache_rebuild
+ :noindex:
+
+Creating objects
+----------------
+
+Creating a new object with the low-level API is a rather complex process. The
+``MelodyLoader`` does provide some basic integrity checks, but most of the
+meta-model-aware logic is implemented within the high-level API.
+
+Before creating a new object, you need to generate and reserve a UUID for it.
+This is done using the ``generate_uuid`` method. ``new_uuid`` provides a
+context manager around it, which automatically cleans up the model in case
+anything went wrong. It also checks that the UUID was properly registered with
+the ID cache (see below). It is therefore highly recommended to use
+``new_uuid`` over directly calling ``generate_uuid``. Note that even when using
+``new_uuid``, you still need to manually call ``idcache_index`` on the newly
+inserted element.
+
+.. class:: MelodyLoader
+ :noindex:
+
+ .. automethod:: generate_uuid
+ :noindex:
+ .. automethod:: new_uuid
+ :noindex:
+
+Deleting objects
+----------------
+
+Inversely to creating new ones, when deleting an object from the XML tree it
+also needs to be removed from the ID cache. This is done by calling
+``idcache_remove`` (see above) on the element to be removed. Afterwards, delete
+the element from its parent using the standard LXML API.
+
+Saving modifications
+====================
+
+The ``MelodyLoader`` provides the same ``save()`` method as the high-level
+``MelodyModel``.
+
+.. class:: MelodyLoader
+ :noindex:
+
+ .. automethod:: save
+ :noindex:
diff --git a/_sources/development/repl.rst.txt b/_sources/development/repl.rst.txt
new file mode 100644
index 000000000..e9ad7c89a
--- /dev/null
+++ b/_sources/development/repl.rst.txt
@@ -0,0 +1,16 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+The |project| REPL
+==================
+
+.. automodule:: capellambse.repl
+
+.. sphinx_argparse_cli::
+ :module: capellambse.repl
+ :func: main
+ :hook:
+ :prog: capellambse/repl.py
+ :title: Capellambse Repl
+ :group_title_prefix:
diff --git a/_sources/examples/01 Introduction.ipynb.txt b/_sources/examples/01 Introduction.ipynb.txt
new file mode 100644
index 000000000..13fa7c0d5
--- /dev/null
+++ b/_sources/examples/01 Introduction.ipynb.txt
@@ -0,0 +1,658 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1a1fe414",
+ "metadata": {},
+ "source": [
+ "# Introduction\n",
+ "\n",
+ "Welcome to the py-capella-mbse Showcase notebook. This notebook will show you some basic (and not so basic) things that you can get done using this library. For more advanced features have a look around the nearby notebooks.\n",
+ "\n",
+ "The below code loads the library and one of the test models:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3e28d1c9",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import capellambse\n",
+ "path_to_model = \"../../../tests/data/melodymodel/5_0/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)\n",
+ "model"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "48ce0c1e",
+ "metadata": {},
+ "source": [
+ "Let's go to the first practical example of working with the library!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7e68b88c-b4bc-4c20-a39f-48094c0eabdd",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "## Example 1: Actor functions\n",
+ "\n",
+ "The below code will print every Actor available in the Logical Architecture layer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "abcd8693",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Multiport\n",
+ "Prof. S. Snape\n",
+ "Voldemort\n",
+ "R. Weasley\n",
+ "Prof. A. P. W. B. Dumbledore\n",
+ "Harry J. Potter\n"
+ ]
+ }
+ ],
+ "source": [
+ "for actor in model.la.all_actors:\n",
+ " print(actor.name)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4ddbf9be",
+ "metadata": {},
+ "source": [
+ "but we could also \"zoom-in\" to an actor of interest:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "56bb4b44",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Prof. S. Snape (org.polarsys.capella.core.data.la:LogicalComponent) allocated_functions LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)applied_property_value_groups PropertyValueGroup "DarkMagic.Power" (2a480409-57d1-46f8-a0ce-e574706a9a7c)PropertyValueGroup "DarkMagic.Power Level" (b1d7453b-69ab-4d81-ab8b-1e48b5870340)applied_property_values (Empty list)
components (Empty list)
constraints (Empty list)
context_diagram Context of Prof. S. Snape (uuid: 6f463eed-c77b-4568-8078-beec0536f243_context)description Good guy and teacher of brewing arts.
\n",
+ "diagrams (Empty list)
exchanges (Empty list)
filtering_criteria (Empty list)
functions LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)is_abstract False is_actor True is_human True name Prof. S. Snape owner LogicalComponentPkg "Structure" (84c0978d-9a32-4f5b-8013-5b0b6adbfd73)parent LogicalComponentPkg "Structure" (84c0978d-9a32-4f5b-8013-5b0b6adbfd73)parts Backreference to Part - omitted: can be slow to compute. Display this property directly to show. physical_links (Empty list)
physical_paths (Empty list)
physical_ports (Empty list)
ports ComponentPort "CP 1" (b4e39757-b0fd-41ff-a7b8-c9fc36de2ca9)progress_status NOT_SET property_value_groups PropertyValueGroup "DarkMagic.Power" (2a480409-57d1-46f8-a0ce-e574706a9a7c)PropertyValueGroup "DarkMagic.Power Level" (b1d7453b-69ab-4d81-ab8b-1e48b5870340)property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f496cb3f010> realized_components (Empty list)
realized_system_components (Empty list)
realizing_components Backreference to - omitted: can be slow to compute. Display this property directly to show. realizing_physical_components Backreference to PhysicalComponent - omitted: can be slow to compute. Display this property directly to show. related_exchanges Backreference to ComponentExchange - omitted: can be slow to compute. Display this property directly to show. requirements (Empty list)
state_machines (Empty list)
summary None traces (Empty list)
uuid 6f463eed-c77b-4568-8078-beec0536f243 xtype org.polarsys.capella.core.data.la:LogicalComponent
"
+ ],
+ "text/plain": [
+ "\n",
+ ".allocated_functions = [0] \n",
+ " [1] \n",
+ ".applied_property_value_groups = [0] \n",
+ " [1] \n",
+ ".applied_property_values = []\n",
+ ".components = []\n",
+ ".constraints = []\n",
+ ".context_diagram = \n",
+ ".description = Markup('Good guy and teacher of brewing arts.
\\n')\n",
+ ".diagrams = []\n",
+ ".exchanges = []\n",
+ ".filtering_criteria = []\n",
+ ".functions = [0] \n",
+ " [1] \n",
+ ".is_abstract = False\n",
+ ".is_actor = True\n",
+ ".is_human = True\n",
+ ".name = 'Prof. S. Snape'\n",
+ ".owner = \n",
+ ".parent = \n",
+ ".parts = ... # backreference to Part - omitted: can be slow to compute\n",
+ ".physical_links = []\n",
+ ".physical_paths = []\n",
+ ".physical_ports = []\n",
+ ".ports = [0] \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = [0] \n",
+ " [1] \n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".realized_components = []\n",
+ ".realized_system_components = []\n",
+ ".realizing_components = ... # backreference to - omitted: can be slow to compute\n",
+ ".realizing_physical_components = ... # backreference to PhysicalComponent - omitted: can be slow to compute\n",
+ ".related_exchanges = ... # backreference to ComponentExchange - omitted: can be slow to compute\n",
+ ".requirements = []\n",
+ ".state_machines = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".uuid = '6f463eed-c77b-4568-8078-beec0536f243'\n",
+ ".xtype = 'org.polarsys.capella.core.data.la:LogicalComponent'"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.la.all_actors.by_name(\"Prof. S. Snape\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "30e17ac3",
+ "metadata": {},
+ "source": [
+ "We can also turn the above data into a table, for example \"actor function allocation\", using `pandas`.\n",
+ "\n",
+ "For this, we first make sure pandas itself is installed, as well as an extension we'll use later."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "400e483d-eca7-4fdd-a9e0-71467e1af8d8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%pip install -q pandas openpyxl"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acbe1247-e1a1-4da8-a95a-7b41f4836937",
+ "metadata": {},
+ "source": [
+ "Now we can use it together with `capellambse`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "833220d0",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " actor \n",
+ " functions \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " Multiport \n",
+ " LAF 1 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " Prof. S. Snape \n",
+ " Teaching; maintain a layer of defense for the ... \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " Voldemort \n",
+ " no functions assigned \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " R. Weasley \n",
+ " assist Harry; break school rules \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " Prof. A. P. W. B. Dumbledore \n",
+ " manage the school; advise Harry \n",
+ " \n",
+ " \n",
+ " 5 \n",
+ " Harry J. Potter \n",
+ " kill He Who Must Not Be Named \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " actor \\\n",
+ "0 Multiport \n",
+ "1 Prof. S. Snape \n",
+ "2 Voldemort \n",
+ "3 R. Weasley \n",
+ "4 Prof. A. P. W. B. Dumbledore \n",
+ "5 Harry J. Potter \n",
+ "\n",
+ " functions \n",
+ "0 LAF 1 \n",
+ "1 Teaching; maintain a layer of defense for the ... \n",
+ "2 no functions assigned \n",
+ "3 assist Harry; break school rules \n",
+ "4 manage the school; advise Harry \n",
+ "5 kill He Who Must Not Be Named "
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "\n",
+ "data = []\n",
+ "for actor in model.la.all_actors:\n",
+ " actor_functions = \"; \".join([function.name for function in actor.functions] or [\"no functions assigned\"])\n",
+ " data.append(dict(actor=actor.name, functions=actor_functions))\n",
+ "df = pd.DataFrame(data)\n",
+ "df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e04c482",
+ "metadata": {},
+ "source": [
+ "and any `pandas.DataFrame` can always be turned into an Excel Spreadsheet, just like that:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "10af24a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df.to_excel(\"01_intro_actor_functions.xlsx\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5370bc56",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "you can check the resulting file in the folder next to this notebook (right after you run the above cell)\n",
+ "\n",
+ "Now that we've seen the basics, lets do something visually cool."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5afcdfdd-79e0-4e07-b321-d92a11f1d082",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "## Example 2: working with diagrams\n",
+ "\n",
+ "The below code will find some diagrams for us."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "eb5f8747",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[LAB] Wizzard Education\n",
+ "[LAB] Test Component Port Filter\n",
+ "[LAB] Hidden Wizzard Education\n"
+ ]
+ }
+ ],
+ "source": [
+ "for diagram in model.la.diagrams.by_type('LAB'):\n",
+ " print(diagram.name)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "66609218",
+ "metadata": {},
+ "source": [
+ "We can analyze which model objects are shown in a particular diagram."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "71bf090e",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Part "Hogwarts" (101ffa60-f8a2-4ea2-a0d8-d10910ceac06)LogicalFunction "produce Great Wizards" (0e71a0d3-0a18-4671-bba0-71b5f88f95dd)LogicalFunction "protect Students against the Death Eaters" (264fb47d-67b7-4bdc-8d06-8a0e5139edbf)Part "Campus" (a3194240-cd17-4998-8f8b-785233487ec3)Part "School" (018a8ae9-8e8e-4aea-8191-4abf844a79e3)LogicalFunction "educate Wizards" (957c5799-1d4a-4ac0-b5de-33a65bf1519c)Part "Whomping Willow" (1188fc31-789b-424f-a2d4-06791873a351)LogicalFunction "defend the surrounding area against Intruders" (7f2936ab-0b54-4e92-9f0c-85a9f0981959)Part "Prof. A. P. W. B. Dumbledore" (4c1f2b5d-0641-42c7-911f-7a42928580b8)LogicalFunction "manage the school" (f708bc29-d69f-42a0-90cc-11fc01054cd0)LogicalFunction "advise Harry" (beaf5ba4-8fa9-4342-911f-0266bb29be45)Part "Prof. S. Snape" (ccbad61a-39dc-4af8-8199-3fee30de2f1d)LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)ComponentExchange "Headmaster Responsibilities" (c0bc49e1-8043-4418-8c0a-de6c6b749eab)ComponentExchange "Teacher Responsibilities" (9cbdd233-aff5-47dd-9bef-9be1277c77c3)Part "Harry J. Potter" (26543596-7646-4d81-8f15-c4e01ec930a7)LogicalFunction "kill He Who Must Not Be Named" (aa9931e3-116c-461e-8215-6b9fdbdd4a1b)Part "R. Weasley" (4d31caaf-210e-4bdf-982e-cdecbc80c947)LogicalFunction "assist Harry" (c1a42acc-1f53-42bb-8404-77a5c08c414b)LogicalFunction "break school rules" (edbd1ad4-31c0-4d53-b856-3ffa60e0e99b)ComponentExchange "Punishment" (85a1fb20-38ea-4d77-acd7-90a8c44dc695)FunctionalExchange "wizardry" (6545a77d-d224-4662-a5b2-3c016b78e33d)PortAllocation "" (a4e2bf11-0705-4f20-bf73-5fa5519954f7)PortAllocation "" (7d31ab50-63d6-46bb-bf53-1716175beae3)PortAllocation "" (317715cb-376c-4df6-a32c-433e3c081f8d)ComponentExchange "Learning" (3b3fc202-be5c-49ae-bf2f-1d61daf3bb50)PortAllocation "" (c1019d06-f376-48e3-832e-634a8ec59463)PortAllocation "" (4cbdf5fd-7268-470b-9811-b62ad67fded1)FunctionalExchange "assistance" (241f3901-11f0-4b00-a903-ed158cce73de)FunctionalExchange "friendship" (1bbb9b2d-517c-4f77-a35c-b3aa3f9422b8)PortAllocation "" (18fa81ee-8b16-4815-86ea-0c287ace43d8)ComponentExchange "Help for Harry" (d8655737-39ab-4482-a934-ee847c7ff6bd)FunctionalExchange "punish" (96a0cf4c-adfe-4490-92d1-bcf75ee77004)FunctionalExchange "educate & mature" (09efaeb7-2d50-40ed-a4da-46afcb9ca7a1)FunctionalExchange "Knowledge" (b1a817bc-40a9-4fc4-b62c-8dea4aa28915)PortAllocation "" (dda7a62a-f25f-46d8-8f05-867c616914c1)PortAllocation "" (fee1fff5-d751-401b-bb3c-2114a74f0c8a)PortAllocation "" (0f6e1aa0-942a-40a9-930f-c7df34b9d8eb)ComponentExchange "Care" (c31491db-817d-44b3-a27c-67e9cc1e06a2)PortAllocation "" (98760017-b3a3-46ca-b1ef-87eee9ea1600)PortAllocation "" (74bd0ab3-6a28-4025-822e-90201445a56e)PortAllocation "" (3ed5ae4f-8a4e-4690-9088-655990a1b77b)PortAllocation "" (299b98b8-8716-4dbc-bc7e-4b9349778c26)PortAllocation "" (14cabdd9-c36f-4e01-ad09-110f906ad725)PortAllocation "" (6d882e28-4208-41d0-b8a5-3a19e1805a34)FunctionalExchange "educate" (cdc69c5e-ddd8-4e59-8b99-f510400650aa)PortAllocation "" (c90bb30d-e36b-46a3-a3a1-e39fdcb519be) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] \n",
+ "[5] \n",
+ "[6] \n",
+ "[7] \n",
+ "[8] \n",
+ "[9] \n",
+ "[10] \n",
+ "[11] \n",
+ "[12] \n",
+ "[13] \n",
+ "[14] \n",
+ "[15] \n",
+ "[16] \n",
+ "[17] \n",
+ "[18] \n",
+ "[19] \n",
+ "[20] \n",
+ "[21] \n",
+ "[22] \n",
+ "[23] \n",
+ "[24] \n",
+ "[25] \n",
+ "[26] \n",
+ "[27] \n",
+ "[28] \n",
+ "[29] \n",
+ "[30] \n",
+ "[31] \n",
+ "[32] \n",
+ "[33] \n",
+ "[34] \n",
+ "[35] \n",
+ "[36] \n",
+ "[37] \n",
+ "[38] \n",
+ "[39] \n",
+ "[40] \n",
+ "[41] \n",
+ "[42] \n",
+ "[43] \n",
+ "[44] \n",
+ "[45] \n",
+ "[46] \n",
+ "[47] "
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "diagram = model.diagrams.by_name('[LAB] Wizzard Education')\n",
+ "diagram.nodes"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eaaffccd",
+ "metadata": {},
+ "source": [
+ "And again there are warnings - there are quite a few visual filters in Capella and we are not handling all of those yet but mostly those that are used in our projects. The filter coverage will eventally improve, stay tuned."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9ec8f512-6e78-46fe-9dce-ed6fbfc8ad7a",
+ "metadata": {},
+ "source": [
+ "And finally, you can display the diagram right in the notebook."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "cc09fd22",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "LF Hogwarts produce Great Wizards protect Students against the Death Eaters Campus School educate Wizards Whomping Willow defend the surrounding area against Intruders Prof. A. P. W. B. Dumbledore manage the school advise Harry Prof. S. Snape Teaching maintain a layer of defense for the Sorcerer's Stone Harry J. Potter kill He Who Must Not Be Named R. Weasley assist Harry break school rules wizardry Headmaster Responsibilities Teacher Responsibilities Help for Harry Knowledge Punishment Learning educate & mature friendship assistance Care punish educate "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "diagram"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f678a3ee-ac7e-4ce4-a8e2-0d41c612800e",
+ "metadata": {},
+ "source": [
+ "We use SVG diagrams a lot since they look great in documentation, are zoomable and really light-weight. To make integrating them into a pipeline easier, we also support some derived formats, which you can access using `.as_` style attributes. With some additional dependencies set up (see the README), capellambse can also automatically convert these images to PNG format."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "b5699e75-2e4c-4b8e-81af-51be00ff6dc3",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "'` tag, using the above `data:` URI as `src`\n",
+ "print(repr( diagram.as_png )[:100], \"...\") # A raw PNG byte stream, which can be written to a `.png` file"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7917bb3a-d1b8-4ce4-9d60-5c0c50b5b1da",
+ "metadata": {},
+ "source": [
+ "It's also possible to directly save a diagram to a file by calling its `save` method:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "7798e7f0-61eb-4395-99f2-2cc6dbd46ff1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "diagram.save(\"[LAB] Wizzard Education.svg\", \"svg\", pretty_print=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "93a2e9cf-e599-4c3d-96b7-d6c590e74b16",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "...\n"
+ ]
+ }
+ ],
+ "source": [
+ "with open(\"[LAB] Wizzard Education.svg\", \"r\") as f:\n",
+ " print(*f.readlines()[:10], \"...\", sep=\"\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "21e0b9c2",
+ "metadata": {},
+ "source": [
+ "Lets now try something else - we check if function port has any protocols (state machines) underneath:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "cf91c71a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "StateMachine "FaultStates" (06cefb2b-534e-4453-9aba-fe53329197ad) "
+ ],
+ "text/plain": [
+ "[0] "
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fnc = model.la.all_functions.by_name(\"defend the surrounding area against Intruders\")\n",
+ "stms = fnc.outputs[0].state_machines\n",
+ "stms"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dc8069df",
+ "metadata": {},
+ "source": [
+ "and we can also check what states it could have:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "b5751a0d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "State "normal defence" (e494e247-efce-4258-9cc6-fd799dbb0adf)State "erroneous defence" (81f3de46-4596-41b0-8569-c3c21161a2f6)State "no defence" (5b6a03d8-0ef9-4b2b-9a50-a745f490d663) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] "
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "stms[0].regions[0].states"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "86e23011",
+ "metadata": {},
+ "source": [
+ "This concludes our introduction. There is a lot more you can do with the library - feel free to explore the examples collection or create an issue to ask for a specific use-case example and you may see it around pretty soon."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "c5ea7dc634d8047a259e5b898f154d237fbe6934b444b1a949475949608d751e"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/_sources/examples/02 Intro to Physical Architecture API.ipynb.txt b/_sources/examples/02 Intro to Physical Architecture API.ipynb.txt
new file mode 100644
index 000000000..af23ddc03
--- /dev/null
+++ b/_sources/examples/02 Intro to Physical Architecture API.ipynb.txt
@@ -0,0 +1,754 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b02a2030",
+ "metadata": {},
+ "source": [
+ "# Introduction to Physical Architecture API\n",
+ "\n",
+ "**Note**: In this notebook we will use `pandas` dataframes library to construct and visualize tables, **if you don't have pandas installed** in the current environment you may want to do so by running the cell below."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "4c181cfb",
+ "metadata": {
+ "editable": true,
+ "slideshow": {
+ "slide_type": ""
+ },
+ "tags": []
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Requirement already satisfied: pandas in /home/dahbar/projects/py-capellambse/.venv/lib/python3.11/site-packages (2.1.1)\n",
+ "Requirement already satisfied: numpy>=1.23.2 in /home/dahbar/projects/py-capellambse/.venv/lib/python3.11/site-packages (from pandas) (1.26.0)\n",
+ "Requirement already satisfied: python-dateutil>=2.8.2 in /home/dahbar/projects/py-capellambse/.venv/lib/python3.11/site-packages (from pandas) (2.8.2)\n",
+ "Requirement already satisfied: pytz>=2020.1 in /home/dahbar/projects/py-capellambse/.venv/lib/python3.11/site-packages (from pandas) (2023.3.post1)\n",
+ "Requirement already satisfied: tzdata>=2022.1 in /home/dahbar/projects/py-capellambse/.venv/lib/python3.11/site-packages (from pandas) (2023.3)\n",
+ "Requirement already satisfied: six>=1.5 in /home/dahbar/projects/py-capellambse/.venv/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas) (1.16.0)\n",
+ "Note: you may need to restart the kernel to use updated packages.\n"
+ ]
+ }
+ ],
+ "source": [
+ "%pip install pandas"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3d39f975",
+ "metadata": {},
+ "source": [
+ "The cell below loads our test model so we could play with it and silences warnings."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "1386d2f7",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "import capellambse\n",
+ "import logging\n",
+ "import pandas as pd\n",
+ "\n",
+ "logging.getLogger().setLevel(logging.CRITICAL)\n",
+ "path_to_model = \"../../../tests/data/melodymodel/5_0/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9f73eb7e",
+ "metadata": {},
+ "source": [
+ "but before we jump into code, lets have a look first at Capella metamodel concerning the Physical Architecture layer (PA).\n",
+ "\n",
+ "Things in PA are very similar to what we see in SysML when it comes to `ibd`s (Internal Block Diagrams) - the boxes we see on those are `Part`s that are instanciated from `Block` objects. Same happens in Capella - the boxes we see on `PAB` diagrams are `Parts` that were instanciated from `PhysicalComponent`s. Here also comes the very special difference of Capella - unless you explicitly enable **part re-use**, `PhysicalComponent` will always have only one `Part`. This is the default behavior of Capella. \n",
+ "\n",
+ "Our API should support both cases but at the moment we don't use models with **part re-use** enabled in production yet and so don't test the library against this case. Yet we do implement Parts and support many parts - one component relationship model.\n",
+ "\n",
+ "One more issue to mention - rendering PA diagrams outside of Capella was never a high priority so the resulting representations of PABs rendered without Capella are not very accurate at the moment. We hope to improve it soon though. If you still do want to see how it looks like when we render it right now - uncomment the `# diagram` in the cell below"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "8b555976",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAuEAAAMqCAIAAACjeggGAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nOzdd1gTSRsA8HfTCVVFQUVQmtKliBVsYO/YsX9nAw9FxYqoiNi7Yj0FFAs2VEBR7GLBLogNETuiKEgLIZv9/giEECAUKQHf38Nzt5lM2012nczMzhIURQFCCCGEkJyh1XQFEEIIIYSKgW0UhBBCCMkjbKMghBBCSB5hGwUhhBBC8gjbKAghhBCSR9hGQQghhJA8wjYKQgghhOQRtlEQQgghJI+wjYIQQgghecSQ/bany6DqqQdCCCGEqo2PX0hNV6F0pbRRAMDHb0M11AMhhBBC1cPTZU5NV6FMcKwHIYQQQvII2ygIIYQQkkelj/UghORWdHT0rVuRsuMYGpr26zegeuqDEEKVCNsoCNVily6dnTz5KIslK8769fbYRkEI1UY41oNQ7aaqCmpqsv5oNEIyfvfuYwMDT4tf/vjxS0XFIjX1d9GcebwcNTXLouEcjnFJlZHxFkIIlRe2URCqrRwcuiYmhk+bBhcv5oUcPAhTp8KcORATU2Kq8eOHHDxYcM/h4cNn+/TpoqamUvZyb9w4UsEaI4RQeWAbBaHaqmNHau/e39OmQW5uXsjNmzB3Lri4wIQJQJLFp3Jy6hUd/fTz52+il4GBp8ePHwIAV67cad9+qIVFP3v7UXFx8eL4Xl6bjYx6Ghn1fPAgr+Fjbz9KtBEZGWVjM8jEpJelZf+EhI+SpZSUG0IIlR22URCqrXJyLMaO1QkPB23tgkCCAF1dYLFKbKMoKioMHtwjKOgMAMTFxX/+/K1Hj07JySlz5viGhu57+jR0zZp5EyfOF0VOS0s3NTV88SJi8WIXL6/NkvkkJX0fO3auv//a588vREUFa2ioi98qKTeEECoXnDOLUG1lbNzm8+cvOjrv69cvCHRzAwUFmDkTZEykHT9+iJub97x5UwICTo0ZM5BOp9+8eT85OcXZ2V0UIT09Q7TB4bCHDesNAHZ2Nj4+OyQzuXXroZ2djampIQBwuQqSb5WUG0IIlUtZ2ihUldcCIVR+9+/vXLr029On8OQJNG2aF7hlCxgYSEWkpM7iLl1s09MzHz6MCQo6c/78fwAURVEWFkbh4fukUrHZLIIAAIpOpwkEAol8KIoSEgRR3PWhpNwQQqh8cKwHodrqyxeIimLGxZU7IUEQY8cOnDLFU0ND3cysJQDY2dlERz+9c+cxAAiFQvHUExns7dvcvHn/1at3AMDj5WRlZYvfqkBuCCFUFLZREKqtVqzwf/TIoX9/6Nw5L2TPnqKdKMUbP37Io0fPx40bLHqpoaF+6pSfu/tKc/N+pqZ9Tp26KDu5KElg4Hpn59kWFv07dRqZlPRD8q3y5oYQQkXhfBSEaitjY/1GjVSMjIDNLndafX0dinojGWJv3+bu3ROSIRwOOzX1kWhbS0szPv6yaJvHey7acHDo8ODBackk4reK5oYQQuWFbRSEajE2W8XbuzmdLivO79/M6qoOQghVJmyjIFSLzZ07D2BeTdcCIYSqBM5HQQghhJA8wjYKQgghhOQRtlEQQgghJI+wjYIQQggheYRtFIQQQgjJI2yjIIQQQkgeYRsFIYQQQvII2ygIIYQQkkfYRkEIIYSQPMI2CkIIIYTkEbZREEIIISSPsI2CEEIIIXlUhc8U9HSZW3WZo2rj47e+pqtQTfAbixCqS+rA1btqn3vs47ehSvNHVc3TZU5NV6Fa4TcWIVQ31I2rN471IIQQQkgeVW0/CgBVxfkjhBBCqG4qSxsF2xl/OfwCIIRQbVTrr95V3Y9SOqFQKBSWchxpNIJGw2EphP4WFEWRpFB2HIIAOp1ePfVBCNWImm+jzJ7tWr9+nOw4fH57H5/V1VMfhFCNCw4+eevWxoYNZV2g4uLqHT16ptqqhBCqfjXfRlFRoby8vsiO4+WVKxWyf/+Jdev28vm5FEWNGzd42TK3KqugvBAKhatX7160aLqc54lQZRBMm5ZsYiIrhpdXI6kQJSUzFRVlGo0AAA6HHR9/pVxFcjjGPF4pv5f+kLydcXhVQXKuqgdQKBl/v36lrlmzMjb29Zo18PNnXoLXr+HhQ/j6VVY+b968W7BgXWRkwNu3l+Pizvft20V2QX/+R5KCqi6i1L/c3Fxf352Vm6dQKCwtT4Sq2549uy5dCgsMhAcP8kKSkuDhQ3jzBqjSvpKPHp359Cnq06eo8jZQAODGjSPlr2z5CIWUr69fVZdSdrm5gkqvj7ztI6rVanKSx48fv5o0OX3q1MemTeHHj7zAqVMhMhIWL4aFC0tMmJT0Q1lZUUNDHQA4HHabNmai8CtX7rZvP9zCor+9/ei4uHgA4PFyVFWtli7dOmLELFtbpwcPYgEgKyt78GAXM7N+Zmb9Zs1aKUp78mSEmVk/Y+PeQ4a4/vjxS5x2yZLNw4a5hYZeFZceGXnbxmaIiUkfS8uBCQkfS0qrpma9ePHGVq16mpr2ffr05bBhbvr6Dv36TeHzc3m8HBUVy/nz1zk7z+nc2VlUKwAYNszNwqK/iUmfqVOXkCQpVYfRo2fzeHwHh/FOTjNk51/2Q+HpuUmcZ6V9rgj9mc+fz+/bd2fePIiKygsJCAA/PzhwAHr2BD6/fLkdPBhiaOhgbT1w0aL1rVv3B4CkpO/6+t1E78bGvraxGSTatrcfBQA8Xo6KisX8+WudnWd37jzqwYMYyDujLRcv3tCqVQ9T095Pn74YNmyGvn63fv0m559xd9q3H2ph0c/efpTEGdd66dItI0a42doOEeXj6bmRx+M7OIxzcnKVrGRkZJSNzSATk16Wlv3zryoXzMz6GBv3HDLEReKqUmIdiq02AAwbNsPCop+JSa+pUz0lriqtlyzZNGzYjNGj3cX1qep9RKgCangialgYa/FidmhoQQhBwPz5sH8/XLtWYqr27S319LRbtOg6dqxHYGCI6PxJTk6ZM2dVaOiep0/PrVnjMXHiAlHk378zHBw6HDu2edkyNy+vzQAQEXGLxWLFxITGxIQuXToDAD59SnJ1XR4aujsu7nyLFlrz5q0Vp+3c2fb48a0DBzqIQpKSvo8d6+Hvv/r58/CoqKMaGuolpU1LS7eyMnn5MsLZeYCj4wRf39nx8ZEMBiMk5BIApKdnduvWLihow44dS8eOnUtRFABs3+719Om52NgwiqKOHAmVqsOxY1s4HFZkZMDJk9tl51/2Q+Hj4y6ZJ0LyIC6Ov2yZysaNhQKHDQNfX9DRgdevZaVt02Zw8+admzfv3KfP/wDg06ekBQvW3rhx5OHDMz9/ppWxAunpmd26tQ8K2rhjx3Lx6Zl/xl10dh7o6Dje13dufPwVBoOef8b5hobue/o0dM2aeRMnzhflk3/GbZU442ZzOKzIyMCTJ3eIi0tK+j527Fx//7XPn1+IigrOv6osCw3dGxcX0aKF1rx5a0QxZdShpGpv377s6dPQ2NjzxV1Vth87tlWyPlW3jwhVTE3OR9HT0965M3zVqrk7d15XUckLpCg4fx4ePQJr6xITMhj0ixcPxMa+vnHj/s6dh/fuPXb9etDNmw+Sk1OcnfNW1ktPzxRtcLkKdnY2AGBqaiD6gWJu3tLd3dfd3dfRsaOjY0cAuH37UZcutjo6TQFg+vTR3buPF6Vls1ndu7eXLPrWrYd2djampoainAEgLOxqsWk5HLaTU08AsLU1NzbWNzBoDgBt2piJ6sBkMnr06AQApqaGfH7ux49ftbWbnDgRcfRoKAAkJ6eoqCiNGTOw2DqUmj+dTi/joUBF4PBWzdu379jJkyeNjFZaWRUEPn4MX79CfDzo64vDihmOvH//lKZmQ3GEqKgH3bq119RUB6AmTnS6e/exRKqi/83Lk8lk9OjREYAyNTXg8/kfP35p1KhB/hlH2dqaGRvrGxjoAFBt2pglJHyg02nJySnOzu6iLNLTM0T55J9xlKmpQULChyJF57l164GdnY2pqQEAxeVyACAs7EqXLm11dJoAUNOnj+7efZworYw6FFttbe0mJ06cP3o0DAquKgMAqPyrivShqLp9RKhiarKNkpj4eeHCCQ0apEybBr6+oKeXF56RAV27QocOpSQ3NTU0NTWcNGmompp1YuJniqIsLFqFh++TisZk5u0jjUYTCEgA0NPTfvbs3KVLUUFBZ9es2XP9ehBFAUEQRYvgcNhS4RRFFQkpPi2bzRJt0Ok0Doct3hbVQSikSFLIYNABIDdXQBDE3btP9u8/ce3aIWVlxY0bDyQkfCipDqXmX/ZDgZAcmjZtvKbm12fP4OlTmDYtLzAjAxo3htBQ4HAqmC2VP5mFwWAIhXk3Not6YaUUPT2h0BlHlzjj6PlnnFGFz7jirirSISIy6lBstfOvKkHKyoobN+4X/zIpw1WlkvcRoYqpyTmzJEn26/fbzy+rf38gJb7bw4YV20ApSPj27fsbN6JF2/fvP6PRaBoaDezsrKOjn9258wiAEgrJBw9iCrfoC7Y/ffrKYNCcnHrs2OH16NFzihJ27Gh5/Xr0589JANS+fcFFfmEU/Nnb29y8ef/VqwQAisfjZWVllSGtdAVE+37oUAgAdfnybQ6HpaWl8etXmrZ2Y2VlrkAgOH36YtHkDAaNTqfz+fxS8y/7oSiSJ86ZRTXPwIDctOnHkiWQk1MQ2KkT9OoFiorly6pjR+srV+4kJX0HAH//k6LABg3UsrJ4v36lAUBExM2iqUiSPHToDABcvnybw2FraWnKLsXOziY6+umdO48BQCgUiueCFMVg0Ol0ulTDyN6+zc2b91+9egcAPF5OVlZ2x47W16/f+/z5GwDkX1VKV7Tav36laWs3UVZWFAjI06cvlbE+VbGPCFVMTfajqKkpx8a2HTr0iZ5eco8eeYFTppSekKKolSt3jR07j8ViqqgonTixVVFRQVFR4dSp7e7uq7KysgUCctAgBxsb02KTx8S8nj9/HUEQFEVt27aEIAgtLc2tW5f06TOZoih9fZ09e1aUVLSGhnpg4Fpn5zm5uQImkxEcvEVXt1kZ00pSVVVOSPhoazuUz889fHgjQRCOjh39/U8NHDidy1UwMtIrNpWrq7OV1WBNTfXQ0N0yMtfQUC/joZDMMzLSvyw1R6iqcTiWkyYRysrPB+VNZoUuXaBhQ5lp8llZDRSv9xgXd0FLS3P1ag97+9GNGjXo2dNOFE4QxJo1Hj17TjIw0GnWrHHRTFRVlRMSPtjaOvH5fNHpKbtQDQ31U6f83N1XZmXxBALBoEGONjZmJUV2dR1jZTVQU7NhZGSAOHlg4Hpn59n5V5WturrNtm716tPnn/yrik9Z9r1otR0dO/n7nxo4cJrMq0pefUJD91TdPiJUMQQl82Y+T5dBPn7rKpa1p4uHj9/aUqN5ebl4e18uLU5/b+9a/4xpMR4vR1OzY2rqg9Kj1jRPl3kV/gLUOp4uHnXgUeZ1w7Fjx0xNPUtbH8XC2/tE2fN8+TJh5MiZT56ckx2Nx8vR1Gyfmvqo7DnLg1pabVR1PF3myrh6e7p4+PiFVGd9Kqbm13AjSeG7dzVdCYSQnPn8GbhcWRGysgTVVReEUM2o+TZK797jrl1rIzvOwIFWsiPULhwOu1Z0oiBUU9q27XD16vzPn2XFsbfXKFeerVrpltqJAnmnZ+3rjail1UZItppvo3Tq1KFTp9Lu4UEI/U2aN282ceI/NV0LhFANq+o2Ct4YghBCCKGKqOF1ZhFCCCGEioVtFIQQQgjJI2yjIIQQQkgeYRsFIYQQQvII58wihBBCSB6VpY2C7Yy/HH4BEEKoNqr1V28c60EIIYSQPMI2CkIIIYTkEbZREEIIISSPamzOrKfLwiouGhXw8VtV01Wo9Txd5tZ0FRCqVvgYcFTjavJ5PT5+G2qw9L+Hp8ucmq5CHYHfWPT3wOsGkgc1+0zBWj/lGNU5+J1ESAxPB1TDqriNgt9wOYEfROXA44gQQtWnZvtREEJyJyLiwvPnj2XHsbW169SpU/XUByH018J1Zv8S+EGgsrp1K2TOnMuy42zc+APbKAihqlaz9x5T8vmXnZ09e7avtrZ9ixZdzM377twZVONV+rM/hMqBIEBNrZS/opSUzHv2nCja/vHjl5qaVUn5C4VCX9+df15PHi9HRin7958wMuqpp9dNV7frsmVbS82NwzEptW6yS0QIVTpcH6UYI0e6f/2aHBsb9u7d1cuXA3/+TKuKUkiSrIpsUVWq8eZm1f4lJHxwcur25csdJyd4+zZvnzdsgKlTYdEi+PBB9qGAly8TbtyIlmgZF19KfjvgT2tLkoKSSnnz5t2CBesiIwPevr0cF3e+b98upeZ248bhstWt7n8NJPYUoRqGbRRpMTGvb9y4v3fvShUVJQBo2LD+4sXTAWDYMDcLi/4mJn2mTl0ial7weDlqataLF29s1aqnqWnfp09fDhvmpq/v0K/fFD4/FwCuXLnbvv1wC4v+9vaj4+LiRUlUVa2WLNk8bJhbaOjVonkiVINIkhw06Pe+fVmDB4P4+xgWBn5+MGwYTJhQSnIvL1dPz01SgUXPAk/PTTwe38FhvJPTjO3bDy1YsB4Ajh8/z2AYpaWlA4C19eDXrxMB4OTJCDOzfsbGvYcMcf3x4xcUPoPCw6+LisjKyu7bd/Lq1bvFhSYl/VBWVtTQUAcADofdpo0ZAMguy95+tFTdACAy8raNzRATkz6WlgMTEj7m7+YWI6NeRka9HjyIrdBhRgiVFbZRpD1+HGdioq+kxJUK377d6+nTc7GxYRRFHTkSKgpMS0u3sjJ5+TLC2XmAo+MEX9/Z8fGRDAYjJORScnLKnDmrQkP3PH16bs0aj4kTF4iS/P6d0bmz7fHjWwcOdCg2T4Rqiqqq8uvX7Z2dNV+9AlXVgnA6HVq1gpycUpIPGdIjMzP74sVb4pBizwIfH3cOhxUZGXDy5PauXdteuXIHAK5di7axMb1+PfrXr7Tk5BRDw+afPiW5ui4PDd0dF3e+RQutefPWivIUn0H9+3cDgJSU1B49Jg4d2mvBgqnictu3t9TT027RouvYsR6BgSGi3wwyyhInlKxbUtL3sWM9/P1XP38eHhV1VNTiSUtLNzU1ePHiwuLF0728Nv/R4UYIlaZm58zKY3ciRQlF/5cKP3HiwtGjYQCQnJyioqI0ZswAAIrDYTs59QCgbG3NjI31DQx0AKg2bUwTEj7S6bTk5BRn59mi5OnpmaIeVDab1b17O1H+xeVZVbtVZTmjukNBgWNgYBMf/9bAIImb30qnKBg5Evh8WLmylOQEQXh7z1yyZHNY2F5RyM2bD5KTU5yd81YDS0/PlEpiYmLw6VNSWlr6nTuPly3798qVuyQp7NzZFgBu337UpYutjk5TAJg+fXT37uNFSdhsVvfu7UXbfH6uvf3oVavmDBjQXTJbBoN+8eKB2NjXN27c37nz8N69x65fD5JRVrFu3XpoZ2djamoIAFyuAgDweDkcDnvYsN4AYGdn4+PjV8oRQQj9Gbz3WJqlpfHz5/EZGVmSXSl37z7Zv//ktWsHlZUVN248IO71ZbNZog06nc7hFGwLBAKKAguLVuHhe6Xy53DYBEHIyBPJsTre1EtK+v79+5YVK9LPnIGvX0FZOS/86NFioxc9GlTfvp1Xrtx59qzotiCKoqgiZ4HkrA4AgE6drIODw+vVU3FwaL9ixQ6hUNitWztRWoIgCkemRD8MCCJvm8lktGtnce7clf79u4pOK0mmpgampgaTJjmpqdkkJn7S1W1WUlnF1o2iqPyCCirPZrNEgXQ6TSAg6/xXAqGaVafaKEFBga9ePZAdx9q668CBg2VEMDdv2bGj1eTJnjt3LlNTU/n+/eeuXUdtbEy1tRsrKysKBOTp05csLFqVWhk7O+tp07zu3Hncvr2lUCh89CjOxsZUMsKvX7/LmydCVS0hgREVxXj3TlDhHFasmPm//y0SbRd7FjAYdDqdzufnslhMAOjatZ2Pz85//hnG5SpwuQohIZHu7hMAoGNHK3d338+fvzVtqrFv33Fx34kkgiD27Vs5ebLnpEmL/vtvJY2WN3j99u2Hz5+/2du3AYD792NoNJpopKakssQk62ZvbzNzps+rV+9atmzB4+UIhUJx/qio69ej7959ItpWVlacONFJQYEjGeHRo+fnz9+QDLGyMund2776qohqoTrVRnn16q63dynrOnh5sWS3UQAgOHjzokUbTU37EQShpqbs5jbO0bGjv/+pgQOnc7kKRkZ6ZamMhob6qVPb3d1XZWVlCwTkoEEOUm2UCuSJUJXS0Wni6npo27YV//57t3nzvMCrV8uXSffu7XV1mz16FAclnwWurs5WVoM1NdUjI/27dm3r4rKsa9e2ANCli+37959btNACAC0tza1bl/TpM5miKH19nT17VhRbHEEQe/f6TJmyZMKEBQcOrKLT6QBAUdTKlbvGjp3HYjFVVJROnNiqqKgAACWVJUmyboGBa52d5+TmCphMRnDwliZNGpXvWPxNIiKuX7my18oKAIj4eHZw8KkrV45Lturu3n0SHLyja1eKogCAiokRfvgwANsoSLY68rweoVCYlpbB4wl+/QIVFaDT/6hcLpezefOizZsXSQYeOyZ1wwLF4bBSU++LcuvSpU2XLm1E2wsWTBZFsLe3uXv3WElJGAxa0TxlVwyhKsViMY2N9Rs2VDQ2LnfajIwn4u0rVwLF2/b2be7eDZaK7Os729c3b6pWq1a6FPVKtL18udvy5W7iaEOH9hw6tKdkQg6HnZr6QGpb1EyRjKavrxMR8V/RSsooi8eLKVo3B4cODx6cksxBXLqWlmZ8/KWiRfzNOncmXF0JgiAoKnfkyISAgFMTJw6VjGBlxZg/n6QoiqIgMBASE/PC06yHE0pcEDVoWEyViN0gFPL2neJMGQoAVA7/t/0E1XuHSyqX4uXwtgTlRkQBnUYoKrBG9maP7F1MtBLySW09VO3JiVL3LmOipzDxCwDQDXQUVsygaTQoNQn6c3Vkndm3bz8uWTJGT+/39Ong7Q2GhgAAc+fC79+QlQXu7mBtXT0VkVvY+qkUf8Vh5PFYXl7NZcdhMpX+kqOBKoBGI2bNynGd7jVpUqFfemw69O7N7NRJeuYQACid3ERTr1fwmoKc3cGiNkqpsuasJxTYyme3EUpc6mdazvGLf1b94nF9Z9IaNwSK4m05xNt0kLt6VlWUgqTUnbGevn35w4fn+PsXhDx6BFeuwI8fMGAA3L5dYxVDqHZZu1Z6jROEyoggCNHk5bZtCV6m4DuXqyjxbiRJLprHvxDFEI33yJC95RDFF2RMWkIoK3LXzgYA3rbDuRFRAMBd7U431RfHJF+/Fzx4rnJ1P8HlAABRX5UzdRgAZM5aI3z/BQQk3dqYu2SquHc9e90BQdRjoNG43jMk8wEAwb0Y3uaDFC+HUOIqLHOh6zWTfJfWuCEAAEVRAlzLqvqUpY1SC34tqavX+/Jl0KhRV9q2/aiuXugtgQDY7BqqVh1RC74ACCH5QRAEk0nUV6b9yKQUJe636kanJ36lMjJAUVE6ScawOaJmBF1PS3H3UoWZY/hBoUr7VwAAlcOn0jPpBtqcf0fzz13jbQtS3L1UnJB8kUA30BY1UCRxl0wlGqgBRWUt8+OH32T17wIAVHomvWVzBY+JguiYzHkbVML8IL961M+07DX/Ke1fQagpC568zFq0RfnYeulKTvQkn72maWkq7feujONUDWr91buOzEehKGFm5m+SzM3MBHEDnaJg1ChgscCv0CoGxS/zHB//wcCg55Yti9zcxlZWrYri8XI0Ne1SU6OlwjkcCx7vadWVixBCVU3ciSKSyaOkmiJkXjSqaD+K0vENhcZ6pHJms5g9OwIAw9qYt6vw9KYSumT4Ebdzw28AgPBnGqHEhf5dAADoNFZfewBg2JpBrkCY9COvdwRA8OA59TMtc97G/NpnF81T6YAPCMjsTYG8AyEKcyeUVFtUierIWE9KSqqBwRVv77RDhyAlBRrkT2Y6cqSsOQQEhHTpYhsQEFKlbRRUy9X6HyUIVTVRS+XnTyAFoE4rNPUkiiRbNCG4XKAoKHW4pxAWM6/Dg06HwkMtdCNd8s0HKosn2ZUiePqKfypSKWAloaiQ439G+CmpmDwpgMJr6tBbNpfsoSkeg85ycsz8nxe2UapH3bnd/8wZ9ty5nJCQgpDGjcualqKoQ4fO7ty5NDU1PTb2DQBkZfEGD55hZjbAzGzArFmrig2BvGeRjLSwGGRvPyYu7i3kPcTHdvHiza1a9TE17f/06cthw2bp6/fs12+aaEFuAPDwWGduPtDScrDU8z58fHYuXJjXir9792mbNsP+4HgghFB1E/ejhIVRLAUGNytL8s9JkOOxnFam1gmdBnQ65Ja+Tg+9ZXOGlVG213YqPRMAqJ9pvJ3HqN+ZtMbqhKICkMLcyDsFsUkhP+wGAAiiY4DFkLw3h2FtLIh5I3jyEgBAKCRj4yVLoVLTRTf1AEnyQ67QDHRK3wVUGerIWvgGBtpHjkQuXz7zyJGrTGZe4OGSb1WTen3t2r1Gjeq3atVi7NgBAQGn163ziIi4yWIxY2LOAMCvX78BqKIhyck/58xZExm5v0EDtTt3nkycuPDevWMAVFpaupWV0cqVM1et2uPo+L+oqCADA51Bg2aEhEQOGNA1LS3d3Nxw3bq5165FOzt7vHwZln9WU5MnD7OxGert/S+Tydi9+9jUqcMr7xBhBwBCqBieLgtKfssDAHz81pUrQ4IgeDxizx5G8Ok9ko8a8PMLio5e27VbLkUVM9aT4eQO+YupKJ/bTihx2aP7pDu5E+pqijuXyC6Ru2keb9PB9AH/AgChosQe04/ZoTX/9OVM15WEApsmMfWVUFYUvv+aPnwO5AoU186R7EchGqgpbl2Yvfo/4OWAgGQ6tJOcUUtl8zLnrqe+/wQajW5mwPV2LdcxQRVWR8Z6AIDJZNBohLiBUi4BAWfGjh0AAOPGDejUaT7t3+UAACAASURBVMzq1bPNzVu6u692d1/t6NjB0bEDABQNuXnzQXLyT2fneaJMxM8iyX+ID9jamhsb6xkY6ABAmzZmotXuGQz66NF9AaBLF1s+P/fjxyRt7bwOHw2NBh07WoWEXHZ07HDhws3t2z3/6IigisDGHPrr+KwrcZFrT4+XkieFklLrhg3r02g0FRWlLVsWt2qlO2nSogcPYhkMeoMGKlwulZ5OEgTx7Bm7c+dunTu3kTqhHj0SrFmTFxIbK1okggIA1YeS60iJUJxZYzizxoheqN4LEsWkadRXidgllS3BYSks/J/Cwv9JBipunCuVIcFmqt4LAgDOv6PEgQCg9uR43ppVNsbKR9dKJhFv0RqrK5/YIJVh0cOFKl3daaMAgKJiYy8vC9lxNDS0pUIyM7NPn468fPnO+vUHAODnz7SLF2/37m337FnIpUu3g4JC16zZd/16oJ5eM6kQigILi5bh4bulMpR4iA+Nw2GLtwVF7ljLfyJJAReXUcuX7/j69fuQIY6ilTGRPMGrEvpb3E5sfvtd80cM0/URBY/AZlnPH+82TkmJ+/Tpy1G+dydP7tCk56rZrs0pSrh/25ac7KREnjYANLJUbdVr9PqIQotpfqY6NbWaE5+e95KjA2Qzc8nMUeX6Si//Uozyp0bbKJV9wZ8/b3EFyj154mKnTlZhobtEL/fsCQ4ICDEzNaxfX9VpSI/u3do30+5KCanPn5OlQuw6WU+btuzO7Sft27cueCKP1BPQJP9LAVAgEJCHg8LGjh1w7Vo0m83SaqohGc3ezub7919r1/4XHrYL/0FECNWU2++ab7jaFZjwWGJFNLbNgt15a021A5N2u28DQBNIBAAAY28AeJQfMyqyaJZ20MBO8vWTXxBWJcutIQAASwLbKH9KLv4RDggMmThhsLgyQ4f2mOuxbqhTD+8VOwkCKAq2bV1MEBAT82r+go2SIRoa9U+d3OI+e3VWFk8gEAwa1N3GxkTqma6Fb3WmAChVVeU38Ym2bYfz+blBh9ZKPFg1L9qE8YNOnLxobm4oJ8cHIYQQqhF1ZC38P3E5cr/ky/r1VX+nRQPA0KE9JMN797br3bvQjwAAsLe3uXun0P3NHA479ddd0Xb+Q3wAABYs+Ee0IXrXe/m/kql42Y/F21G3H7m6jIJKVgs+iFoAjyJCCFWjOjUfpbZ7//5Lr95T9PS0R4wo5oFYSA5gIwX9LTq0SAS4euXij259HcWBvr673NzGKSlxxSEURZ08eZHDYffr16X6K4mk3H6rcOdtnVpYHdsockRHp8mLuNCarkUpoqOfXb16T7StoMCZOHGIsnKhxSTj4uJPny40Fm1srDd4sCMghGqPDs0TOzRPTA1/Obdnwf3Dy5zWTOvoqKmZ98ARiqImTlzYCuDAnlUEkVZDNUUF1kcAtlEqEf4qrX2uX79/9Oim9u2FAMSnTyx//8N37pwR38oEAM+evTp4cGevXkKKAgDq9Wvq8eMO2EZBSN5k8wT7Tj179Vutwjncvx8TEHC6ceOGzZp1BoCuXdsePFi+xVQQkg37UVC5tW1LX7BAtKCkYMqUb9u2BcydO1kygpERe/78HNFCTWfPUpcvF2qMplmPJOqrAo1GKCooLPofw8YkzXqkcsQumnox18rslXtzL0cLk36oRgUQ9VSqdscQ+jtQFBURlbjO/76ZoXozxYyyJ8zIeCL50tbWnKJeVXbtECqAc2b/ElXyQRAE4e7OHzl8i4dHodWNmDQI78vs3YcoKaHSkTU0dTX+matZHptUru6TUQSzV0f2lKHpvaZXWqX/CH6fUa0X8+bHqn33+Lnk2tn21sYanq6Rnh4vYxn9vtEM6wk/1Kc+aghfKFC/a7qaCAFgPwqqAIIoeCqHsTHBAOFbBYXGEovRPRQKR8/P6dWbIfvBHEw7q6yFWylejow4DOu6cIs/QvLgW0rWxsD7d599dR1hObSnIY0gAMBnx0oAcN7XJPElN5HeFgD8nL8Ntkz3dF3s47e2lBwRqmI4HwVVkPg57I3Vad8+U5JtFGsaTcCDz5+pJk1AxqfMvxBFa6ZJcOrUDC+E5BAvR3DwXJz/mdghjobhfk6KCtIPDXnxtWBKmVFjWT8bEKpO2I+CKoAQ96MQBJGZLeQWiUFSwCj5y5UxZiHQaDSNBoob5lRVHRFCBVNPHpgZqgdv6N+0kXLROGnZ9K9peacrk07pNcyt3joiVCJso6AKEvWj8Pnw+TvZgsmSfOuZUMjmQqNGUOwDTgFA6dCqYmfIyj3s+UO1ScybH6v2RfNzybWz7ayNNQCg2O9w3JeCbhVDDT6TLqyuCiJUCpwz+5eozA9Ccj5KRASlpspS/ZElGYFJgy3r6MUlRQhVh28pWRsDH+RPPTGgESVOYAeAF18LxltbNeZXfe0QKiucj4IqiCAIgYDYvp3pt2e15PInR4+GHT26rP+gbIoqqRulGBlOs4FGAwCiYT3l4IIlFrKW7RRcf0jx+OmDZtEMdZT2Lq3s/UCoTuHlCA6ee+F/JnaIo0G435CiU0+KepEkMRlFEyejIDmCYz2o3O7cIX19KYIgXr1i6em1Lro+24sX/LVr81onb96AklKhd1UfHpWKXzREjLtMTu46RkjeURQVEfVetOpJ8Ib+TRsplZ4GAAr3oxjjhFkkT8rSRsHejr9coS9A5842QuEs0baREXfy5GFSEczNW44bN038UlMTjI3168q3SO72om+/qJquAvojYaEdKyWfmDc/Vu27n7/qSSMAKOPXlaLg9Tepm3rk7nuOKqrWf5TYj4LKx9bW3NbWXEYEY2M9Y2O9aqsPWrB3ak1XAVXQ6sm7/zyTbylZGwMf3n321XVE61KnnhT14ScznUcTbatxSU1VwZ9XCaHKUrNzZmt9E0+ueLp6lfzWMgDw2YGTOUpVzHfS02V+3obrkmLT+OxYUYU1KhWeRn+r/Kknz4c4GoT7DS7L1JOiCg/0SE2YLf67lZGRtWNHkPhlr152FhatpOKsWrVHKCx0f9DChVNoNFoFaoj+ZtiPUqf4rJO+Uoh5eryszprUMWU8sErKbRs2rEej0VRUlLZsnm9vb/2v26ozZ65+/Jj0PfmGetXcbl3WacmoDsmfeiJa9aRf2aeeFCXZRinj6m3p6ZnLvf3sew5k0OlACdeumxQWurNdOwvJOEuWbPnftH9JISkQCAUkecR/j4fH/1gsbKOg8sE2CkJ/rqCVcOf2QU1N9cDAc85jFnz8cHH4sB6LFv5jYNgPgKqiHo9KyfTFo+gnd2/IjqOt37Jjj/6VURqSVO4PMOZNyqp90fxc4drZduWaelKswjf18MqYFZfLHT5hGpvJYrOYphZWU6ctf/zohFQ3yfSZc3MFQh6fz8vhHwss9FguPp8MCHgXFfWdRgMFBXqfPk379m0qVcTOnW9CQz8dOdJJRaUi/UOobsB7jxGqfL17dxo/wTM7O8fOzqqqy6qUfpR71yLadnJiMFgy4kSG7uvg2O/Py0IVlj/1JMl1hEUFpp4UK06yH6VJ2W/qIRh0OoNBZzDonR16HdnvR6dLP1prvrvr0lWbBAJSICCl3lq9Oo7Npvv5teFyGWlp/AsXvkpFiI1NTU/nM5nY7/K3w36Uv0Wz1CzejlPlTdUhMYW341hV1EcOlbSzzVKzigbKFhwcoafXTEGhWh5FVCljPRQoKKowmbLaKASNVrSs88H+R3etz83lA0X1cBo7wb3ESVEiPQyULr7JoITCw35rnWcsKDYOP4c3xForNPZHSZn0NlJTVFIhaDQAcJr078ipc0TZyi66VsufehI3xNEg3G9QxaaeFJNtLi3xR15WNAJaapRjATcGnS7+a2/XtYPjwL4jJojfJQUCr+mjHj+4Z2hiISALtVESEzNjY9MCAtorKNABQFWVNWKEjmQEPp/cv/+tl5fZ7dslfgfQXwLXmf1bNEvN5vmdLG+qDgB/URsFgLejmJVamjVvUPZM7Own0mhE06aNjh5ZU3lVk+XPmyjuwx0aNGq2f9O8Dt0Gm9l0BoBbl068ir3H4Sja9xrRrIVRfknSZX16F79n1aI94ffVNZvyc3jvXsaWWpktx69SFJCk8NCO1aNdi2+jiDKRndXusOj6DTXF8UXZShKSJI1eJYsdV13OxcqfevLQzFA9eEPfP5l6UtSrJBYpzOuM0a6fq8gu6yr4BAEMBkPUj8Kg0zU0m8QnfpCMQGcwLNraPXl4X7elqVQb5e3bdB0drqiBUqzAwHd9+jRVU5PVYkZ/CexH+Vt8VFPguAwpb6or4de79XWoivrIoSthkd36Sq9HBwAfo26VlrTgn8ebN/ZraqoXDa/C+Sh/3EgxMLUd7Dw7/sWj9LSfopCXMXf7jXAhCNpW7ykr/M7TaPRiy/r5/auCkpKaeiOKopgstqG5NUVRIYF+379+njx/5fXwkz5uY0IeJykqq07r39Zz6yGtFgYzh3W98Cr9v/Ve/BzeXOeeisoqy3YGP4q6vHfN4hxeNpPJWrYzuIFGYwA4sGHZ9fATALBgk39LM+uiey1ZGVG2/Byek43WkAkzPrx92aXf8A0Lpg4cN/3m+VN0BmPR5sBD23zj455o67Vavis49Mg+GZVc7jLy07s3JCkws+k4c8U2Gp0umbPDYGeuotL+9V687CxFZVX3lTt0DIyg4mR9fDFvUvJXPen051NPiir0uOMmZZ2MIlLQj8Kg87Kz2ByOVARSkEsQNAFJ5hYZ65Hh1avf799n/vOPftmToDoM56P8LT6qcTmu5W6j3I6L7eM6oirqI4duP39c7M5+fP6o+itTdpUw1EOQe9bPbNCwma1934IwIBo11mEwWUKhUNRGoYqUZWTZrom2nnMnA4t2na07OXTtP5zBZFm067LO4x+Kgid3rrc0s35y96ZZm46pP5KbNjcQd5BMnLM8JNBv7cELAJCSnLTKfeLag+ebG5rkZGeJ2h6Z6WnNDU3Guy+NDDnsv3G57/6zUlV2GdBe1Jnhu/+cqIlAUUBRkJXx27yt3YTZy/g5vMz0NAMTy0lzvI/sXOMxpvfWE9ebNtf3mup0K+Ks7Er+u3xLPXUNiqI2LXa5fPaYw6DRkjmnpiTPH9933cELKvUaxD26u9bjn+2nK38lvW8pWRsDH+VPPdGvlKknRb1IKvdNPWKiHhTR38f3CTrGNpLvkiT5/HF0lzmLBCQp1Y+iq6v0/n1WdjZZbFfK8+dpiYkZEyfeAYDcXKGb2wNvb3NtbcVy1Q3VGdiPglAVmjptRVjYzawsnrnFUDMzg4gLOyu/jD9upOi2NE5J+qLeqKmScj1xYMB2Txab02vIPwxG/tSHIo0UOo2+JiAs8fXzZ9E3zwbtDjv636Yjkc31jb4nfcr8nRr36O64mUue3L4iJAXmbe0L0lKU5HBO7P0oszYdmxsYA0WxOQoAwM/hsdgc+95DgKLMbDoGbfctuo87Qu7Ub6hR6AhQFFAUk8W2bN9VtM1ic+x6DgKKamXeRsfAqKmOHlBUSzObrx8SOvdxklHJG+GnroYGA0BqSrKikrLDwFGSOcdE30pNSfZ1HycqPCszvXKmBOXj5QgOnnvpfyZuiKN+uN/Aypp6UqwXXws6P8r7pB7xnFlSIIi6fuX8uZBdazwlI9g79G5pYs7j50rNmW3RQsnYWHXr1lczZhgoKjLT0vjh4V9GjWouenfIkGZDhjQTbQ8adH3rVhu8r+dvhm0UhP7I63S1kMtvB3XXA4CM9DtS7+7eVfyyb5Xoz8d6nt2723+E2/u3cYnxsfXU8yZ5jJuxQrOpbpGiiilLx8BYx8C459Dxgyw1vn5KbNyshal1x2thJ5RU1aw6dD203VcoFLZu10WcNm+YhsqrOUUJAQjJnEUjR6INgkYjBQLpcinpsR5xtiw2R7zNZLFFcQgajZW/TaPRBIJciqJKquSLJ9EXjvuvP3yRq6h8Yv+Wrx/eSeUspIR6rcxX/ndGsmjZR9hRX3ocRIygAQBQwieQN/Xkwzr/h2aGDYI39KncqSfF+oMn9RDiTpQjB//r1r3d6VNbJd9mMEw8vFbxSbJoPwoALFxoEhDwdvr0+wQBioqMAQO0Kr4PqE7DNkqd4jHnTWKGckuV1JquSF0jYwW8xgqs/Wfi7jz7umx6OwVODZxQf/4T/ldK0uvn91OSP+vom5WrrC8fElK+fTFr0wkAXj17SKPR1NQbUQAW7ToH7VjVe/hElgKXzVGIunR2yCQ3SiITGp1Bo9Nzc/kMJsu0jd2OFXM+JrzW0jXk5/AooVB0ww5VcrlQ3OwecUgZ/1tSJdPTfjVs0kxBUVlACqIuntFtZS6Vs6lNpy2eM54/vmds2ZYSCt88f2xYZLpMMYeu5HYMQRBQ/NSTqvU9nf4jI2+0hcMU6jTILXvarMzMAzs30el0Mpd/9VJo9L1iZtYH7N1GkkKSJAUkKbXmLJtNmzLFYMoUA9mlhIR0LnuVUJ2Ea+HXHT47lq4PeKTGFy6eXGhg2NN1uc8O0a95POAV4eO3BgA8Xeb77FhWbIQcvnB9wEOn2aGb59kbNq9XbJyq8+f9KP/M9w4N2tvW3kmjSfO8kNnriymoSFmUUHh4x+qPCa8YTBZXSdlz22E2h0tRlEU7+21L3czbdqYoyryt/bcvHzSa6kj2owDAgDFTpw9oV7+hxuqA8Hnr/ls1e7xAIGAwGIu3BjVo1FgcTdRbUsw+ltCPIpmw4OBIbufvSEmVtOzYLeJk4NKpQ9kKCs30WhXNWa1BQy+/Y7t85ubwskmBoINjfwPTP1oFh8FRmr/p5t1n31xHmOdPPamOU1VyZZSWmjl0Wllv6lFWVvTyEj+QXNF7yUFt7cZScVasmCnZLunQ2o3BqL6boVCdgf0odUdaes7xi29Pb+pT0xX567BZtMWT24RcSRjvecl9jOXwXqX8Oqxkf/zPmbaekWq9hk20DWSvj1K0rCbaer77zxWN0KxFy4jX2aKX49yWjHNbIk4YGpsq2p4423vibG9RHMv23bafui2ZzamHSaJo6hpN/SOfS5V75ukPqcqIsmWxOOKEktvmtvbmtvai7RFT5orSllRJOo2xePMhqZ2SzA0AzGw6bTl+QzJChcXEfNG1GPIrmZrYxSY3hX7k8OeK51VON5ILViVhZ/0KCvok+e7XVP2goMSS0mppFdwBFx1NRUdLx9TW7iEVcuTIB0DlZG6uZmZWJc/QqC2wjVJ3HDz3qmcH7SaNcAJ8zRjUTdfcUH3W2hsPX3yrznGfSllnlslmnT2ySXyPcbH4/Cx8NlCle/bsi36D9p9j4HiM9FqrVe194xagmrf9Je7T4ahPhd/XP3z4XTVXCRXRAtsoqC7IyMoNCn91dG2vmq7IX01XS+X4+j7rAx46zQ6rtnGfSmk3DP3HvdrKQpLMzZssXx621Gtq9Re96VUjyF9CuV8nur5SoYmrV8KvFbtcEKoeMTG/YmJwZiGuj1JXHA5/bWfdRKeJEh7VqlT6sWWziMWTbSTGfap8KSpsNtRqZmZN3rwJdXb2ruZySSHhubjgviFXZyV1JQXJCC9uxzs7T67mWiGxoCDANgrU9JxZVDly+MJDoS//W9695Cj4QVSrwuM+bat23AcbKaj83v1g8XLzntjXSFmgrlSOpWARqjb4VMm64NiFN61bNTTQUS09KqouonEfFSW20+zw14lV+HuIQnKv6j79Cov7IrF6Wzked4xQtZLT+Sh9+0XXdBXkTliobbHhAoHQ/+yLrfPtqrk+qFRsFq0axn3k8R9AJPdefJN4Uk9jXg3WBCEZytJGqbproKycF+ytgUlkcmv15N0lHa6TkW8NdVRNDepX2SeF/wiKVeRQDOrWwtywway1Nx+++LZsum3lj/vI5c90JIUo5YE71f0hvpRcBV+jfE8TRLVHrf9Y5bQfBaAOHNvqQAqp/06/WD2rXU1XpM6okq+drpbK8fW91wc8cpp9fvM8O8PmlXkzITZR5N+5mN/Fhu+cH1RS/2hVkxzrMS5xrAe/WzVIvLhxuT6FuvaRye+cWfkcxJU3564lNmnItTJqWFpEPJg1TGLcJ9J9TOtKHPfBMwWVV0YO/eOvvAf10WmUfiOcj4LkVM3OmaVK/pP13l/4V+zhElLCfafipg03KVNqJAcGddMNWt3jUPir+ZtuZ/MElZJnTc8HRWX1MeHVzGEdRdu7V3lM6mEcHj79x4/quL/05cvE1pajACA5+We//jN1mnVP3q2bdmESJcjSbcjnMMu6Cn4VEQqFvr67xS85HIsarAySK/I71kPhr8PSXIz6qKjAaGeuUXpUVDkq4Tupq6V8fH2v9QGPnWaf3zyvUyWM++CJIseEQrJg9V6JXw2dHAcP+9/s//W0qLofEiQppNPFv0JFRVBCoXDqlCFD5/dfcLJRaqhzZvR6Y5eZ5a1ARkbWjh2HxS979epkYdFKKs6qVXukniO4cOEUGq34X8VCIeXru3vRorw5iDduHCxXfVAdJr9tlOocZs/hZf+3bsn18FM0Go2rpDxgzLSBY2vBjN29p178O6qUB9UiOcRm0RZPtg658m6852X3MRZ/OO6Drfnq9PTetcAty/k52Qwma8H6QA2t5ms9Jnx5H0+SAiPL9tMWrafR6Hx+zoRuBv1GT/307k3nvsOzM9OP7V6roKhk1aE7lf95GVmWew5ZZGT0goXbsrNzWCzGyRPrdHWbDhs+//XrDwIB2alTa78dC+h0Go/H19B0dHMb+fJl4hjnPr9/Z3qv2KuszO3Vq4MoE03NBv372y86rUjQ2SwtO8GPWCPNnGJLSUlOmTT3o65us5MnLy5btp0kha1atdizx1tdvd6PH78WLNyg19IkKyMjOzPdd9XeiAt7WrdupaHRadascS9fvnv37tPDh8//me5GCsmPHz48un/3R/K3Cxdu7t7tbWysBwCRkXcWLNiQnc1jsZgnT27dsyeYx+M7OExUVVU+eXKrvf1YHu8pABQtmsfLkSzFz8/Lxsa0Ej5XJK/kd30Uiqq+P+8ZzinfkvZffHL4Vvz6wxd/p/6silJIAVnhtEVdu/+ZJIWdbaQfN4pqi0HdWgStdjwU/voPx31qfCDy7/n7lZK8afFUN2+/rSfvrvKPUGnQiAKYvGDtpuBbW07coSjqxvmTopM1KzPd2Lqjxzp/PaPW/pu8VuwL3XDk+q+f36U+r7JLSkoZO26J/4Flz2ODo27t19CoDwDbt81/+uRIbMwxiqKOHLkgivn7d2Zne+vjwWusrY3mzd9y7eruRw+Dvn1LkcztxVcOJeBlPz/IMRjUSuLGY8lSxg+209BQ//QpydXVOzR0V1xcaIsWWvPm5T8Qm4Kh46eu23Nk+lwv9UZNpk7zFgqFv39nODh0OHZs47JlMyiKmj5z7nDnSe/iX+86dJrBYKxc6T5x4iIASEr6MWbMvH79prdps9jMzH316vcdOgzjcFiRkQdOntwKAAIBNW7cnaFDw8eP9zp4cKtU0ZKleHltq8Apg2qRKu5HKeUXnqx3q+3X4btXsc/u3Tx6J0GBq0RRlGo9dWfXBRRFLXcZ+endG5IUmNl0nLliG41O5+fwhrZpNnDc9JvnT9EZjEWbAw9t842Pe6Kt12r5rmAGk/X49tX967142VmKyqruK3foGBjxc3hONlpDJsz48Palw2DnyNNBUnmWp6aFDsieEy+mDzchCOnwEpJW08FE5aKrpZI/7nOhwuM+2I9SbeIe3TG2at9MrxVFUSw2BwAoirodeebWhVMAkPbru4Kikn2fYRRFMVlsszb2FEW9eHLXzNa+fkNNiqK6DxzzNu5JxT6vW7ee2NlZmprqAQCXm3dLzokTkUePXQSA5OSfKiqKY8b0AQA2m9W9exsAiIp60q1bm6ZNGwHA/yYNevhwtTi3F19oaeHj2c0d2bp9jRu/KrYUJoOuqKgQFnatSxdbHZ0mADB9+qju3SeIYhIEYWxmyWDQW+gb8nN4qbmEoqIVANjbjxHnNt/dtXP3nj9/pqxa4kGSpI/PzvT0TAC4deuhurqBgkJjPz9DLpeRlsYPCyv0OEM6nQgMbH/s2PlPnywuX85u3bpQ0Vwux87OGgBMTQ0SEj5W4GCiWkR+x3rKeCKfPbSHl5khO063gSPVNZuU9O6b2Cc6BsYcBSWpEv9dvqWeugZFUZsWu1w+e8xh0GiKgsz0NAMTy0lzvI/sXOMxpvfWE9ebNtf3mup0K+KsRTv7nSvnrTt4QaVeg7hHd9d6/LP9dBRFQVbGb/O2dhNmLwMAo9a2UnmWaSeLuPP0W2p6jmMHrdKjospU+a0BNotYPNlKYtxHr/yVwjZKNaEoIQGE5AF/HfPgcsihFXvPKXCVzh7y+/Y5UdTzyWSxCQDRNoPOECVh0BmiXKRylfpe+fmd2LgpCAC2b5vXq1f7gqIL/yC5ezdm/4Gz167uVlbmbtwYlPDusygrDocljslkMvI36OKCPqbQ35+cTOM2VLZfpcQmterxC+1g4VIoqsSVXRh0OoNOZzIZQiHZsbNj2259w4757z5zCwB+fv+2cvb/XsbFNdNpoWvQcsnqbUO62YSG7mKxmACQnMz7/TvXza2lggIdAFRVWcOH60yZUpCzqECKKr45x2Tm3ZFEoxECAS7hX8fJbxuljFfej2/e9BnqIiPCi2e3v7yPV9cocUyEooTFFncj/NTV0GAASE1JVlRSdhg4CiiKxebY9RwEFNXKvI2OgVFTHT2gqJZmNl8/JNBotNSUZF/3caLkWZnp4quVZfuuovyLybNCdh1/PnWYMa2UVaHkRZEZdnYWFi2l4qxatUcoLPQRLFw4uaQZdnVP/jpvUQ9fJC+b3qZc67xhE6XaGFl2+G/dws+J8U109HP5OUKhMP13qrqmFkdBSSAQ3Lsa1tzQRDw4K/pvS4u2QX4rednZbI7Cg1sXoQyfl4vLUBeXoVKB9vZWM2dtePXqHUo7twAAIABJREFUfcuWOjweXygU/vqVrq2tqazMFQjI0yHXLCwMpJJ07GjhuWRnVhaPy+WEhd8SBVIU9c8/3gRdScVhGwAYNc6RvIpIliIghVlZvI4dLd3dV33+/K1pU419+453795eHJnBYDAYdAadDkBoaDZ5/fZdoeIJwqKtHS+b9+p5zPNnjwFAKBQ+eBBrY2PaqFHLnz/jP3z40LJlCx4vRyikuFwOnU7n83NFjRgAWLTo6ZMnubGxz/z9VQBAqmj095DfNkoZe0QZTCZXSUVGBDaHKzs3PSOL92/isjLTFbgFTwF98ST6wnH/9YcvchWVT+zf8vXDO9Edg0wWW5QVQaOx8rdpNJpAkCukhHqtzFf+d0ZyFyT7hIvNsyz7KOXpq5QvyVn97HUqkLZGpKdnLvfead9zIINOB0q4dt3/wkJ3tGtX6PbCJUu2/W/av6SQFAiEApI84r/Hw2MSi/W3tFEgb9yn5/qAJ06zIzbP61j2cR8c66k2qvXU/13ut8lzCikQ0BmMOav2m9t2vnr2yOrZziyOQtPmBhSVd9ZD/udSv2HjYf94rPh3aKMmOsoq9cSdA7t9Zz+8dYkk+eYWo8zM9CMulDKvQkOjfmDAcucxS3JzBUwmI/jYKkfHtv4B5wYOmsPlcoyMmhdNoqXVyGvJP716u7Vo0aR+/byL5P37cRfPhNAUNb/v0QOABKv2MGNBsaV8//p9yvzvurrNtm5d3KfPVIqi9PW19+wpeD6zqB+FTqcRBPCys1gcjlQFSEEuV7H+Qp8N/23fQJKkpeWQwYMdbGxM69VT69PHxdnZI29fgjfp6jZzdR1tZTVEU1M9MvIAAPj6WggE5m5uaT16TK5XjylVNPp71GgbRea1tdTrbujhfW+fx2Smp29bMfXfJbsBgBTk+m9bBABNmhk4DJzAZLLEWcnIrUUrMxPr9hsXubh5b1VSUUv7+SP08B5DM+uGTZopKCoLSEHUxTO6rczFmZT0X1ObTls8Zzx/fM/Ysi0lFL55/tjQzFoyQnrar6J5lkP+4fI7Gjt5iBGdVpt+QXO53OETprGZLDaLaWphNXXaisePgqW6SabPnJsrEPL4fF4O/1jgPsm3+HwyICAxKuo7jUYoKND79GnSt2/B4N3UqfczMwU0GgEAHh6tzMwqcxXX6sRm0fLHfa6Ufdyn9nwL6gKzNp3XBFyWDHH3LfRdpShgMNkBVxLEn4t97+H2vYdLRgCAKQs3AsCBZcfDQm3KWLSDg+0Dh0DJkGNHV0nF4XBYqb+uil+OHdtn7Ng+khFsbU1cDiWdepR3jswd/AWg0HRacSmerj66us0AYOjQnkOH9pSMw2azGqg3EHWiNG7c9Hj49RWL3HWMbUQDPQBQv6HG2gMhS11Gd5mzSN/IdPnmveP72T19GiLqJtHVVQJocfPmMdFYj4ivr7uvr7toW3RTD4NBLFo0NCPDIDCwoAeFw2GnpuY9zU1LSzM+PqIshw7VXrV4ndmc7Oz+I9yUVeuf9F8nCiFJ8uf3r7OW/Xft/OGzh7c6jZ8rzkp2bou3HDqwYemU3lZAEEoqaoPGuVh27BZxMnDp1KFsBYVmeq0kM6EkenLF2VIAag0aevkd2+UzN4eXTQoEHRz7G5haSSYpNs/yHpYXCb9ev0/btrBjOdPV+L9jBINOZzDoDAa9s0OvI/v96HTpOwbnu7suXbVJICCLjjGvXv2Czab7+dmIZthduJAkFWHzZmt1dRZUueo4jIO6NTc3rD9r7e2HL5KXTbcpfdwHGym1W3V/fIWeeNw4u8IVEJ/RpEAQdf3K+XMhu9Z4Skawd+jd0sScx8+VOqNbtFAyNlbduvXVjBmGioqMtDR+ePjXUaPyOobT03N//xY0baogFFKXLiXp6ChWrHqobpDfsZ5ST5wWLU2irhxLeBmr1bzQ8kFMFlureasHUecLZSUzNzaHO23xummL10kGLt58SKo+LBbn1MMkUVbmtvbmtvai7RFT5ooimNl02nL8RklJ6DRG0TzLyy84btLglixmuW4IkguinmHRX3u7rh0cB/YdMUH8LikQeE0f9fjBPUMTCwFZ6IqWmJgZG5sWENBOPMNuxAjtaq58NdPVUjm+vsf6gCdOsy9untdB9rgPjvWgssslibff2eKXf/DEY0J8Oh85+F+37u1On9oi+TaDYerhtYpPkgKSlDqjAWDhQpOAgITp0+8TBCgqMgYMKJj+z+MJ16x5/usXnyAIQ0NlNzfpuWvor1KGNkoNXQBLvfLW12jcqIlWwsuYJs0KlsBKjI/d7jOdIAjnaUsls6ob1/G3H38/eZWyzr1ttZb650eOAoLIn2HHoDPodA3NJvGJHySj0BkMi7Z2Tx7e121pmndFy29Zvo3P0NFRVODQZdRkwYLHFEVYWalNmqgn2YFce+WP+ySO97zqPsZcxrhPXfhmo+ryJpmTS+bNkm1aL1dFoYL3xWRlZh7YuYlOp5O5/KuXQqPvHS0aJ2DvNpIUkiQpIEmpNWfZbNqUKfpTphSzemHDhuytW8s6/oVKUfuvDjXbj/JH66M8uH6pmbaZ0ziPS2f9bTr1FgXq6JnM8NxZTF5Fchts2YirpEzQaAAwaJzr0P/NGmBe/+yzn+XagepF7Tr+fFw/Aw6bXhu/egX9KAw6LzuLXdwMO4KgCciiYz2l7OzyZaYaGgrZ2YItW1/vP/DW1cWwUitekyTGfb6XNO5TN9rfqHq8+CLRiaKZXbFMlJUVvbym579S9F4SqK0tfePkihVuku2SDq3/ZTDqwo8HVM3kd6ynLBfeDwnPaXRmxu9fpWRVQm7bTt2up64hLm7twYtS0YQkWc5l1sqqAjl/TMq4+eib11TrqqhPNRD1oIj+Pr5P0DEu9FOJJMnnj6O7zFkkIMncwj3DurpK799nZmeTJXWQaGoqAACXy+jbp/HefQlVtws1MvNDt6ny8XWO6wOeOs2+uNmjg2Fz1SK1qv5KocpTvV+qjz8Lpm3p1OdXrHQlJe78+f/IjrNw4RTZERAqC/mdM1vqydN94KhfP76d2r998Ji82eAsNmfeqqDia1FsboXXmZ83tseZJyn8HN5ouxYDx7h8THhl39tpi5drv1FToy6F0OkMj3X7j+5c8/bF02a6LT23Hj4ffODHt88TZ3vfjDi9Zu6EY7c/KiqruA3tNH+9f9Pm+r6zxnx+H08KBCbWHVyXbBItUyvOuduAkQqKygGbl+fwshSVVGYs26qtJ/1QLil7TrwY01dfWZEpO1oJav7fsT+dYbft9QxXg6Iz7LKzycxMUl2dlZsrvHwlWVdXCeocNou2eLJlyNXE8Uuuuo8xH95TV/Jd7EdBZafdoODpPB9+VsM0c4T+iDz3o5Ry5VVSUVNSUVNRa6DRtEWpWRWXGzVzmL2oM2P5rpPaEjfvZGWkm9p0HPOvJz+Hl5n+W8/YYtxMr+C9Gxb/r//6Q5FNdPRW/DvyduQ5M1u7zYunUxT1LPqGgYllzP2bJtYdUlO+N9HRoyhquucGtQaNKIravsztWlhw1/4jJXNO/fl9yeRBvv+dU1ar//JJ9MZFUzcdvSZjFwQguHj38wW/3qUcNflVeIZdt3anT22WfJvBNJM1w26BcUBgwnSXBwRBKSoyB/RvKn4rI0OwdFlMerqARqPMzNSmTpFeyarOGNS1ublB/Vnrbj+MK3S/D7ZRUNm11Choo7z8Jj3eipC8keP5KGXL4kPCi1MH18uI8OPb535j/ik2t03B1wvGevL/SwEwWWzzdl1E2yw2p4PjQArA0My6mV6rxjp6FICBqfXXT4mdeg358e1zRvrvl0+iR7suenLvOkmSpm06ibK6eTHkRvgJAEj7+V1BSaVL/5GSOcc+vJ368/vaef8TlZ79f/buOyyKow0A+Lu316lSBEQRBEGaBbHXoMbEkhiNUSEajV80do2V2Hs3NtSosaPGFo1KrNgVFSs2sHcURZR23O3ufH8sHOcBxwEHd8D7e+7hWXZnZmfL3b03OzubmqJ7e5MEH374sloFS7EptIgUgnYPu6htOdNsWrOM0dHD7hePfr/k3sNuRVh56WFXrbLlzvlfLth4o8vIo+rrPhiiIP1Vr6gQ0YTvNvvigzhZQVtIcTh5ZLpMtx1Fz4/eSWG59CfXt7SczxQmBAgRazxrQyQSQ9ZgsmKxRD3NMiogxCeg0dlDu80trWs3bLl95RzCsbUaNAdC7t24fHTPpjnr/5OZme/duDz+xRPtkjmumpfflJW7tWrYwS/3MXNt3OuN+/X2qD5phL2g1/aaEgsLs0kTf836Tz5twsZcethNG6I5Fn7jWqbZw8744YBETI3/pfbeyMeNvvw98WE0AEREDMg1ZfjpVyVbNZSnkOZ5Pi+MogEACBtVMjURC4mbXUbcG37wa4iNFwe6ppXMqhEqBH1iFON8LpfAr8M8QpTstef1FwCAACHgX6/Z9j/nfdnlJ7FEJpHKLxw/+G3PwYRAyqcke8cqUrk5wzDnj+938/LXKtknoPHyacPvXr9Uo1Z9wnEP7t6o7lsnqw55bnleD/cqZkU9EubmsrFj++ouMzT0l+JYdcEZPwrRR6cgt+8eRus+VUrHlpQbpvO+ruGYHpd1lSf2jUxnjIInkSkoylEo9UfQuH1mi3TvcdHl7KdCsmapx4fVmObjksxpfr5/vWYrZ/zmX68ZIcSvXtO3r59VrORCCKnVsOWxvVumD+kukcqquHlmlZtdmpWN/e9/bFkzd1yGIp1jmQZB7T18autZ68Jta6FyoVIM+6mgXNVwzPj3Rub0vXjskoJMmule6ynuT9i/o15prWXX5Tf8UwO3nXvGz9ec9gts4hfYhJ/u8vNwPq+za/V9N5L46R4DQnsMCM16yiA9et56rc3RLA0AfAIaz99yrMS2F5U7eEah3Hg7ZQ+Lcve1zIg1QShfphuj4C//nGxtPcO3vilortdJHoXIlZ03/Gnh8pY6ujf2dZJH+NbXJVkf3Wxt8xmqDkOU0sLW1rMkT613GR8BMu+FvP5Ukteqy9V734hq1rQqvY9BLQGmG6Ngu0JONjaeW7dpP05PDx6FyqXOW34+pzy2bn2ia2nhd6Ph2djkG6PgO6h0KOz7upAIUALPJpxACACpjGjjjiQRm+tTe3S/HZChuGKMokOpv/e4XElMjAvu8XNBc0VGnAtq17Rwa4yMOBvUrlXh8pY6kRHHg9q3znPpwWOF3o3FYdjwON0JMEYpLRIT44J79M0/neG8i015npb5vdjoa3dPi/c500RGnNXxdkBFFxOTFBOTZOxamDpsRylN3r+PCwl2KGiuu+cfhAR3Kdwa755/EBJS4KiolLp7/kFISJ5fFXfPPQgJ/r4k66Pbjz3ziVEwzC8t3r+PCwl2LMk1Ru/gtl/OnK7s4xzSLJfRq3W/HVDRhYcDxij5KsVj4aOCwJ1pEKVpN2KUX1rYuAcevfCiTSPn/JMaSA3HNAAbfvpevLR0ndioXDHldhRj1wCh0gzfQKVFasLTOetuxj75OKi7d8mMlVJD89YevP0YmTAT7o9SXoOU/D6kyuluQTnpPlXK7TvINOk+WLsWBg2Zc+Hh8+TZwwOl4mIfYdnbMTtGiY2XcQQERhkeEqH8YDuKadl56V2u89dP2Xlwv38JVwaZMsKeB4D2HW90GfZVHinK5VvIJP11+HGu83cvOXRwfy1+et3U5pPCrvw04VRYaGO7CsXbtlHRgrE1Z96nCAEgTSl4niipqvE8ZIRMh+nGKPgJi0yPKZ6T+EYp5TKPn1hEzRkeuGn/g66jji8b18iveoViXatXxfTzKRb89N14aVXbXG8/RsjITLfPLLZUGxTuzDIL3yllSa+OHi5O5gNmnZ/Ur06bRnk+ibDovJ3Szz/KjFFi42Vf+eINJsgUmXB/lBKrRamBu6T4lcJ9jCFKGdMy0HHt5KYDZ16IfZJUfL1oNbvN5vnUHjy1ihXJ+pvrfta9VHeZZYjpXuvBX4cI6QXfKWWOl6tVcfei9XLQvLUHn9qDTJTpxihlLx5EpZ8pnpQYzZdyuR++CpaidVObTgq7mtWLVmLYtXo7pVNUZnz78K1UyVBiIWfYVSBUdAJjVyBPBGkw9tFApovgq9S+dBOLBHOGB7Zv5tJ1VOSt+x8Me9qYS1hnayU/zXDUgwQcJQWZIuP2mdW1FL+YcyjKDsGdWWbhO6Vs69XR3cXJbMCsC5P61TZsL9oaDukvPoj56XvxMh+nNAMWjpBBmO61HvzgRUgv+E4p6zR60X4c1L2GoXrRejulHbtnxU/H4mizyCSZboxSPoOUkOZ5/k6iaAAAwp4uudqUR4Vv+TOW/auOGbsKqCj0Oqm8XC12LWw5ZM7Fh8+TZw8PMEgv2hoaDSd3X8tyq4kpnvBlCMn6m+t+1r1Ud5llB957bHJ0NN1TFFWOdwzKxcH9fsauAiohFSzF66Y2mRR27acJZ8JCGxW9F62XQ/a4bffe4K09yBRhn1nTwm/7vHnzZsyYkZGBo1MjhLKJRYI5w+u2b1al66gTRe9FW72iQkRnfua8+CBJVhT7c4IQKih9YpSidFovdJd2AELK4wsAAEJCQuLi4vz8/CIiIgp/bEviIJaxF0KlQK+O7pMH1BkwK+rohVdFKUcs5NzsMptSCMEuKWVSqf+4M93+KOWyO0omZ2fnTZs2RUZGDh48eOXKlcuWLXN1dQUAW1vP8K0JBS3tdZJHIXJl5w1/ltfSmjWt/P2tClcyQqjQWgY6rJ3cpOi9aGs4psdlXeWJfSMPdE01XB1zcerU5aiom/y0hYW8T5/vZLLPAqOrV+/8998ZzTkBAT5ff92sWGuFTJkJ90cpz0EKAAAEBQVFRUU1bty4Xr16UVFR7u7uNjaeW7cVItrw2LrtbWFr4bF129O8l1YtZzFKeT8nkekwSC/aGo7p/97InL4Xn2u3WUM6fPh05Il1AQEAQD14INmxY29k5DaBILs5Pyrqxo6dq774gv/4JzEx3LNnHTBGKc9MuR2lvH8f8O0o7u7uBw4c4NtREhPjgnv0LnA5EReC2jUuZB0izge1a5VzfsytpJiYj4UrEyFkEFm9aK//NOFsWGjDQvSi9da+tafYtWhBDRpEURRFiKp790cbN+7t06ezZoKAAOHYsSzfPW/TJnjyOHP+x8AQylwOfEAjFloeCgOOU6zdK+3XGQBIhvJTi1+sojbmtV6iyFAs3aY6fAFomjKTibt9KeneNpdkeZSTVKeH9bVtujeNJH5KmxDG3HpACYXCBn6yyf0pqTjfHYJ0M90YpTz/ZH358mVoaOiFCxeWLFnSrl079fz37+NCgu0KWtrd8w9Cgr8tXE3unn8QEtIn5/zwcMAYBSGjE4sEc4YHbNr/qOuok8vG1ferXqFA2Ws4asQo8XJD104XgYAaPlw5aMDUn/tO1JwvoeHrr0VNm+Zy9cp813yBnXX2/wQyVu/mY5R8pY36g5JJLfb9QZnLSeLHjJ2Gv2OfcJy4axuzZWOBZVN/W5ixdo90cHeDr6W8Me44szpzluN2lPDwcE9PzzVr1kgkhnpIR/ndmQiVeb06VnNxMhsw6+KkfrXaNHLSP6OLTYZczKYpaQBITBUmJAvtLZhiq2YmiqL4DjQNGlCKVCZBLjfTWHqMZX8fozx0TpjvV0D60q1EyaT0nUpZyOVzhwGAYvl21eELACCfPZT2c1enZOOeMtF3LCNXU3IpAFA2VtL+XQAgdcQC7ulrYFi6rrd8wv+Azrxelr5gE3PuBggo+dQBmuUAAHPxlmLJVqLIoMzlssn9affK6kUCO2vBF4EAALRAGOjLPsizJx/Snwn3RymxWpieMWPG5L2wPO8YoyuWnd++453iKBaVjIP7fYxdBQCAloEV105uNHDmxdgnSYO6e+nZi1ZAgadD+vXn5vy/d+Pl9hYl1D5KUZRIRNlYCN6lEjON2gbR9JPXJCUFzMy0s6T8MIYPI2j3ymarxsuGBivD/zP/azIAkAwlSU6lPVykg7sr959WLN9utmq8OiN79zFd3YUPUDTJJ/xC2VoBIWlT/1RGnBN3bA4AJDmV9qwqG9WLuXQ7dewSywNLIKt6JPFT+rwN5n9NpqwtmOuxaeOXW2yfk3PTSIZSue+kdGiPou8lZLrXesptO4qhBrpGpci41f2NXQVUGHP6/WnsKmTzcrXctbDFkDmXHj5PmT28jp69aL0ds2OU2HhZ8+rFG6OoG1F4qQqiFYqwmclIzq8A8x3zPrvWo1WyRCxq2wgAhHW9FX/u/mxZHl8mysMXVP+dBQAu8RNlLoeOzQEAaIG4fVMAENb3BRXDxb8XOGVeYWei75DET6ljl2TVPj2XQlkubcwSYZNaIr5NBRWN6cYo5fPm478OP851/u4lhw7ur1HClUElhiuXZzsyuAqW4nVTG08Ku/7ThHNhoQ306UWrOSL+vZLqksJHKomJwDJgJ/jsV9k5lnWrRMnl/IhRBXlfiEWZDR40DcxnV6xobzf2/jOSptBsSmFuxCn/iTTfMJUyk2Vs2M+9fJNLmYTA5z8aaa+qmi002lg2dexSysZSNqpXAWqO8mbK48ziS2toN1RmEY7DV2l8GfvEyQXfi7Z9s8pdR526dT8p3/RejtmNAXfjS+LWHnU7ysGDRCwTytPSNF9dmIzRUwV6RSe0AGgaVPl3oKG9qgoDvNMnryLJaQBAEj8qVu4in1IFTnaUmQxYTnX8YnZqllMePAsAzKXbIBYJHGzUS4R1vZmYB8z1WAAAjmNvPfxsNYSkTVpJSUTySf3yrzzSj3H7zOL4KAVSlB2CO9Mgims3chweoNLLFI9dr45uWb1o/XX3ovV2zB63LTZexhEiKP6rzRRFKRTU6tXCHXtWtGhRTz1/xYptly4v/CJIpflsELWU70dD1mAqFv/+QZnLJcFfJX8/mrKzNlsRqnuN8kUjFYvDk78dAUAoS3NJSDtR41rKvSdSB8+hZFKBRtdXysKMe/Y6udtYUDFmc4dptqNQtlZmS0anz90ACiUwjKh1g8965t56qNx7UmBf4VOrXwFAWN9XPmdoYfcQymS613owREHlB9EjRiEcx5F8frgLBDT2Z0K8loEV105uOHDmpdgnnwZ198zrxKhoobI1Z96nCAEgTUk/T5RUtS3GJ4WdOkWSk1mKom7eFLdo0VIzQOFdvcrMnZv5drh1CzyrZ863ig7PWZp0WLB0WHBmgqxBTQQONpaHwrRSUlKxbFwf2bjPRlIwW/ibdjKJmC9H67Zh9eAowkAfi22zc9002t/D+vauXBehQjPdGAWDFFR+6NMfZVHoQEvrijoSMCplBXu7br+ONFy9UOnm5Wq5a2HzIXMuP3yeMnt47bx60XpVTDufYslP3403K74YpW3b5lZWmZ1ea/pb9u2rPbRJw4a1PnwYoP7X0QECAkzitilkLKYbo+C1HlR+6NOOYmlt/22P4ToSKNJSzp38W7Oow7s27lz7B6NSEkJafxfSc8gE3avo4Gd94FYS4bjtqxf0+DX3G+CVGYrujV33XInPq5AMRfqGPyafOfSPQEDLzSw6BP/SIbgAl+f/27Fuz4blltY2C7ce4+ujf958aW2awcs3QRUsxeumNpoUdkNHL1pvp7TzjzJjlNh42Ve+xVWZFi3q5Ww40RQQ4INBCdKE46OUIrhLjK74+qPouojz/u3rY3vCn9y/vX/78rbf/U8skQLAy6dxKmWGjb2TpXX20MOEEHVRL58++GvBhLB/Ltg6VFJmKJ7E3da9FgCYv+UIx3Esy2xfOa9bv1F5V5XoKGrW8J4SmXzV/mi5ucXHxHf/7ViX73o1/btlVeiija6evhzH8fXRP+9n9WRZAa3dbKC1aUUpX4OpvzHFImrO8Nqb9j/uOur0snGBftW1b9/9/NaeYn9qD0L6M+p9PTqfGk2Qhnx2l+4XMnm6j37C6+f2Fd2HTVorFkszFJlfJ6sX/BZz5dTmsEkH/g7LtaTEhDcyMwsrW3tCiEgsqe4XQAj5d8uqdQsmEkJO/7enva9lyqePhJAhnZu8eHyfEDL6xy8JIRv/mKpUKkJ7t58xpAch5Or5yCFdmvZvX3dQp0avnz3iz8ZNS6b3a1enX7s6cTFXNKv6OPZWzOWzQ6ctl5mZE0IsK9h26z+aEHL28N5fO9br1z5g+uAeHxPfEUIyFOldAh03L50xa0TPYV2b8+WsnjPu5ZOHy6YM3bh4qro+hJDj+7b2bVtzSJem6xdNHtSpISEkMSH+5y/9+KVP4m4P6dJUXeamJdNmDgu5eCJi5rCQgd826N++7tJJQ1iGyblp6vL1rF7ub8xSoldHt8kDag6YdfnoBe02MC8Ho42Ij5BuxR2jFOGbs9BfyWXyVYwHAgMc48v3FtfLZw7sWDfn1rWz6ixisbRj98GDxq+4fPY/9UxCsovyqlnPqYpbn1a+88f879g/4cqMDI4j/vWaXY86xXHk5qXT1X3r3Lx05lPSh6T3CU4u7vy9RRxHfhw6USyWzPhrf+ji8Pdv4xeM+d+ImatW/Ht5fvhRS5uKHEdSkz+5eHiv3H/lh36jNy+doVnVB7evV/XwlkjlmjPfvn4RNm3E5BU7V/4bXdG56tr54/n5aSnJtRq2HLtgY/DAUL6cvqNn2Ts5j5zz149DJqrr8/bV8w2LpszbfGTxjtPJSYnqbQSNjVXvw7SUZN+6TcYt2lz/i/a/jl+4bM+FsH2XOI47cWCH1qZll6939XK+SvpEKRq+F+2cdbeXb4vVDLC8ndLUHWofvpUpGdMdkwKVN6bbH2X/KsM/8wmh/BjnW0d3fxR371r9J8zbvnLer2OWyM0z+w2wjOr6xeOxty75BWQ/uZ6Q7KIEFD3tz71PH9y5HX3u4Pa1h3ZtmLP+vyrVarx/8zLl08e71y8FDwi9EXWSZRi/wCbqXIQj/DT/93b0ed+Axi7u3oQjYrEMAJQZCrH5sWKtAAAgAElEQVRE2qRNJ8IRnzqNt6+ap1l5jiMkx+bcvRrlX6+ZvWMVwpF2P/Qd/78O/FokUplPnUaEIy7uPq+fP85cLwEgRLM+d65G+ddvZlXBnnCk1bc/3rtxWauShB/tiyOEIyKxpGb9Fvz8s4f+OX1oNwB8fJ8gN7No2b6bZi51+QWqXmnn5Wqxa2GzIXOiHz6/qu5Fay5hna0zXnyQAADDUQ8SZD5O/A3JZWGTSwPd+7lcHwUT7Y9y8N/qeS0qx8r1mWoaiusQ6P7+e3Q3Zu+G5WKp2ap5w/qPWWxuYQ0AhJAMRVq9pl9X86qtURDRKsqlmrdLNe9W3/7Yo6lL/IunjpVdves0PPPfHnMLq1oNWm7/cy7HcjXrN88rRsn1S10oEgMBQghFCViW0Vxazavmswd301NSpBrPieNyK5BwhBaKsvJSmuWo65A5TQDUsRcfwnBEIKA5juNnqjKU6lwisYSvW+zNy0f/2TzrrwiZmfnezcvfvHiitWnq8gtavZxHT8exM0EVLEXrpjaYFHbzpwnnw0Lr8b1oazik8TEKANyLl/k4pRi1jghlwjY9hIxP96UehlHWb/5Nn6Gz/eo0VY9tSgtFDVp0/CxAyfwqz8z16tnDmOiz/HTcrSsURVna2HGE8w9stmP1PL/ApiKJRCKVRZ044BvYlE/G14QSCAQCWqlUcITzDmh4++r5549jOcIpFOnp6an8bdJ8epKVRf1yqe7tXbvBsqmDkz994AiXlPh2+59za9Sqfyv6bMKblxzhDu/ZWLN+C45weZWjWSA/7VWz3s3Lp5MS33KEO/7vVkKAI5yZpXWGIv3Tx0SOcFfOHSOZubLLTP74wc6xskQuVzHKC8f3E0K0Nk1dfoGqp/UqsTPEsMQiwZzhtds3c+466uygfqsmDF6SEvOvK3uxjmpnK+Wic+vmTxi8BAAmDBo/YVDe474jVPxM91oPQuWH7nYUqwr254/uP33kb3uHKvxNPQAQ1OHH3ArKLorjuJ1rFywef18oEsvMLMbM3yiRyAhH/AKbrpo10i+wKeGIb92mb189r+jkotluAQBfd/vfb91bWNs6TF31z7DpqxaF9mMZFS0UjZ63zsbeCTRbHYh25UfNXb9l+fShXRoBRZlZWHXo3t/G3ul/Y+ZOH9SVEOJUpdqAiX8QLvMRD7mVQ7TaUWwrVgoe8Hton6+tbR3cvPzNzC35pb2GTp4yoHMlF3c7B+fM7Bpl1mzQ4vi+8FnDgsVSWWU3T/VVMM1N4xMXsHplR6+Obk52sjWrXoQtcQN4BPAoa4kTQObQtBNG39PMYm5Rz97eRiCgLC3Nlywe17x5YKvWfWNjHwOAv7/n2jXTnJ11DeGDUEHpE6MU5Z2Jl9lMhMEPIsn6iwfRAHT3vrRzrNJz6OStYbM6/5h9P3DjoO9ypuT7k/LTDs5uE5d9Nuolv8jJxWN39Hv+3279xnbrN1adZfv5V/x08MAJwQMn8Gn86zWft/m4ZjmbTz7mk1WwdwrbG61VeZFY2ue3mX1+m6m53oZBHRsGddScQwvFuZazdNdFdVXV9Wnc5ruWHXoAwI7V8zz86vIzW7Tv3qJ95mCgIYO1y6Qo+rfZf+XcfM1NU5evf/XKmDaNHE+FJwE46p/lwvlwR0e7TZv+Dflx7PNnx9evm+Hi4kQIGT9haejvf2zamPsYrMhISv1Ji+0oCOmv2Pqj6HEXK6NSJsQ/05EgIz0NoJTdEKunrStm3rl6nuNYB2fXAeP/MLFtNKnKGNhr2mfB4eyH6onrjl11vrK5mTzNoltSlbQ5By2FQhu4CwTIFWXbFHmaZmKUl8Ye6Y3d0/NPhzBGQagAiu3LSJ/f6DUbtIy9e1F3mtoNW5XJn/s9h07V/Ne0ttGU6mJwrymfiKPZYYckcNyf5zOnzRtNWHJCM20HMIOFR0uydqVXIsYoesIYBSHj06evg19gs3zT6FkUQgiVCiZ67zFC5UrpvUMEIYSKT3HHKBiFmAg8EAZhnPFRkGkry8fOidwJapOo/nfW7NVDh/5obpY5Xn56uiItXWFrY00IOR4ZFR//7seQjnmUVN6dfyS78FBm7FqUPnitByHjwxgFmSYn9s6ottkxypTv5/7auKWjY+ZjLJ89e/1d52GvXycIBFT9+v77F4dWqZKYR0nl3YLDNhijFEIxxyj4wWsi8ECYNtPqBIpQHlKSL2v+6+LidCV6h7Eqg8oD7I+CkPGZ2M20qHzRGqgNIdOB13oQ0l9xRRIch31mS6/SHV/OWDY41/kThiyfETYz10UIlRjsM1tO4IEwadgfBSGEcsJ2FISMj8NrPQghlAP2R0HI+LAdBSGEcsJ2FIT0V3z9UTBGKb3w2CFUXDBGQcj4CPaZRQihHLDPbDmBB8KkYX8UhBDKCfujIKTJOOfk/pXHjLJehHTCj2gDIp9Pk6w5JI/9rHupPmspC4wZo0wYssqIa0eo4Irl/X/w32rFUSwqKWXtWwEh02G0GCWvgYMQQgghhABAYOwKIIQQQgjlAvvMIoQQQsgU6ROjYJxRzuk+AcrV6VGuNhYhVNqV+o8svNaDEEIIIVOEMQpCCCGETBHGKAghhBAyRTgWPkL6K/UXdxFCqBTB+3oQQgghZIqwHQUhfeHIyAghVJIwRkFILzPCZhi7CgghVL5gn1mEEEIImSKMURBCCCFkirDPLEIIIYRMEbajIIQQQsgUYYyCEEIIIVOEMQpCCCGETBHee4yQJuxBhRAqASSPad0pyx3sM4uQXiYMmmjsKiBUomaETTd2FVB5h+0oCOlrxoqFxq4CQiVkwsCRxq4CQsUco+DY4QghhBAqnGKMUbCdECGEEEKFhtd6EEKGp1Ixy5b9AaDSmUrYv/8QMzNZCdUJIVTaYIyCEDI8hSIjNfWfIUPe6kizfr3Nx4+9MUZBCOUFYxSEULGQSgXW1roSyGS5jM+0bt3O+fPXKpVKQkivXp2nTBlaXPVDCJk8fWIUvH8Y5USy/uLpgbRNnhyanh6dlPRu4EBYsQIA4OVLmDYNBAKoWxf69gWKyj3j/ftPxo2bf+3afmdnB4UiIyYmVp/VsSxL03SBaliILAiVQqX+8xnHmUVIfwRf+r1S5817vHo1Y2+fueMSE0Eqhfnz4d49CA/Pc5fGxydYWJg5ONgCEKlUXK+ePz8/MvJ8o0bf16rVoXnz7nfu3AcgCoXCyqr2xImLunYdHBw8YtKkP/iUV67E1K7dId8sBw5EGnsXmf4LIePDaz0IIQPz86s/Ywbcv3+iceN0zfnm5uDtDUlJeWZs1KiOu7uLm1vLli0btGnTpHv3DmKx6O3b9yNHzj52bJOtrfWFC9f69Bl78eJuAPj0KaVFiwbTp4948OBp27Z9pk4dRlHU5s17e/bslG+WYt4BCCHDwBgFIWRgrq5eHz6kPHhwxsMje2ZEBCQkgEwGS5fmmVEopI8c2XDrVtzp05dXrty6Zs2OU6fCz5yJfvv2fUjIb3ya5ORUfkIiEbdq1QgAPDyqVqxoe+7clYYN6+zc+V909N58syCESgWMURBCBrZv38bevQ8FBcGaNdCqVebMr7/WFZ1o8vPz9PPz/Pnn762tA548eUkIqVXLOyJirVYyqVRCZXVs6dmz0+bN+z59SvH393JystcnC0LI9GF/FISQgbEsdfmy+blzVGpqwTI+fPjs9OnL/PTlyzECgcDBwa5Zs8BLl25cuHANADiOi46OyZmxe/cO+/YdW7t2Z8+enQBAnywIIdOH7SgIIQMbPnzSs2ev//6735gx7/g5/v56NaIQQmbOXNGz5yOxWGRpab5r1zIzM5mZmWzPnhUjRsxMS1MwDNOpU5vAQH+tjDY2Vo0a1Tl69OyWLQsAwMHBLt8sCCHThzEKQsjAHBzs5HKZg4PQxaVgGT08qh4+vD7n/ObN60VF7dKcI5VKkpKuas75558VBc2CEDJxGKMghAyPoqiTJ4XJya460sTEMJ06Ye8QhFCeMEZBCBmeubn84METxq4FQqh0wz6zCCGEEDJFGKMghBBCyBThtR6ENOEQ4Aip4dvBgMjn0+oHDuT15AHdS/VZS1mA7SgIIYQQMkUYoyCEEELIFGGMghBCCCFThP1RENJfWbvWixBCpgzbURBCCCFkijBGQQghhJApwhgFIYQQQqYIYxSEEEIImSJ9+sxiP0GkA54eCCFkmkr95zPe14OQAUwYONrYVUCowGasmG/sKiCkC8YoCBnGjBULjV0FhApgwsCRxq4CQvnA/igIIYQQMkUYoyCEEELIFGGMghBCCCFThP1REDKUUt+FnmVZkt9G0LSAoqgSqQ5CqLzDGAUhlKlPnx4eHm90JPj4kfXx+blv359LrEoIofIMYxSEUCZXV3rSpFc6Ejx9CseOqXLOT09XjB+/aNeuQzQtsLAwHzAgeMCA4GKrJnAcN2fOn7//PkCfxEWs2717j7p3H3b9+n7NmUOGTNu379jz568TEi7Z2VUoWO0RQnrD/igI6Y/k/SrdHj16OnfutFu3ns2dC+rLPTExcP06vHuXf/bu3Ye/fp1w61bE48cnjx/flJiYVKy15Tgya9ZKPRMXom4sy+pO8MMP7S5e3G1mJtOzDiaszJ7SqGzAGAUhBLGx95s337xnz9v09OwYpVcvOHwY+vWD1at15Y2JiT19+vKaNTMtLc0BwN7eZvz4gQCwe/dhf//2Pj5fde486N27DwCgUGRYWweMH7+oRo0v/fza3bhxr2vXIR4erTp0+EWpVCkUGZaWtceOnRcS8luLFsHR0TEAEB+f4OHRil/RrVtxgYHfAcCECYsUCmXr1j916TIIACIjLzRq1LVWrY7Nm/e4c+eBPnXr2nVIrVodfX2/7t9/Ih+RKBQZVlZ1Jk78o2vXIQcOnNi8eW/16q0DAr7dtOmfnJvcrFmgk5N9UXY4QkgfGKMgpKnc/qwUbNliM3686Ny57FkVKsDYsRAeDtu368p57dodX9/q5uZyzZkvXsQPGjTlwIHVd+4ccnOrPGbMXH7+x4/JAQG+9+4dCQn5pk2bn2bNGvngwXGhULh371EASE5ODQpqFB6+KCxsSs+eo0gePXhnzPhNKhUfO7Zx9+6wt2/fjxw5+8CBNTdu7J87d0yfPmPzrRsALF8++caN/bduRRBCtm07wM/89CmlRYsGO3cuq1vXb8yYeSdPhl+9uu/NGz3akcosHW8HfBX0lXPf6t7PhTsKZQ32R0EIQevWzRs2PDJ79i87dlwTZP1ySUuDgwfh8GHo2FFX3lwjifPnr7Zs2aBqVWcAGDAguFWrXvx8qVTSpUtbAKhfv6aPj0f16q4AUK+e/6NHzwFAJBJ++WVTAPDz81QqVc+fvxaLRbprfuZM9Nu370NCfuP/TU5OzbduALBr16Ht2w8CwNu37y0tzX/88VsAkEjErVo1AoBz564EBTV0dnYAgL59u165ckt3HRBCxQRjFIQQnDp1YceOiULh++7d4dAh4G8uZllIT4e+faFWLV1569TxuX37fkpKmmZzBSEk11uUJRIxP0HTtFQqUU8zDAsAHEdYlhMKaQBQqRiKooRCIcdxfDKlMpfuuoSQWrW8IyLW6l+3qKjr69btOnky3MLCbNGidXx4BABSqURdZ5FIlDWBH5IIGQ1e60HIUIzemFz4l0qV0afPyxUrFI0aZfdHMTeH77/PNUD5LG/Nml5NmgT88svvSUkfAUhCwvvp05c3aRJw6tTFly/jAcjatTtatWqk0RZNcpsmAIRl2S1b9gKQ48fPS6WSypUdbG2t0tIUHz4kAZDDh8/wWYRCAU3TSqUSgDRrVvfSpRsXLlwFIBzHRkfH5Fu3Dx8+urg4WVjIGYb5558jOevTpEnAuXNX0tLSAMjBgyfzPril+6AX3zsBIUPBnwgIIXBxqRIe3nrhwitVq35QN3/066dv9h07lvz++yI/v/YURVlbWw4d2qtyZcelSye2a/c/QoiHR9XVq2foU46VlcWjR8/r1++iVKq2bl3Et2rMnTu6bdufq1d3rVLFSZ1y0KCQgIBOjo52x45t3LMnbMSIWWlp6QzDdurUOjDQT3fd2rRpsmHDnm+/HSCXS7293XNWo3Jlx0mTBn31VV83t8o2NtY5E/TvP/HgwZNpaYqaNTv4+3sdPrxO3z2FECoIjFEQQuDr6zlr1opJk4KnTYtWz+zRQ9/scrls8eLxixeP15z5/fdfff/9V5pzpFJJUtIVfrplywYtWzbgp8eN6w8ACkUGAEybNmzatGGauX766buffvpOa42zZo2cNSvzsb3Nm9eLitpZoLr9/fdirWSadQOAnj079ezZKa8y//xzel6LEEIGhDEKQiiTQsE+fqwrwcuXJVUVhBDCGAUhpNayZe+TJ9voTtO8eVAxrV2rJQMhhDBGQQhlatfua2NXASGEsuF9PQghhBAyRfq0o+AtaignzRsvEUIImaBS//mM7SgIIYQQMkXYHwUh/en+UVLqf7Kg8gdPWmTSMEZBCKGybMLAMXkvGgsAM1ZkPvExISExIKDzsWPrvbzcACDkx1DvGtX69evyc9/J0dF3hEI6KKj+qpUT5HJpydQcIYxREEKojJsxv0ZeiyaMvqeetre3mTNnZN++40+f3nL/aXzsyw8b1k9//z6pf7/v9/7TlGXZH7qNmTN33bSpA0uk1ghhfxSEEEJZQkI6WllZzJy56tDpm3+tnSISCR0d7Tp2bCEU0hKJuEXzus+fxxu7jqgcwXYUhBAqv17TPgsOf/ZMooCf1s5fsqlS6xkn3jU/cTh7PsMya844twr6bsFhu5KuZel3/pE8/0QoB4xREEKo/HpN+UQc0XpuorVZw/EfARYezZHafeD+pwBPS6huCGGMghBCxqdQMkolp1AyGZkv7WmlkgUAhZLNnKliFRlshorJyMicVqpYRQaToWIAICODzVCxfAkudAVjbxxChYQxCkKaSvRWTIry0p2gXbuVJVMTpBsHBIBwQAhwQBGOEAAgFMcRAhTHESAUR0j2HEIRjhBCcQBACOH/hayZmXOAEOAIEAIEACigKKAoEAiAoghFURRFBAKKAkI1b+YAABIRLZEIJSKhVEJLRLSlmcS+glAqpsViWioWSsQCiVgIABKxUP0vPz139EQAB6PuP6SFaAyAmddImIUbJ7Os3UyOMQpCxkRInp8pFEWFrv21JCtTeilVKkbFKFUqlVKlUqlU/DRPyfBL+WRZGKVSpWJUKqVKxTBKpYrJmgMAmTNVKpVSpcjI4FhOJBKKRCKRWCQWiQBAJBSKxCKRUCQWi4QioVgs0pzDJwYAkYifJxSLRCKxUCTiyxBplSaXy3Rs2uz/rVo8tkjPcaQoXd9bTuRO0JdJ/PTNm/eio2/36dOZoqjIg0dFllZv3rxv1Kjm2rX/mJvLKYoCADe3St91Kq7nSpYTjT3SjF2FUgNjFIQMxQC/YDIyMubPny8Wi8eMGQM6I5hSJGcAAVrhgkrFKBl+OaNSqRj2s3BBxSiVKobRjirU2QEg81tfJNIKF4RCoVgsykygjiGEtEwmtbK0EIlEQrFQHTRAVlShGUNIJRIBXbz3P+pxlIvxNHBi74xqmxmjQFtHAEeAjwCQtG/XjOlTAKoAwB99unye6V3x1QchTRijIGQqIiMjBw8e7O7uvnTp0pJcr65GiKwAAgByxhA5AwhQN0IoVSrV540QIlFmuJAjhsgZQMhkUrFIpBVDFKIRAiFUqmGMgpDxvXz5MjQ09MKFC0uWLGnXrp3mIlNrhHjz/MnH9wkCAUVTFCUAmqIEAhBTlBhAIBTQAhBIKM9adWrWa1wyjRBIt/PXX8YlW6sHaquSlFYlKf25tey5Nd4Ki0oBjFEQMrKHDx82bNjQwcHhypUrlpaW6vl2no0GDBonFotompZKJEBlthnIpFJKIJBKxAKaFovFQiEtFAolYrFAIJBKxSKR2M7WBgCkMqmAoiRSCS0QiMVioVDIhxq0QCCVSoECuawwLRArZ4R+1/Fn3WlOHt7QrNVX/HSZuFpVWp28/Gz80lPLfu8T4O3Iz1GE/a0I2y4d1F06qNuEgWPVo+AjZJowRkHIyNzd3a9fvx4aGlq3bl3NdpR3cRd2R54tzjUXJnyggJKbW+af7vPCMxTpa+dOOHlwt4Cm5WYWnXr9+m2vAnQHfvbg3tSBwX8duao5c8nEoWcP//v21fN/b76xstEeVUyRlrpixphzR/YDIU5Vqw2aNN+7dn0AiNi+ftuqBYxSSYC0/b5nn98m61+N0uXg6QezVl9YMbFtLa+Kxq4LQoWEMQpCxufs7Lxp0ya+P8rKlSuXLl3q5uYGYFo3Er569mjpxN+kMsvFU/r26DfRoZIrAETsXPX6xUNzS5vWHXvZVnTOTv15zacO6CGVyTccv2lmbpn0PmH/1jX5bhrHsgKa/qy0z7N80aHrj4NDg5t55Xp75tyR/xOKRFvPxEqksvNHD4zt1XH90evpqSl/zg7969AVO0dnZYbi0b0Yk9rDBrTj8N3lW6+sn9He09XG2HVBqPAwRkFIf8X7hRYUFHTt2rX58+fv3Lkz876eYl1fAbEsG9Doq8ZBnc8e281xHD/zWtSx0Pl/P3t0d9XcYeMX7uJnasUMj+7F3Lh4ZuelpzIzcwJgZWv/45DfCcDkX3948eg+yzD+9ZuMmBkmoGllhuK72k6dfx7y7OG9Lzv/mJr8aePi6XJzi/ot2+aMQ/zrN8t1dQDw/GHspVNHdl56KpbKCECjNh1atOu8Y83ixm06yM0srO0cCIBIIvWqVc+k9rChhB+8vW7Pzc2zv6laKd8WrzK5A1DZgd3ZEDIhEolkwoQJfIBiaswsrBITn6+aO+T18wdyMwv1fIGArlTFg1Ep88p4/9Z1Vy9fmZm51vzhM5b9deTa+uM3CSHH923nZ6amfKrdsMXUVTs8/QNWzRy7ZGfkmv+iPyS8KVBVH96N0VqjT0DDh3dv+gY0qlS1WvfG7jOH9Tq8a7Mq7zqXXmt2Xd+y//aWuR31CFAQMnXYjoKQoRSqewdF8RMVKrjb2Xl/+PDw3bu7GkWa0M9ciUTq4uH58tF9R+dqEklmf1tCyLLpvzKM8oe+4z5LrVFzwg+pmmNbTh7YFfnv3wCQ9D7BzNyyzXfBQIhILAlo8gUQEnP5XECTL+wcKgEh7br/HBtzJc+9kUvhRGsm4TgAoGl6Qfihx7G3b1w8vW/zygNb1yzZeUIgMP2fanqdBoSQBRsun7r8dOOs9hVt5AYdvRQh48AYBSGjIeQuALRvf3L0ql+iDl0/s/dyw69qN+tULzuB8eqW0/uE+JcPn3UKGXnl/OEPiW+d5JmtFEMmrsqZWLPm1X3rPIm7k5aaotmwcefqxYi/1y/eESk3t9i55o9Xzx7zX5tiiVQ9MCotFKknIO+9kfP71q2Gn9Yab1+9WK2GP5/M1cvX1cv36259Ovjaxr944uRSrYB7whQRQmavjbpyJ37L3I7WFlJjVwchwzD9HxAIlQMEhDQNAAzDZj/Kw/ReCa+fxd2+/Pb1s3w3R/NVrYa/X2DjBWP7p3xMAgJJ7xI2LZmR/PGDg7OL3MyCVTFnDu3N+QATv7qNb0Wfz0hLAwJRxyPyrFWO1QEBl2o1Apu1/uP3QRnp6UDgwrGDp//b07XvsFdPHt6MOsOnuXc9WiAQVLB1MPpezeelB5bjxi89c/fRu40z22OAgsoSfdpR9HuXoHIKTw/DoEUCAGBVnLErkifHylV7DBq+Y/XSNt/2tnesws+csGi3PnmnrNi+Zt6EPm1qURRlbmnVuc+QwKatD+3cOP5/30ll8qoe3jmz2DtV7jVswphe7RyruFla53JzysLQAVGRERnpaX3b1nGr4Td/83+aS8fMX7ty5piQ5l5AiJOL2+z1/9o6VHr55MHm5bOeDY8VicVyc4upq3ZI5WYF3xOmRcVwoxZEpiuYNVO/loqxaRxpKvWfz3hCI2QKCC2kAYBRqUz2Y0UoElWt7m1Vwda5qmd+abVbACQy2eDJCwdPXqg5c3LYVq1cYonkwK136rxfdg75snPI58VmGzl7RY6VZpOZmf02K+y3WWGaCZxd3edvjtCRq9RRZDBDZh8TCQXLfm8jEdP5Z0CoVMEYBSHjIwRoWgAALGPqjxFUMcp/whfqTiO3kJv4VpQN6Qpm4IzDttbyuSNa0jRl7OogZHgYoyBkEjLbURjW2BXJx8CJ84xdBQQA8ClV+cvk/7yr2U0a0FhAYYCCyiaMURAyCbSIBgDW5GMUZAreJ6X3nfRf0wDnkT/VpzBAQWUXxigIGR8hJPNaj4o19Ys9yNhev0vtM+Fgm0auI3+qb+y6IFS8MEZByFCKFFsIRaXjWg8yhuxT68Wb5J8nRvRo59Onk3/RTjkMhVEpgDEKQpqM9MFNgKazrvXgdwfKw8PnSf+b9N/AHgFdv/QqkRXiuVgydO/ncn0UMEZByPgIEIGQv6+HJeX7Iwnl5c7Dd/2mHh71U71OrfK99xuhMgJjFIT0V4zRAx+jcIzpjuGGilXrapK8FlEUyGyca3/de+rAJm0auxp0tRgQI5OGMQpCJgCv9SAAHd2lbT3qLRjVsnFt55KsD0JGhzEKKhYpKWlhYTvU/371VeNatbQbqGfPXsdxn30oh4b2KQ0PoTU8ojE+CoYoKKfEh9EYoKByqDx+H6ASkJycNnX6mhOX3p658v5MdEJQ64FRUTFaaSZOWvksXvT4leD+M7j7mJ00eWXpvqulSA+NI7RQAACMijX2I+zwZaxXsZ1gOdej3woRMjpsR0HFRS6X/9D7V4lILBGL/GoF9B8w59qVzVrNJAOGjVIxnEKpVGQo/960VnORUslt3PT83LlEgYCSyQTtvnZo395BvXTVn0+ioj4kJCi3ba1raVn6T+PssfA5/PJAOdnaeoaHPy16OZ4xSdUBYmKS4sKfvk7y0FHm6ySP8PCXRQKOw3UAACAASURBVF8jykvMrU/GrkIpUPo/3JEJE9K0UEgLhXSL1l9tW7eCFgZqJRg7YtDk2X8wDJuzBWXO3AcSiWBFWE25nP74UXXoUILm0mZNbX/o6vxLv+vFuwElhQAIhJn9UTBEQTnZ2Hhu3fak6OV0SUqqDhBzK2n3iycAHlu36ijTY+u2F0VfI0JFgTEKKkZCmla/GjX7onGbb9t3661eyjLMpAE9rkVf9PStxbCfxShPnqTfupW8cUNtmYwGACsrUbdulTQT+PpalMgWFEgRoousPrMcyxIOcHBzpCUxMS64x8Cil+N5JhbOgL+ftaRZ1ciI40HtW+eVMvLgsaB2LYu+RqRbzZom+FFmQjBGQcWFoiihUMi3owhp2sGx0oMnzzQT0EJhrQbNrl+5XM3LTytGefgwtWpVGR+glA+EokBACziWIxxL0fp2FFs8bENx1goZzPAlvYuS/f37uJCQqkWvhiLJSnEG/P2t6oVUvXv+QUhI37xS3j33ICQkpOhrRKgoMEZBxSi7HUVIK9LTJFKpVgKWUVGUgGFzXuspX1c8+K2lhTTHcgzDivSOUQBg3Or+xVQrZChz+v1Zvk5ohAwEYxRUjPgWFP71/Omjqj6f9UdhWfb2tUstR/7OsKzq83aUatXMnj59lp7OmlZTSvF9zxAAAKFQoMoARsWJxAXIyuEzCEsF0zxKplkrhLJgjIKKkbrPLMsw505F/rd/76q5EzQTNG/9tZdvTYVSpdWO4uYm9/GxWLrs8eBBrmZmwo8fVRERb3v0KOPjQ9BZ3WYLlItwODRtGUF93hFJKJS5ubUSCqV37+4yVpUQ0gdVtD50OkYvxBgFFSN1I8q2zWuDgur/s2feZ0tFgaMnzVayLMOyWv1RACB0nMfGTc8HDIyhKDAzE37T0UFz6bLljy9fTsrI4AYNvunqajZ9Wsk8Yq248M/oyRrGjSnQI3u0xsHL6cWj++eO7NedpoK9w5ddsPNBMcr3mB6KS9Oa8/F98pZZe1mWO3Z0XKVKsmKrGkIG4PibQvksMvnMBMKkUwKx9TfbaSu3pAPBzIf7wDFi58aWrZYCRRNG8XaVi1mdQcyHWJl3D4l7x/hF2n0ANOkTo2BrIMop36GgSFpq2vqVf9A0zaqUJ47uvxS1IWfiTWuWMSzHsizDshzHaRYokVD9fnHp94tLjpUCAAwZ7JpbfUotAqBuR1EVbDh8kl+MEhdz1bmyXyWX6jrSHP5nFfkuuABrRQVV8DPUysaiRqD77Yv3d+56PmwoPkcQFULJfTByqW+S/utj0yVCaOdLmDQgBAAsgxYL5BUByKejg9Lv7ZB59wAAovwkrtLMvMlkfYrFdhRULCws5JMmqm8ZEE2bsNrFxVErzfRpAzmN6xSNa/0qFJpS75MSxw81y6oKdu0m3/4oHAGp3FxubqkjjUAo1ConQ5G+fuHkM4f2CGhabmbRIbhfx5B+BaqYQXzjb2tlayegBBzhajds0WvYJHunylpp2vtYHbzzsYgrOrxz4461ixilkhDSpvOPPYdOWLdgEssyv4ydBQB71i9bt2Di3utvhSIxw6g613HcfCrWysauuPdSYBv/2xfvHzv2puv3VbApBZky5ctzYuemQjtfAKCEcn6mIm6PInYHAHBpCZTYErx7AABFS8QuX+hZLMYoqFiYm8vHju2tO01oaJ8SqYsB6Y4GijQ+CqhjlAI+VlB3O8r0QcFyc2uO4Vw8fFt16AkANy+fvHz2oEgkqd+8Q42aDTMLIdrlzBrWUyKVrT54RW5u+THxXcTff+XbYFMIHMsK6HwC0yV/n6pg75ChSN8aNnv4Dy3XRFyVmWUPKcGx7MKtxwpXN/XaXz55sHb++BX7Lto5VFJmKJ7E3SYc8Q9ssmX5TL7kmEtnXD19792I9g1oFHs9uqKzi6W1LeFIAfZSoXaelY0FAHAc2bnrmaGbUojGX4SKjgB81itF9fpS+q2NNj8cocQWqVeWsB8fZy4QSrVS6oAxCkLGx3dWEBSyP4qudhcnF49Owb+lfPpw9lhmv8unD28FNm1XtZrP0un9h05abW1TMWc5T+Ju37x8ZvPJOKncnOM4C2ubbv1Hcxw3c9iPL5/cZ1nGN6Dx4MmLBTStzFAEN3XrGNz/7JG9NC0cs2D9tpVzH969UaWa58Rl24Qi8Y2oUxv+mJKhSDOzsBoyZamLRw1lhqJHE9dvew58/igu6Jvukf9u1ypTewMJx3GcSCz5acSUq+cjT+zfEfRtD80SZo/o9e/NxM1LpwNAz6ETAeD+7WuLxw8I2xuV79obteoAAO/fvpaZWVjZ2HEcJxSJPXzrcBznXafhw3sx6WkpEqn86YO73/cdcfPSGe/aDW5eOuMf2ITjuLz2ko5DXDhCIYVNKcjEiSs3+3RiJPMhTljBkzAKAI5TfKAtq1BiC+CYjAf7hPY1C1EsPlMQIVMhVD+ypyCITnJzs00rxu//O6yKm7dmLmtbB6sKdsqM9FxLeXDnelUPb6nMTKu0gRMXhu2NWvnvZULIiQM7+JmpyZ/cfWqvjrj2Rcduv//cofeIKX8dvimgheeP7v/w7u3qOeOmrNoVtjeqz8hpi37vz2dJS0n2q9f098WbGwa1z7VMNa2qefrXffrgrlYJfJqgb4Mj9//NcRwh5Pi+rUHf9NBn7fycGrXrO1Vx693KZ/6Yvsf2hquUGYQQqdzMxb3G3WuXnj646+xa3S+wya3oc4SQmOizfvWa6thLORXxxAgKqshxsHPX8yKWg1DxEcgrWn+97mNE73eb6yX+HcSlvpFUbQUC8Yd93yf997PQpkbhisV2FIRMAH+tR8T3mS3YYwV139dTuZrnh3dv5PIKFWyz+wPtC19y+tD26j6BFZ2qqtevWQ7HcUByKfn0oX9OR+wCgI+JCTIzi5YdunEcEUukjVp/w3Gkul/dKu41HKtU4zhS3Tfg1fPHIBAkJSbMG/Uznz0tJZnjCMcRkVhSs34LvvycZWrtGj5LdsWA0iqB3wmOld2sbexuX7ngVavemUP/LN5xOib6XL5r51EUPX3Nvqf379yKPndw25r/dqyfu/EQJRD41W0Sc/lsBTsHn4DGjlWqvX72SKlU3r0WNXTqco4jee2l3BUhUOn2g0tk5FtsSkEmTuwSZBtyXnOOdYctWmkoodRh0Bv9y8QYBSFNxrk8rx5nFgAY/R4r2M7bjJ+IiBiQa4L9MZ8A4PqF063a9UpN+XQz+kQlFw9+0bfBQ2vVD9Kug8Z3bTWvmk8f3E1PSZHKzdQzY29ePrp70+z1/8nMzPduWh7/4gnhCOGISCTm81KUQCyW8NMCgYBVqQjLuXn6TVm5W3MthCNisQQIEEJyLTNnxdQz78dc+fqHvpolaFb+iw7dI/dtS03+5Frdp4KtQ75r11qRi7u3i7t3604/dm9cJf7FU8fKrr51G+/f+qe1rf03IQMIR6pW943cu9Wygl0FO0fCkVz3Ul6KcmI5OkqDgioeOfKmxG/wwd4qRpTvvZM6cpUdeK0HIVNAAEh2n9nMDybdL11XeSDr+zj1U9L9u1eePIjJd/18ev5V1cPXu3bDpZMHp3xMIhxJep+wfdXc5KQP9k5VpDIzRqW6cGw/kKz0WesiRKMcAoSAT51Gcbeu3L12kXCEY9j7MVe1suRZZtZLvSHpqakbF0/58P5tkzbffbZSjTRN23aJOnHwyK6NLdt3JxzJd+3q1+unj25dPstPx8VcoSiBVQV7whGf2o3ibl6+f+uqe41ahCO+dRrt/GuRb0CTvPZSR3/LXF8REQPaeZu18zbT78hqH2gA6PaDC98r5dWrdF3HESHTwCTGvttcv+jlYDsKQiaAv9ZDZ40zq/dvoXnz5imVytGjR0skEq1FHOEAoNuA0RdPRNhUqOLl34Cf37H74NzWT/j0aqPnr9+ybNrgzg2AoswsrDoE96/ZsMWxfeEzhnWXSGWV3TwJIRzh+DuW+bx8vJA1TQgQSxu7cQs3r50fmqFIYxmmYVD7aj61NLPkWqZW3X4LbklRFAWUf/3mczYclsjlyowMdQmaG2tmaeVVs961qMjhs/7kCJfv2tVYwv69ZsHL3/sJRWK5ucXYhRvFUilHODMr64rOVa0q2FE0zRGuRp2Ga+aN6/rLKHV2rb0EOkfMpCiq0L9yjdeUgpAxYYyCkPFlXesRAADDFOA+2pCQkNDQUD8/vyVLlrRr1+6zMjkCAI7ObrZ2ThUdXM0trHXXQOsii1gs/XnkrJ9HztKcOWrOX1qrEInE4aczL9D4BjTh2xgAoHPvYXwCnzqN5m48klcWAUXnLFPz323nXmjX9PMSAGBH1Gv19LiFmzXL0b12NUdnt8lhn403r06wZMc59b/VvGr+czVRc6nWXvouwAZ0Bo5FaYjHXinI9KXf2ZoSNVMgthC7fmmQAjFGQcgEEAIAFN+OomJA7ztBnJ2dN23aFBkZOXjw4JUrVy5btszV1ZVfpO7LKRCKjh/YZG6pK0ZJiH+ub99PlB8dgaP+RzYnbEpBJo5Nfpl8JtQ25AJtXunjEcM8jx1jFIQMpajf8TQtAP2eEfjq0Zvq1TvExLzy968EAEFBQVFRUY0bN65Xr15UVJS7uztoXHRo8EX7Bl+0z7fMot8ii3h5BY62tp6XjtzMmb6yh0Olag4552tQ90qpktWUUrmwTSmF64mJUP5Ur86Lq3xBm1cCALlfn49vrhW9TIxRUOHF3EoOD39p7FoYzOskDx2b8zrJIzz8qc6lzwq9av6r682zBAB4eu+VSpnPo49fPnpTvXr7mzczYxT+69Dd3f3AgQM521GQUeQMHG1sPC8fzSVGAajplE+MkkmjKeXFsKG6HsCEkFFQgqygQmCY6AJjFFR4MTGfYmI+GbsWBuSxdZuOkMtj67Y8YxQAj63bCh+jaH51vXz45uVDfccPePnyZWho6IULF/Lqj4KMJWfgmJgYV69NqGaalw/fvHr0BqAAjRqGaEpBqFiIKjVOPjeFMGmUUJ7x+JB6fsaTIyLHQIHUJudEvmVijIIKo2ZNXQ+oK6UiI04FtWuhc2mrvJceD2qnPeKInrZue1avTU0AiH+a8DzutWNVuyqelfLPtWJ2zZrfhIdv8fT0XLNmTV739aCSl1fg+P59XL02/lqJM2MUvYMUbEpBJou2cDZvOP7D7o60latm/PEpcrhV27Vi58Y5J/ItE2MUVBj+/hb+/hb5pytV7p5/EBISrHPpzzqX9i7cerduexbYxh8AYs7FPY97bedsG5jjmyynqSMO+PtX8vcfk1cCbEcxlvDw8LwCR5LbvwXtG4JNKchkyXyCZT6Zn6Lqbwj7n+/kNZEvjFEQ0l+xfetnjo9SsOceU5SuZ4dijGIsY8bkGTgaJEgxaFMKniTIpGGMgpCpEIqyxnDTAz/U/cqx4T3GfJNrAuwzaxS6A0dDwaYUVE5gjIKQ8fH3/Qqy2lEKdBsw3jNsOjad0B5xjrd9/v5f5wRDLgcrsyGloAcRe6UgUxO/SFocxWKMgpCpyHpeT8H6unJ6jKeCSq/U1Ldz567jp2la8OOPHRwd7UCjKaVFC9nBAxGaWRwd7fr27WyEuqLyqvh+KWGMgpChFHkMN2EBrvVkrxWv6ZRpKSmvFy8/ULt+M5oWZKSnLlkafCV6W8WKNo6OEr4pZcuWW5s3/92paw+G5RiWTXj79vnDo337fpdfwXjaoFJAnxgFT2WEihf/IyTrWg9XoN8kBUuNjCTXo8TP5J8RrYOLq9sPfQZIxCKJWLT9r+UTJoat/nMiAHT7oXJk5NtLlxLtHSoOHDFOkaFUZChvx9xYMX+8Om+X7y9YWYkoiiKE1Kxp3UvJaD3s/syZd9u2PwMAkYga8Kt7jRplcFiBcqzUfzhgOwpCpoAAAE1TAMCyXIE+WbAdpZTQfZh0LaUoENI0/+r2U7+e3wStWbPz8wTUhrUrvw/uzbAsw2pf+1u4oGaFCmKlktu2/fmRLW+/0ljEMOSPxbFhy+s6OUlPnHj75+pHfyyqXbDNQqg4YYyCkKko3LUevH+nzKMoSiikhUJaSNNm1hWqe/t803NQjZp11QmSEt+F9u3cpl0nWiRhudzPH7FY8FOvqvt205ozCSECAaVQsACgULA2NuJi3RCECgpjFISML+taDw0AHMMW6OqNPs8gREan+5jmd8SpzHYUIS0UCh0cKiUlvtNcbG1jV9Xd686tm941A1iW09EoY2srhgfZ/4pEgtGjvMaMvSmXCyiKmj+vlh6bglDJwRgFIU3GbJMQFO6+HuyPUtYJsq71iGhaRNPp6WkSqfaYKCzLAkUxLMuyutrhtO6/YBiyY+eLObP93d3NDx2Kn78gdt7cmprJDbYNqPDK9VHAGAUhE0D4/igC4L9sChJ27F95rLhqhQyoCJ1mKYoSCWlR1uWep48fdqpcVTNB8scPzx7FuVWvwTAsw3Ik72+19++Vmv/Gxn7KyGDd3c0B4IsvKi5bfp9hiFBYEsPQIaQPjFEQMhVZY+EXoB2l38zuxVYdZCooilL3mX38MC4l+dPo3t9qJfh50G9CkViRoWTzuPanUHB/73guUXy21N5eEh+vePUqvVIl2cWLiZUqyTBAQSYFYxSEjI//2SvI6jNbrtt2yxM9H9ej2Wd2bdjCcWN7jx3TR730ypU7PXtP+677T4oMJcOwLMtoZR8+4gY/Qn+tWlY/takIG7IXVawo/eV/1aZMvQ0AZmbC0aO8DLJdCBkKxigIGUoRQgvNaz1Mwa71oLJA5xF/8vDhuhV/0AJB4rs37948HTF8xucnG3n75u3GP5coVSzLMkmJ7/mZ/LLduxpqFqUIu67IXJqZoG1bx7ZtHQ22IQgZFMYoCJkKfnwULsf4Fqg8Mzd36vp9J35a6F3tfxtHicUizQTOzhVHDOsOABeiEu/fT6levULv4cFGqChCxQBjFIT0V1zNG5nlUpSAFnAsx7IcP+YsKid0nFhmZhXHju2kI6+jo9348b8AQHy8ov+v1ziOfP11gCHWjJDx4ecgQiaAZL4yHyuo4tRz8FXGX6BHAv04OkqDguw5Dnbuyv3xywiVOhijIGQKMr+RBAIaADiOMfY3J75K7AV6JNBXtx8qC4XUsWNvX71SFMNZilBJwxgFIePjB8ggWe0ojJJTz8FXWX7xRx90pSkQbEpBZQzGKAiZEIF6GDeECgWbUlBZgjEKQiaELtRw+AipYVMKKkvwvh6EDKWA7fKaObPa9NVDpJCCtvKj0ijrYk9+h7ugvVKcIyMTIiMTuv3g7OgoNUiZCBkFxigImRBaxA81q287iiIt9dDOv9T/1m4c5FrdTyvNng2LtZ6N3Ln3cEqAbahllpkZbW0tevdOeTDiTd+fqxq7OggVHn5OIWRCsh4rqG+Mkp6WsvOvBQkv4z7EP/zw+v70QV3iYqK10mxfNduCSpOTFDHzUZCRuP3POTmHS0dlRmoqO3HS3XfvlJUryzp/52Ts6iBUJNiOgpDxqVv6Mx/Zo2L1vNRDCEhl8h96/yoRiSVikV+tgLXzRs/ZcFyrmWTA8FEqhlMolYoM5fZNazVvGGEZ9srxW0/uvKAoSiQR1gh0r1HPnV+Unppxdu/ld68SBQKBU7WKjTvUFYpow2wwAgD47L4eg0hLYydMvHP/fmqlStLZs3wqVBAbplyEjARjFIRMwef9UVhW7+4ChAIQ0jT/zLkWrb8K/2vFDw0raiUaO2LQ5Nl/MAzLMGzW6jLLP7EzSiiivxvYRiQRKVIz4q4+zl414bwCq7Wq3ohwcGJnVMzZu3W+8C3qhqLPaI6PUlQZGdzUaffi4lIqVpTMnOFjY4MBCir1MEZByARkfUNl9Znl9A5RAIAS0rT61bjZF4Ivv23frbc6Ccswkwb0uBZ90dO3FsPf1Zz1nfjh7ac3T9/9MKKdSCwEAlK5pGbTGupVy8ykLp5OAAA0OFW1T3ybhP0sDcxwIYpSyU2Zeu/WrU/29pI5s30rVpQUuXIIGZ8+MQp+LCFUvNTvscxrPQxbkBAFhEIh344ipGlHp0oPnjzTTEMLhbUaNLt+5XI1Lz8+RlF/J757/cG6ooVQLNS9Opbh7l9/HBDkj58FxaSIO5ZhyKzZsTdvfrSzE8+e5ePggAEK4pX6tyz2mUXIhBS0zywvux1FSCvS0yRS7dtNWUZFUQKGVV/ryUTp8RHGcdyp3RcruTtW8cIOmKaIYcjMWbGXLydZW4tmTPdxcsrrZmOESh+81oOQJkMOU1GQ1WaWLBBSAMCqWH17URJCAfAtKPzr6ZNHbr6BmklYlr197VLLkb8zLKvKvNaT2Wm2goN10ttkVYZKJM79o4AQcmbPJZnZ/9m77/gm6j4O4N/L7C7de5dCJ1IoUJZYpkwRlA0iDyDLR1Q2og8qQ0VUEBRRGRYQWcoQlD3LHi2rQKGLFlqgLdCmae7u+SNtCekKbdJcm8/7lVdf7d3v7n5Jrrlvvr9x8qjO4Xrr2AllVfe1Van4+Quunzr1yNZWOu/zEC8v8xc9cA3WgkFVryGwvr1liFEA9KUGc7iV/CIWv3hbj0afWValOnb4wJ4d235YOFuzWPtOrzYKjVAoi9R5lNKPPTsXW2cvh2Pbz0X3eElmJlPkF14/k9SkfXDxznk69tdZkUTcsnvT+vbJJww6X4XKX89xtOjrG3FxjywtJZ/ObezjY67DSajPXroAhoYYBUBARBIREXFcNdt61q35Oax528nzftVcO6i125Q585Usq2JZVZk7Ab3cv+X5/Ql/Lt/LMCQ1kwa3CCxd9SDj4a2LyRbWZpu+2UVErr5O7fpGVfOJgb5xHH29+Obhww8sLcWffxYcEGBp7BoB6B9iFAAB0J4Ln9O9racg/+mvyxeLxWJVkfLfv3d+uvLvstuuXrGEZTkVy7Isy7Gc5owcEokoqktEVJeIspVxdLMb8dHr5dYT9EP9er74DY55nr5flnTgQLaFhfizT4MbNkSAAvUTYhQAARGJxUTEqXS977G5pdXrI98nIp5IbEZzlm1zdPHQKjNg7DSO48VE6uky3hwzTd2iBHUUz9PyH27v3n1fLhd9PKdxUJCVsWsEYCiIUQCM79k8syV5FB2/V8vNLHsPnVTurkr1GfbfSo4IQqD728Hz9OOKOzt33pPJRJ983CgszNqQ9QIwMow9BhCQ6o09BtOxanXq9u2ZEgkzc0ZQRIStsasDYFjIowAIQenYYxEVt/Ug0WFSdHq716xN3bQpXSJhZs0MiopqYOg6ARgdYhQA43vW1iMqzqOgLcYUvFCX2djYtN9/T5dImBnTg1q0sDN03QCEAG09AAIiLpkL39gVAWHZsiVj3fo0kYg+eD+wVSsEKGAqkEcB0Bc9pD7EYoaI2JIp3O6lZGfeya75bkGY7qVk6VJs27aMn39JFono/ckB7dvb66kdEJk6qAMQowAYH1+S62fExf1R1Esy72RdOnLNmDWD2sDzlTb2rPw5mWFowni/V15xrLU6AQgBYhQAAVGP61GpnhvX4+Lt6OKDi1O9Vcmbe/NisvqXce/4duvmXFs1AhAKxCgAAlDyLVpcPIcb9+y2KkQu3o4RbRsbqWZQK8pLoyTFp8TtukBEY8f49ujhUttVAhAAxCgAujNUE37pfpni+VFYjRAF938zRSnX0uN2XVAP+OnVy3ABCs4sEDTEKABCUHK/Hom6zyxX5uKBa4kJSb2ecezPsxzHNXk5+OKhq8auDoDRIEYBEADtth4WIYrJunvr3rE/z3AcF9G2UVh0EGIUMGWIUQCMrzQCEZXMhY8QxTRl3L5/eOspluUatwgIa9sY7zuYOMQoAPqihwuKqHjsMe7XY4oy72Qd3nySVXGNmgdExoRprNFjrII+TlCX6BKj4FQGMLCS6TFK5nDjnk2TTjpPlg51WVbawyNbTrEqLrCJT2RMKN5x0Ic6fxYhjwKgyTj/0lrjeriStp4qv/OuX/iXoesGejFoWu9K1j64++jAH3EqpSogwjuqawQxArm2CKMWps6k3wXEKAACUNpntuSegrr3mZ2+YqzBqgX6sWDMj5W8g4/u5R78I06lVPmFebXo2oQEE6EAGB1iFAAhKLkoMSQSiTiO41hOJGbKKVAGbpFcR5T/Nj26n3tg4wmlosirkXuLbhHEVFgSwAQhRgEwPs2LkkjMcBypWFYqlpRbQHtbDh1s64By38GcrMf7N8QpFUWeQa7RvZoyIhHCEwBNiFEABEDj0iQSi6iI5dXNPToMwuC0xymDIJV5l/IePjm48YRSoXTzd27ds5mIESGBAqAFMQqAsIglJV1SdMPXVozCsSxf1VVUJBIzDFN5GSCix4+eHthwQvG00NXXuW2fKPWYcwDQghgFwPg0r/3F07ipOJ549fLSX8pVa/1R5r//tpOrTyUF8p/kNQyPeHXAyNqpT92i+Q4+zcs/uDGu4KnCxcepbd9mIglTZfAHYJoQowDoSw0uM8+19ZQ3HX7F+661PIqTq1efQe9VUiD7XlrSrdNa9bmbfGtk57Bxs796bfiEah/6+7nvn9i3PSsjbePJNFs7B621ezat/mPlYlWRkuf5Tn2HDJs0+9dFc1hW9Z+p84ho66qlvyz6aOu5exKpTKUq6tfMbc2Ba7b2joWKglWLPz6ye6tIJLawtO45eHTPwWOqXcOqlbwq+XkFB34/8TSvwNHDvk2fZmKxWIcTxxBvMaIiqAMQowAIi1j8Ym09nOH7zGam3D749+Y7iVe2b1jac8AEdWtO6u2rHMvZO7lZ29o/K8rzWvX5Z8vaiBbt/t3yW++h46pdgXbd+g4Y++GoLhE8x2ntPz355s9fzf5+6wkHF3dloeJO4mWO40Kbt4ldOk9d8tLpI75Bodcung6JjL528bSzh5d1A3uO4+a9N0xubvHD9jMWVta5D7P/3vhLLbyS+Y8VBzaeeJpb4OBm93K/FhIZPoEBKoP/EADdAZ+svgAAIABJREFUGeyrp1afWfV0+Lr1meUN39aTcvu6n39kl55jNq/+iognYoho+YJJ0a+8dvPquSZRMTE9h5ZWRrM+PM/v/2vD3BVbP36n353Eyz4NQ5SFikFtfHsMHJ19Lz07M330tPkNwyLLXahZgdBmrcvdPxE9zLpnbmlt6+DE87xUJm8YFsnzfEjTVknX4xUFT+VmFik3r/Yb9V786aPBTVvFnz4a1rwtz/N3Ei/Hnz665mCiuYUlz/M2dg4Dxk4x7CvJkyK/8NAfcU9y8u2cbdu/3kIilQggl2H8GgBUAjEKgPGV0x/l+Q6qlfVHMXxbD8/R8f1bzsftvXX1fOlCS6sGvQZOVBYqvpw5VCNGea4+l04dtrV39PBtGNNr4L9bY9/+8DOO4wuePolo2T6yTafkG1fmTx62fPuZcheW1/eW5zhe6/k2iohy8/Ib2TE0vEW7ptGvtO/eXyKVyc0tvQMaXzl/ys7Rxd0nMDSyzYr5U/v/h084fSym9yCO429evuATGCw3s6i1UVFKZdGBjSfyHj5p4GzT4c2WUrkEfVAAqoQYBUBYdGzreaujt/qXXbvKb0PZHp+nryo1adWhUUTU+mVfvDtnBcMUj0BRFhacj9sbf+ZgZHSX0pI8z2v2R9m3LfaVXoN4jn+l16Bpw7uMeO8TnuMlEulLrWJ4jvcOCFYVKbPuptnaO5Zd6OTmWbYmPMdr9XcRMeK5P25Lvnnl8pljOzes3L1p1YJf/2ZEotBmrRNOH7NzdA6NbO3m5Z+RklSkVF49HzfpkyU8x3MczxugK0+vcJuKVu3aRQEBXVq2HdHhjZZSuVS/xwWorxCjAAhARW095RV4tqzitgmGYfR4AU44dfTgzk0MI17y2dhpC9arMxwcxxYpFR1eHeQdEKpZz9LjKgryT+zdfjHu4NZfvyWix7mPzh3dFx7VjuM4VqUSiyVEpFIVqTcpd2G5T7nc5d7+wd7+wR37DB3U1jszLdnV0ze0aesd639s4ODca/A7PMf7NAzZ/+c6G3tHO0dXnuP9G0Wk3Lxa8OSJmYWlvl6l0hpWtIphmJnf/yiW6NJJFgCIiDAoH8D4eI2HOkZRqVit7ihaD7Uvvvjis88+KywsLLtPrrhhRA8PZVFhu85vjnx3fsOQ5qUHl5tZtmjf87kAhYjn+dKtjv27Lbhpq5V7Lq/4+9KKvy+NnrZg31/rOJ7nOPbAjg0cz12IOyCTmdk5u1awULsa5T6puym34s8cVf+emHCWYRgbe0eO54IjWyXGn7mRcM4/OILjueCm0Zt+Xhwa2Vpd0rthcPBLLZf8b+LjvEccz+U8vL/hx4U1f6GqfFNEEnG572YlDwBThhgFQAieXZVEkuJbH2tcpCq8eA0ZMiQxMTEsLGzXrl3ae+R4fT0cnT0vntn37dzRivwn6g6zRFTaB+X5p/Fsq/1/rW/XrV/pn9Exvc8e/edpXo6FlU1m6p0Ph8T8smj25HkriCfi+bILNSuwbO57o7qEFCoK/tu/zSfjXtdcxXHcHyu/Gt0tfFyvZiu/mDH1y9VyuTnP8VbWds4ePo6uHiKRhOf4kKatMlKTQppGl2744cJfbe2d3+0XPapr6OzRvRvYO9f8haryTXnB+ARRCpg6tPUACIDGlUh96+Pi+VF4IqKs1IeX+RtaWzg4BBGRh4fHmjVr9u/fP3HixOXLly9ZssTX11ddQI+9QT39Gw2d9NG6pfNeH/Zh6cLWMX3LeR78sz6tnyzfqlkNC+sGvx1KLlIWEtGAsdMHjJ1eWk91Ga2FmrsdO/NrzT8117p4+H20ZFO5axdvOFr6p29QxOYzDzTXSmVmI9//fOT7n5e725qo6E1xcAi6fFz7fdRFbOxdvVSMiILiHzckio9/nBh7NyMnMDY2raKSGTmBsbEZ+jpuqYgIq/Bwa73vFuorxCgA+lL9K5zmlqLiufCf9WvISnuQlfZAaxN7+6DS32NiYuLi4lq3bh0VFRUXFxcQEEAGGJNcpFRkZaZUUuBhdibxVRxXvVarTLkL67qyb4q9fdCVuOrEKOvWp+urVv1y8hoSxSfkbU5LJwpctz614rKB69brLTbS4I4YBXSHGAVAADTzKCVz4RNPTp4OIa3K3+LkycTS39Vf2QMCAnbs2GGIPIpaSPM216+erLxM46bRlR9XLJGt2ndLq0y5C+u6sm/Kw4eJIa0qm6i3XFfibgwe5K6vWgUdsaYjFB5mLW/nvn/X4Zjur1RUcv+uAzHd2+vruEQUn/A4Pv6xHncIpgAxCoAQaM+PwrEsEe/kaefkaVfuBg/mJBJRenr6jBkzTpw48e2333bv3v25Per7kt80upMuxWptbn7BquhNefAgMaRV4Ivu7UrcjSFD9BajKHKsFUcoPNw6aoj71eM3hwwZVlHJq8dvDhkyQF/HJaLYWEKMAi8KMQqA8T3X1lMyP4oul/rY2NigoKCffvpJLpdrrSodZgK1rJI3xdTDN4AXhBgFQIOxukRUOT9KBaZOnVrhLk0+n2EslbwpdSxI0fO/Q8kgtfrV8chgqvdy1bfXVocYBecTQC3S/Z6C5c0W/wxiFKOo/E0BqFV1//KNPAqA8WneuoUp6Y9S+f1cVu65TURbvt09aGrvcgvUsy6odcLag+UPwFn/xV+v/7cbVXrfJQAoCzEKgO4MdoF5bn4UhoiqClE0Nq37X5VMgkDfJYFWC0ANMQqAvujn475kXI+uPV45Dn1j6z1DRBKITqAOQIwCYHyauRCRmCEiTsXqmCBBv5M6AekugGpAjAIgLCV5FF0vaRwufgBQTyFGARAWRiQm3cb1qCGPAgD1FWIUAOPTTIWIRCXjenSLPTB+p05AtgugGhCjAAiBRn8UCUPFfWZ17I+CPrN1AoIUgBeGGAVAWHSfw00N/VEAoL5CjAIgAOW09eg0Fz4RbV++1zB1Ar1CJAnw4hCjABif5vWLERe39ehyUeszoYuBqgT6hRAFoBoQowDoSU3aXDTnRxGpYxTceg1K6PNMwI39oC4RGbsCAPCcF+2PAgBQXyGPAmB8z7f1FPdHwfdcADBxiFEABKBMn1lWpWufWQCA+goxCoDuDBc1lLlfj87zowDUAM4xEDTEKADG93z/RYZhGJ7nOZZnRIyxqgQAYHSIUQA0CeJrpVjCqIp4luUliFHAmAz07yCI/7K6w6RfLozrARCcklsfY2gPAJg05FEAjI9/vrGnuNssy/K82Eg1AgAwPl1iFJNONAHorPr/KTt+3Fd24d61R2pQGahPDPEhjA92U1Dn32XkUQCMbOf2plpLxo67mpam+HF5sKenmVGqBAAgBOiPAiA4UilDREVFdf47EABATSBGARAcqVREREVF6DMLACYNMQqA4EilRMijAIDJQ4wCIDhSiYiIilSIUQDApCFGARCckv4oaOsBAJOGGAVAcCTqPEqRsesBAGBUGHsMoC96a5qRyYiK8yho7gH94kt+4tSCOgAxCoDuauljHeN6oLYgUgFBQ1sPgOBgfhQAAEKMAiBAyKMAABBiFAABQh4FAIAQowAIEPIoAACEGAVAgErmmTV2PQAAjAoxCoDgII8CAECIUQAESN0fRalEjAIAJg3zowBoqkk3Vb11cdXoM4tus2Agupxa+j39MH3cC6ney1XfXlvkUQAEB+N6AAAIMQqAAKE/CgAAIUYBECCZDHkUAACd+qPggxKgVqnve6xSIY8CADVR5y/fyKMACA76owAAEGIUAAGSShgiKlIhRgEAk4axxwC6q6WgAXkUqC04x0DQkEcBEBzEKAAAhDwKgP7oeQ43pZLF11zQN0ykBnUJ8igAglOSRzF2PQAAjAoxCoDglMzhhm+6AGDS0NYDYGSzJ36htUTFSYk65uXml10FpuazpVONXQUAo0GMAmB8ny1bpPmnQsH167dPIjXTWg6mZvb4D4xdBQBjQowCIATPNevIZETF9+tBcw8AmC70RwEQHJGIEYkYjuM5DjEKAJgu5FEAhEA7FpFKRYWFbFERK5eLjVIhAACjQ4wCoC/6zHmUxCic0WMUlYqtsoxEgkDKcAyUS0OKDuoAxCgAQlQy/NjItz6+cyd98uSBTZtWFoIcPszt3LlXLpfVWq0AwEQgRgEQgrJtPeqpZo3ebZbv1Uv59tuPKinx+eduZectLShQzJq1eNOmPWKxyNracty4wePGDdL9qGZm4QpFvOYv1WBl9ZKNjZVIJCKi//53+JQp/6nefgDAWBCjAGgSSgK8ZKpZY+ZRtm/fHhd3LC0t38mJevUiInr8mBITydyc/P3JzKyybQcOnGxhYZ6QsMPGxior6+GKFb9Xrw6HD8dWb0O1c+e2ubo61mQPpg3NTEJg0i8XxvUA6I6v+KFnQmjrOXNm5+efb129uvDMmeIlZ8/SjBm0eTN17kx37lS4YXx84uHDZ3766TMbGysicnKynzVrHBFt3rwnPLxnSEj311+fmJ1dnJspd2Gp9u2HEJFCUWhr2+zjj78bMOC9Fi36nzmToF67du2fQUFdmjd/febMr196qU+Vz+iNN95t0qR3aGiPsWPnsCxbyZ5NRu2d0gDVgBgFQAi0rxAlMQpb6VXEsI9Hj7h58xznzBE90ogc2rShjz6iESNo374K63/+/OXQ0EArK3PNhWlpGRMm/G/Hjh+vXNnp5+c5deoXFS0sc987nojPy3vSqVP0778v/uSTiXPmfEvEp6benTnz6yNH1p05s/nhw5zyXkaKiurn6/uKr+8rV67cIOKXLp1z8eKfCQnbeZ5fv35HRXsW0gPApKGtB0CIhHDLnvnzv7l5M/nIkbemTcspXZiURJs20bp1tGJFhRvy5dX6+PHzHTq09PFxJ6Jx4wZ17DiiooXlsrAwa9euORGFhQUlJaWqt33llZYuLg5ENHLk63FxF8tudfr0Js22nk2bdm/YsIuI7t9/YGNjOXRo73L3DAACgRgFQAi0r+oyWWl/FKOFKZ98MkMiuZyfn/fxx/TVV8ULCwpIJqP168nFRbPsc1/6mzZtfPnyjSdPnlpZWTwrwfMMQxqpEfWychZq7PPZzqVSqXqJSKQeDq2Va9HapJyKxcVd/OWXzQcPrrG2tvz661VJSamV7hkAjA9tPQBCJIT+KObmivnzU7/9lrN4FmlQSAj17q0VoGiLiGjUpk3k6NEf5eQ8JqKsrIeffrq8TZumhw6dTk+/R0QrV/7RsWM0EZW7UEetWzc9cOBUVtZDIlqzZluV5R89yvX2drO2tlSp2K1b9+p+IAAwFl3yKPhWAaCLF/tPyc7O/fmXHUR04vyNhQtX9u3bKSjIt3StRCLiONXKlav++edZgCCXyz788G091bZqgYEtPvyQvX8/rmPHIvUSf3+S6JZ73bjxm5kzF4eF9WIYpkED63ffHebp6frdd7O6dx/L83xgoPeKFXOJqNyFOvLycv3003fbtRvq6ur40kvBtrZWlZfv3LnNqlXb+vSZYGFhFhzsr/uBjE2/n8Dl5p+gvqrz7zLaegCMIzPzwbwF66Njupt7Nj10Mu2rr4YePPhraGigeq1UKuK4olWrVr81ejzLsiqWK1AodmxZ/+GHI2uthsOHv3XnTuf9+98cMaK406y3N3l7l1tW+5pnYSH/5pvp33wzXbNM//5d+vfv8vxWVO5CheKC5i9mZrKcnJPqJZ6eLjdv7lb/PmBAt7feeo2I/ve/71u2jNCqw5MnZ0t3SEQSiej337XuI13hngFACBCjABiNvYP9m2+9I5dJ5TKpf0DQpEnz9+//Wb1K3dYjlckmvD9dUahUFCofPXq0Y8t6zc2VSnb16jvHjmWJRIy5ubh7d/cePdxL1/7ww824uOysrML161vb2EjVC5OSnnz99bX8fNbDw2Lq1MbW1tIqK5mdzd2+XVmBR4+qnizfQGbP/u7w4TMsy/r7e/300wvkYACgTkCMAmA8DEnEYvXj1dfeWP/rcoYJ0Sry2Zzp703/WMWyKpYleu5L/oIFV+Vy8bLvm1tYSHJzlbt3Z2qubdfW6c03vEePOamZ4/jmm+tDBvtGRzv+uipp7do748c1rLyCjg52To5jDx6orFtMaIhEKpEYJfuw6Kupz/2NDAhA/YIYBcBoGCKJRKx+yKTSlm3aezQMf/nVvqUFlIWK6W/37dF3gJunj4pliafS6/CdO08TEnJXr2ppbi4m4m1tpQMGeGlepUNDbUp+LQ5SMjMVDx4UtmrlQMR3f9Vt8vsXxo8LrLyGVlbmI0dWOB74eQgQAEDPMK4HwIiY0jyKRCJ2dnXPefhAc7VMbhbWPPriudMqllWpnktm3Lr1xMfHwtz8BW44nJWlcHCQMwwRkZOTPC+vyOj3LAQAqATyKABGwzAkkYglYrFULJGKxYWKfLmlg1YZVqViGJGKZVWsiojKTB+iS/biWWOPxmQk2qsAAIQGeRQAI2KkYrG0pLkn5fYtN08fzdVFysJrF880DAlTqVj1/WVK+ftbJSfnFxS8QH9VJyd5VlahehLYrKxCGxuJumcuAIAwIY8CYDSMRp/Zp4/zLpw7ffzIIa0yPV4f6O7pq1AWqtjnpkD187MMCbH5bsmNiRMCLS0lublFu3ZlDBpU/shgNVdXM0dH+YkTD1q3dti5627btrghMAAIGr5FAeiu8nu/Ved2caV9Zn/7edmggd15Ll792LZ1T5cuX5tbWI7/YJaKValUrErFah1lxvTGdnbScePPjnjr5IyZl+zspJprlyy9MXzEycJCbsLEcx/NSVAv/O+7gbHr7ox462RS0pMhg70NcA88PPT7qMZ5VeUOS0/mKk9pACNDHgXAaB5kP/h12WKxWKwoyI87uvf82Q2lq2QyERGpipSrfvhWxapYli1UFGptLpeLxoz2HzO6/ClTJ00sZ8xOQIDV90sj9fcMAAAMCDEKgHG4utpPnzqAiP7583CXPl0XL1zj6GhXulYqFYlE0s6d32gSZF66sFOb8UaoKACAkSBGATAOR0fbaVOHENHjlMxp09Qz3D9LsEuljEgkefnlvlOnNHp+OyThAcBUIEYB0CSUCEAqZYioqEgo9QGTpN/TT7MHDFSpei9XfXttEaMACIH2J0tJjMLVvw8dAAAdYVwPgBAhjwIAgBgFQIjUs6sVFRntlsIAAEaHth4AfalJzqOith403gM6hYDpQowCIEQleRRcSEDPzhYUxP17UvIk78T5G9999/vIkb2srS00C1y5cnvr1oPHziZ+Pm+1eklIiG/f1142RmXB1CFGARAijT6zAPp0LD9/a/KRaI/DjZoye/fdWrV604njsXK5rLTApUs31v72S9eu7P2sm0R8YiJ//kJzxChgFIhRAIQA43qg9rRsIZo+nWcYhkg1Zsz9JUs3fPjBcM0CwcGy6dOVPM/zPP31F79v33Ob50aNZ+xtSMQwlmbm0wdJmgflRo23/nu+yNG27LEK5q0r2n+ey3wke2+mQZ8U1Eu6xCj4iASobSVtPcijgAExDDN5ctHAN3+YMmWp5nKpiHb1kL7analoQ6vYGSJHW+Vfx/On/WSz78tKDiHtGiUf3eNx9xl6qzS8gDp/+UYeBUAIyuZRiNBnFgyDIWKY4vgjJISREHvL3NyNeRaRnOW4wdMKu70q4fnKTj9p2/D8mb/wCmUlZSTNGuqlzmCaMPYYQIiQRwFDY4qRm6Po3vOxSDORSKWg9PTSQUDlU+45LfJyYsxkFRUAqCHkUQB0Vul3Sv3CHG5gQExpGoUYhnlawFuUKcLyJKn4+vBk+EISMSJnO8svxxqojgCEGAVAGLRjEbGYRCJiWZ7jeBHSnWAA6iyKUknpWayf9LlcyCWOk1uQszPx6n6zZVitmVZuD1kA/UKMAqAves55SCQipZIrKuLkcgQppkz/uTTN/ih79vANbGW22fmaBaQi+vZLsd6PC/CiEKMACJRUihgFDIhhGJWKWbpUsuzHj/u+1qF0+Ybf/93w+4Jeryl4vqI0SjmevDGXRCIiYpxsrTfMLl2e/7+1qsOXeEVR+5VLXFi7VELbELwAxCgAQlDOdaBkaA+mSAE9O3GSmzePGIa5fl0a4B+uGaCoXb2qXLiQI2KI6MYNsrJ6bq3t6WVa5csuKWXx8TD1L7Hr7q1bf29wjSsPJgUxCoBAYWgPGEIbCwuxT1uJV+N//jz6+pAeo//TR6tARHjg8GFv791+qFOvdkTk6kIhIb5GqCgAYhQAYSgnUyKTYapZ0L9m5uZtOrc0G9/jccq9CeP7ly0QEuIXEuJXcDdj1swRtV89AE1o5wYQKNxWEABMHGIUAIHCFCkAYOLQ1gOgyVgBQbl9ZtV5FBZtPWAkBjrxcD6/EJN+uZBHARAo5FEAwMQhjwKgL3oOJjCuB4hI3+dV6S14EPtCHYAYBUAAypsnSyopGddTi/cJAgAQDrT1AAgU2noAwMQhjwKgO8OFC+X2mVXHKOgzC4aDUwsEDXkUAIFCHgUATBxiFACBKukza+x6AAAYCdp6AIQAbT0AANp0iVHw+QhgBGjrAYCaqfOfHsijAAhBJXkU3FMQAEwUYhQAfdH7HG7IowBhQnowZegzCyBQmGcWAEwc8igAQoC2HgAAbcijAAiUVEqEsccAYMIQowAIFPqjAICJQ1sPgBBU2NajVGJ+FAAwUcijAAgU5pkFABOHPAqAEJSbRyFCn1kAMGGIUQB0V3msoO/5USQiIipSIUAxcfo9AfiSn7zGnwAChRgFQJOAPrJlstKxxwBGYdDwCCpXvZervr22iFEAhKCSth58pgOAiUKMAqAn+g4kMM8sEGEqfDBpGNcDIFCYHwUATBzyKABCUG5bD0/FY48RpgCAKUIeBUCg0NYDACYOeRQAISgnUyKREBGpVOgzCwAmCnkUAIEqmQsfAQoAmCjkUQD0Rc/BhETCMAzDsjzHkQjfJkwXBvaA6UKMAiAE5V8wpFJSKkmlYmUyBCkAYHLwwQcgXCXdZvGVFwBMkS55FHw+AhhHyVSzxq4HANRJdf7yjbYeACGoqK2n9JY9SHkCgMlBjAKgu9r+UoIpUsDA6vz3bKjfEKMACEGVeRRcSwDA5CBGARCACiIQqaTklj0IUQDA9KCRG0C4cFtBADBlyKMA6EtNIonK2nqUSrT1mDL9vvV8yU+cUVAHII8CIFwlY49xOQEAU4Q8CoAmYUUDaOsBo8I0/EJg0i8XYhQAIah8XA8y8wBgitDWAyBcMhnyKABgupBHARACzI8CAKANeRQA4UJ/FAAwZYhRAIQLMQoAmDK09QDoi6HmR0Fbj2nD4BowXcijAAhX8Vz4KlxOAMAUIUYBEK6SOdyMXQ8AAGNAWw+A7gyXzyh/zxIJEeZHAQPCeQWChjwKgHBp9EcBADA5yKMACEHlfWYrLAAAUI8hRgEwvtmTfih3+cOn7kQRZ04kzr5xsZarBABgdLrEKPgCB2BAny2ZUNGqo8eezl+YGdKk4czpbWuzSgBQL9T5yzf6owAIV8n9etAfBQBMEdp6APRF/19ZSsYeY1wP6Atf8hNnFNQByKMACBfmwgcAU4YYBUC4EKMAgClDjAIgXJhnFgBMGWIUAOHC/XoAwJShzyyAJmFFA2jrAaPS74mH7rovpHovV317bZFHARAudYyiVNa3zx0AAF0gRgEQLuRRAMCUoa0HQHe1HStIpSIiUqE/ChgKTi0QNMQoAPqCOdygDsEZBXUA2noAhEsiIYYhlYrncUEBANODGAVA0NAlBQBMFmIUAEFDjAIAJgsxCoCgIUYBAJOFGAVA0BCjAIDJQowCIGiIUQDAZCFGARA03LIHAEwW5kcB0BeDhBESCRFRURGHCS1AH3DTHKhLkEcBEDS09QCAydIlj4IPRwCjQYwCANVV5z83kEcBEDSZTB2jGLseAAC1Dv1RAPRj9qQfDLHbpKymRC6rvt+91eKeIfYPJqX1nQetifbvOnP8ym1j1wWgaohRAHRXYeL0s6UfGuiQCxamHjma++bbvdu1tTXQIcB0KJZtVyzbHtO9dffxvYioHrQFQP2Gth4AQUN/FAAwWYhRAAQNMQoAmCy09QBoElwoIJWKqHh+FIBaZqB/B8H9lwmbSb9cyKMACJpUSoRxPQBgkhCjAAiaOo+iVCKPAgAmBzEKgKCV9EdBjAIAJgcxCoCglcQoxq4HAECtQ4wCIGglfWZNut8cAJgmjOsBEDR1HuX0meuPHu1TL+nWtWWTJoFaxeYvWMtxz8UxM6YPFYnwJQQA6jB8hAEImjpGOXvu5oFTOUfOPj5yJjem8/txcZe1in005+eUTMvbd81upMiu3hbP+fhnlYo1Rn0BAPQGeRQAQVPHKDKp2ZtvvSWXyuQyaViTyLHjF58/s0IrTTLuvx8WqTiFUqkoVP6+ZqXmKqWSW73m3rHjeSIRmZuLur/q0KO7fenawkLuhx8zTp56LBJRn94Ob/R3qp2nBgBQOcQoAIKm7o/CiMQSsVgiEUsk4pc7dVv/y/di6ctaJadNnvDx/MUqFVs2g7JgYZpczixbGmhhIc7NVe3e80hz7c+/ZBYV8at/bSSR0L176J0LAEKBGAVA0NR5FBEjkYjFpY/odjGtO9v0GPBWaTFWpZozbtD5MyeDQpuo2OdilDt3ChMuP139ayNzcxER2dpKBrz5LFNSUMD9uzdn1S9B6gO5uspq53kBAFQJMQqA7owwuEY9zywjkkgkEnUeRSIWu7i637yTollMLJE0adnuwtnT/o3CSmIUXl3hW0n5Pj5yc3Om3PpnZhba2or/2JR1Kf6ptZVk1NvO/v7mhn9aYHQYKQZ1APrMAgiaVFImjyIRKwry5WZmWiVZVRHDiFQsW/QivWVZls/KKgoIMP/um4CePe0+/TxNn7UHAKgBxCgAgqZugmFExRkU9SM1+ZaLu7dmMZZlL58/1TAkXMWyWm09/n5mycmFBQXlz1Tr6CglonZtbYgoupXNw4dFeXkYEAQIeeBdAAAgAElEQVQAgoC2HgBBU/eZFTHS0j6zrEp17NCBv7f/+cPC2Zol23d6tVFohEJZpNVn1s/PLCTY4rsldydOcLO0FOfmqnb9/WjQwOIuKQ0aSMLDLc9feBLV3Pripac2NhJra3GtPTsAgEogRgEQtOI8CvMsibJ+7cqYmMitm+dqFpPIOkyZM1/JsmXzKEQ0Y7rn6jX3xk24xTC8paW4dy8HzbUTx7st/vbuip8yLS3Fs2Z4MoyhnxMAgE50iVHQtQrAaNQxCpHo1+WLxWIxW6Q88O9fp04sL1ty9U9LWJZjWVbFshz3XJgil4vGjHYbM9qt3EN4esoXfemn/6oDgJHV+cs38igAgqZu67G1tXmpsYiIJ5LOnfWdt7eLVrFP5/6H4zgiMZGYiFo3GSWRoMkGAOo2xCgAgiaTMURkZmY2beqQSorNmD60tmoEAFBLEKMAaBJcalTd1oP7HoMx6Pes40t+4mTWRfVervr22mLsMYCgIUYBAJOFGAVA0CQShmFIpeJ5RCkAYGIQowAInUTCEJFKhSAFAEwL+qMAGFN8/NNL8fm6lIxdd189xgeg2oLinzYkio9/mrguq/KSGTmBseuy9Xjo+ASdznMATYhRAIzpUnz+uvX3dSn5xyZ9XjDANPXLedqQKD7h6ea0Ks+6wHXrccqBkSFGATC+8HDL8DDLitZu+zM7P5/r09vB0hJTnkCNBB2xpCMUHmYpb+dcecn9u47HdG+l9wpEhFvofZ9QjyFGAdCdIXqE8EQUHmYxZLBjRSUOHHyUn8/17GHn7i4zQAXAhChyLBRHKDzcIqri803t6vGbQwb3rJ1aAVQEzdsAQqfuhlJUVP6NiwEA6ivEKABCp54iRaUydj0AAGoXYhQAocM0bgBgmhCjAAidVIIYBQBMEWIUAKEr7o+iQn8UADAtiFEAhA5tPQBgmhCjAAgdYhQAME2IUQCEDmOPAcA0IUYBEDqplIhIqUQeBQBMC2IUAKFDWw8AmCZd5sLHJyOAMZW09Ri7HgBQx9T5yzfyKABCV5JHQX8UADAtuKcggCYhfu1AWw8YCU45ITDpdwExCoDuDPphUeHOZbLSPIpJf1qBXuFcgjoAbT0AQoc8CgCYJsQoAEKHGAUATBNiFAChQ4wCAKYJMQqA0CFGAQDThD6zAHowe+Li6m2YkRNIFLh/14mrx29WVCYn35XopfOnrs+e+Ht1KwhARNT6zoPWRPt3nTh+JZGIPls62dg1AqgMYhQA/fhs2aJqbBUbm7Ru3a2YHl2HDBlXUZmTJ7Pmzr3QKDx8zpxhNaggACm+X6/4fl1Mj67dJwyaPf4DY1cHoAqIUQD0pXptMXzJzwo315jDDc09UENVn28AwoH+KABCh/seA4BpQowCIHSIUQDANKGtB0Bfapg8N35bD8uyfFVHEItFDMMYtBpQK9DWA3UAYhQAoau1PMrIkYMDA+9VUiA3lw0JeXvUqJGGrgkAACFGARC+WotRfH3Fc+bcraRAcjLt3VtUdnlBgWLWrMWbNu0Wi0XW1pbjxg0eN26wwapJHMctWLBi5sx3dClcw7pdu5Y0cOB7Fy78Vbrk/v0Hb78948yZBIlEHBMT/cMP/7OwMH/h5wAAOkB/FAChq4UYJSkpeeHCTxMSUhYupNLmnvh4unCBsrOr3nzgwMkZGfcTEnbevn1g3741Dx/mGq6qRMRx/Lx5y3UsXI26sSxb6dG5sWMHpqUduXVrX27u4wULVuhYEwB4UYhRAHTHV/yofG3ljyq2lUqJiueZNdTj+vUb7duv3bLlfkHBsxhl+HDas4fGjKEVKyp7EeLjrx8+fPqnnz6zsbEk4p2c7GbNeoeI37x5d3h4j5CQV19/fUJ29kMiXqFQNGjQbNasrxs37hoW1uPixatvvDEpMLBTz55jlEqlQqGwsWk6bdoXQ4Z88PLLQ86ciSfiMzOzAgM7qQ+UkJDYvHlfIn727K8VCmWnTiP69ZtIxO/ffyI6+s0mTXq1bz/4ypUbutTtjTcmNWnSKzS0+9ixH7GsSl03W9vIjz765o03Ju3YcWDt2m0NG3aOjHxtzZqtWs/a1dWxV69XJBKRXC59+eWo1NQMw70vhnlQmV8qKgZgZIhRAISuVtp6mN9+s581S3rs2LNFdnY0bRrFxtKGDZVtef78ldDQQCsrC82FaWmZEybM3bFjxZUru/z8PKdO/VK9PDf3cWRkyLVru4cM6dW588h58z64efNfiUS8bdteInr8+GlMTHRs7Ffff//xsGFT+Ap68H722WQzM9nevas2b15y//6DDz5YsGPHjxcv/rVw4YcjR86osm5EtHTpnIsX/0pI2MHz/Pr1O9UL8/KevPxy1B9/fNesWejUqV8cPLj23Lmt9+5VmEdSKApXrdry+uudK3t1AKAG0B8FQOhqIUbp1Kl9q1Z75s8fs3HjeVHJN5f8fNq5k/bsoV69Ktu23Eji+PHzHTq08PFxJ6Jx4wZ17PiWermZmbxfv65E1KJFREhIYMOGPkQUFRWelJRKRFKppEuXNkQUFtZQqSxKTc2QyWSV1/zIkTP37z8YMqR4ytTHj59WWTci2rRpz4YNO4no/v0HNjZWQ4f2JiK5XNaxYzQRHTt2LiYm2sPDhYhGjXrj7NnLZfegUrGDB3/QtWu7Xr1iKq8hAFQbYhQAfalherzCzSUShmFIpeJ4njfQsN9Dh45v3PiJRPJg4EDavZvUR2FZKiigUaOoSROtej5X1aZNgy9fvvnkyVPNdAXPcwzDaJQsbkGQy2XqhWKxyMzs2e8qlYqI5zieZVmJRExERUUqhiGJRMRxxYOulUrl8xXgiYjn+SZNGu/apdkc9ax65dYtLu7iL79sOnhwrbW15ddf/5qUlKbep5mZnGGK9y+VitX7kUrFWvskIpZlhw6d4uxs/+WXU+pss0gdrTaYFl3aeozeeooHHrXzECiGIbGY4XlSqQyVSikqUo4cmb5smSI6+ll/FCsr6t9fK0ApR0REozZtIkeP/ignJ4+IsrIefvrpsjZtIg8dOpWefo+IVq78Q52fqBLLsr/99hcR7dt3wsxM5unp6uDQID+/4NGjPCLas+eouphEIhaLxUplERG1a9f81KlLJ05cICKO486cSaiybo8e5Xp7u1tbW6pU7Nate8tWo02byGPHzuXnK4ho585DWmt5nh81apaZmWz58k90eVIAxlP3Pu60II8CoEmg/7pSqUilYouKOHW7j955e3vFxnZctOicj8+j0lTNmDG6br5x4zczZ34dFtaLYZgGDazffXeYp6frd9/N7t59DM/zgYE+K1bM1WU/trbWSUmpLVq8oVQWrVu3SD1Z3MKFU7p2HdWwoY+Xl1tpyQkTBkdG9nV1ddq799ctW5ZMnjw/P79ApWJfe61j8+Zhldetc+c2q1Zt7dNnvIWFeXBwQNlqeHq6zpkzoVu3//j5edrb22qtPX06fvXqbW5uTl5eHYjolVdarl37ha6vVB0j0H8H08CX/Hyhd6G+vWWIUQD0pXqfDjp9EkmlooICtqiIJRJX6yhVCA1tOG/e0jlzhs6de7Z04aBBFRXXrqqFhfybb2Z8841mf1W+f/8u/ft30VxiZibLyTml3rxDh6gOHaLUv0+fPpqIFIpCIpo7d9LcuZM0DzRiRJ8RI/qULHlfvXDevMnz5k1Wl2nfvnlcnGa33ueqV17d6Pffv9Z6Rpp1I6Jhw3oPG9a73H22aBHO81crf0EErHpXPgDjQIwCUAfIZOpus4a9rigU7O3blRVITzfo8QEAnoMYBaAOqJ2pZjt0GHHwYKfKy7Rv/4qBjm5mJs/JOWWgnQNAXYQYBaAOKLmtoGHzKN27dzPo/gEAXghiFAB9qWEAUUV/FCIqKmLRjQD0BCcS1AGIUQA0CPVzu9ZuKwjwjFD/HUyLab8LiFEA9MSAw3pKYhQlZ+IfWFBTGNYDdQpiFAB9MejYY3V/FA7XFqgZBClQl+CeggB1gEaMAgBgKpBHAdCd0b56oj8KGAayKSBoiFEA9KUWxvWgrQf0BScS1AFo6wGoA2pnfhQAAEFBjAJQB6CtBwBMENp6APSlFsb1YA43qCGM64G6BDEKgKD16Hm09PefVt7+aWWlN/2DumnnjrbGrgKAECFGARAoRhRe+rujY7CdXUB29tVHj26VLjycjqaf+mDB6B+NXQUAgUKMAiBcPF9hQp5hGGTrAaB+Q4wCoC8GGXv8xRdfKJXKKVOmyOXyMhsgSKk3av+txMkDdQBiFABNgvvgHjJkyIwZM8LCwr799tvu3btrrqo4yWJAJw/sTrqaUHmZkGatmrREB4t6QHD/DibJpN8FxCgAgubh4bFmzZr9+/dPnDhx+fLlS5Ys8fX1LV5njCDl/LHDHbu/XXmZA3tWNWnRpnbqAwD1mC4xikkHcQA6M+DY45iYmLi4uNatW0dFRcXFxQUEBJCR8igMMRZWNlUU4rXrVqgo+PnLjw7t2iwSiS2srHoPfafPsHd0P2jKrWtzJwxeuftc6ZKcB/cXfvif65fOiiWSyNavvD9vmdzcQnMTRf7TH+ZNO/bvdp7n3b39xs/+qvFLUUT098ZfN/ywqKhISTzfpd+wtybP0b0ahlRr7yXGHpuUOv8uI48CUAeo8ygBAQE7duxQ51EcGrb636dfeXt7ent7Bgb4enm5Mwxj0DpkpNxe8vEH5uY233wyatCYj1zcfYlo1x8/ZKTdsrKx79RruIOzR0lZXquvzNyJg83MLX7594KFlU3Og6wd61ZW2ZmGY1mRWFy8u+KfzzZhObbXkNGf/rSZ49j/jR8Uu2zhyA8+0dz8i6mjJRLp2kNX5WbmJ/bumD6y18o95wqePl2xYOaKXacdXT2UhYrb1xLQpwdAyBCjAAhaenr6jBkzTpw4odUf5eHNU6PXbLp1K/lm0u2jR+Me5eR5uLt6e3t4e3n4eHu6ubnovSasim0W3a11zOtH927muOJhz+fj9s748veUpKs/LPzvrEWbnpXWuPQnXUu4dPLI7ydum1taEU8N7J2GTpxBPP1v/MDUpESWVYVHtXnv06UisVhZqHi9mcfrIyem3rreqe/g/Md5a777zMLSOurlrlr7tHd0je7Yk4jEYkmTlu1vX4vXXJualHj60D+/n7gtl5sTT9Ede7bv1nfTym9bd+xpbmll5+BCPMlkZo0imiNEARAyxCgAuqv8gmaQcT2xsbFBQUE//fST1rgenudcXZ1dXZ3btIkiIoVCkX43MyUlPT7h6tY//2YYxsvTw8fbw9vbw8/P28rSsmZ1IyKytLZ+kJ3yw8KJDs5e4c3aly4XicTuXoGqIqXmM9EcNX3j8nnfoBAzC0utodST/veNnaMLz/OLZ47f99eGTq8N5nk+/0lek5btRr7/SVZm+vje0cv/inN0df9q2hiqYCS2slCx+4/Vo6Z8qrn21tVLWkcMbtrywPaNo6Z86u4dMLhtYJNWLzdr1ymm15sSqazmr4w+GGtcD2I0EDTEKACCNnXq1IpWaV6y5XIzfz9ffz/fDi+3IaLc3McpqWmpqelHjp5avXajRCoN9Pfx9/P19vbw8vKQSaXVqIlUbu4VEJR++6arh79cbl5SB37Jp++oVMo3R03XqNlzdXt4PzMrI3398i+JSCQWd3ptsL2TKxEd2rXlwPaNRPTgfkbyzauZacmsSiUWS66cO5WZlmJuYfVSdAcHF3eep25vjkyMP1c2RGFZ1ef/HRbVvkurmB6aa3m++FGK43meSCSSLFyz607i5Uunjvz124871/+8eMM+RoTblgEIFGIUAOGqqotJhV+CbW2twm0bh4c1Vv+Znf3wVtKdlNT0c+fj0+7edbBr4O3lEeDv6x/g4+rirGNHlkdZmRl3UvsO/eDs8T2PHt53s7BSL5/00Q+V100qkxUVFqTdSBCLRYr8p9tWf7/szxMZKUm7/1i1aP2/FpbWyz+bsn9bbHTLFoyKHfTW6Mxb8Yd3bRo0fppEKlXvRyKRlH2+HMvOnzyigYPzmBnztVb5NwpNvnGlIP+xeUklr54/6d8oVF3MNyjENyik2xsj+jRxzky74+btp8vTB4DahxgFQF/0PK6H584TUY+ecZOXlD/WV/dxPQ4O9g4O9i2iIomIZdn7WdlJSck3k+4cOHjsUW6eu5urt5e7l7eHt5eHm2uFHVl4nu5npCRePn0/I6XqZ6VRN2cPH1dP7zdHviOXyeQy6bqfls4Z02/IpFnObl7mFtYqlepC3CE7B8cJk6cpCpWKQuXl+Itfz/8kpFnrXxZ9rMjPl5tb7Fp5wd9r6M8f/8ET79XQPbp7U6sGFl9NGyuTmb07d0neo/wNX/2lPlaRkrWxtxw6/bXIth2/mT1p8ufL5Gbmcft3Hfl764pdZ9OTkx5kpoe3aEdE1y6eEYlEDRycjTI8qgyM6wEohw4xCs5kAOPS61VULBK5uTi7uTi3iS7tyHIvNTU9IeHatj//ZkSMt6eHt5eHt5e7n5+PpcWzAb0u7l5vjp20+eelnfu85eTqpV44++vN5daYnm96MTO3lIglErFYIhYPGjlmSK+YWW/3JqLOAcWdbBiGWbVyef/Bb6lYVsVyPJGTi/uwSbNmjOzp6ukr41sn390yddlBVZHq5O6Lvy/eEd3L558ta+2dXQe38SeiJq1enr7oVyLaE3vEzsmGeP7DBT+umD99xCvBPPFuXn6frdzq4Ox6N/lW7PcLUj8YKZHKLK1s5ixdb2ZuYZwx3AC1oO6f2sijAOjMSP/wldy1p+bkcrm/n7e/n/fL7aOJKDfvcWpqWmrq3SPHTq+O/UMqkQb4+/j7+XipA5eAxjYNHDx8gqqq8PN15olhGIlELJGIJWKxZQO7oODQPsPHN45oVlok52H2jFGvd+7+mlgqZzmWeOJ5vmOfQR37DCKi76f8tnD1Lp7nxRJx656RKYl32cIG/9woeP6gvEqpunUpZei0PjzPm5lbvjt3ybtzl2gWcPP2n//rdq2tqv/a1QOm/exB+BCjAAhdbV5GbaytQ0OCQ0OCiYjjuPv3s1LS7qam3j1/PiHtboa9XQNFjvLnnxZZyniZuMJuLGZWZs+HKMQwjDqJoo5UnF3dch5ma27SwN7RJ6DRlYRLwRGRLMuVEzxopGZcvJweZOaUfVkSLyQ7ezlaNbA08cADoN5AjAKgLwYZe6yPPVeTSMSohze3aP4SEbEse/fuvVu3k1PT0lNT7+bk5rm7unh5uXt5uQf4+zrY21VcZ17EUHGMIhZLxRJFfr7czFzrcCzLEsOoWJZl2TJ7IM0uFDxxIkZc9mW5cupmaMvAupkcwD0FAcqBGAVA6ASSFRCJxJ6e7p6e7uo/CwoKMzIzk24nn7+Q8Of2PQzDeHm6e3t6eHq6+/v5WFg8C0F4nhiGkUrE6odELE6+fauvp4/mzh/nPkpJSvRr2FilKu6PovWsNZfcS84Ob9NIq8DjR0+z0h4Ejo4RyMsFADWHGAVA6ITZZ8LMTObn6+3n693xlXZElJv3OC0tPTXt7vETp39bv8nCwsLf18vT08PL051Vcc/aesTi27cSnzzOm/JWH829MQzz9oT3JVKZolDJchzx2s+a53me54uUqjP/Xsp/oghs4qtV4Mqpm4FNfEQSsTBfLgCoBsQoAPpisHsK1oVrrq21tW1w49DgxqTuyJKVnZp2NzXt7oWLl1NSU8my0R97jgf5egT5uP2w9Ov+/3m//6j3S7e9cfn8ktnv9B04QlGoVKlYllXxpP2sf1+8kyGGiDwbuvab2E0qk2gVuH4mqdPA1nXitSoPxh4DlAMxCoDQ1bn73jEixsXFycXFqXmzJkR0/N+/1iz9MtlGdP1yQp6CU0qDzAqstvy509PTPcDfx97OjojPzrq36ofvVCzLsqqHD7K17ko4dv4grUOUfU2GzuhT7nIAqLsQowAIXV1vu/BpGNqxZ1/17yKx5OWeg3KfFty5nXzh4uXt2/cwYpGLk0Nk91FKucjKTCwRM3Zufs079Kzrz7qsHiFWFa1iREREPHe29moDUBcgRgHQF4ON66njl2t3b//+oyZrLnFwJH8frxgiIsrLe5yafjct7e7t5NRLd1JtrC39fL3NnN2Tbid7ebhLpfXqM6qSvjIMw9Ru+0vdPqnARNSr/38AAzPOx3odD1GqYG1tHdK4UUjjRkTE8VzW/ezU9LtpaRkXL11Oz8iwb9DA18/bz8fby8Pd2dlJx1sLgc7q9bkFdR9iFABNQvzINp0+FgzDOLs4Obs4NYtsQkRKZVH63Yy09IzEG7f2Hzyal5fn4uLi6eHm5+vt7+djbV1h0wnoiamceIJUvd7N9e0tQ4wCoC/1Z1zP07yCxHO3iRHE550VWTV2adTYpZGyqOhB3sPs+9n7bxz9I/cvRiSyt27gYGtnb2PnZOckk0qNXdMq2NkFVrLWwSEoNjbd0HUIis9rSBQfn5cYm56RExi7/mFFJStfC4YWH19QdSETgBgFQOhqecKPlOt3D/wRV/BEUZsHfSFmZOVBVipilQUFafczbzJ3FKSQ8BI5yeVkJie5nDdTD1QWFEfHxpWstbcPWrf+rqHr0C/ncUOi+ITHm9PuEgWuW/+g4rKB6xCjgLHpEqMI4rsUgMmqtRCFVbEn91xMOHaN58nNz9nF27GWDlxjPM8/Lnj86HFuzpOcR09yM59kWltYOdrYN7BqYGdta2NuTQLoyHLq1LeVrH34MHHwoNGGrkPQEWs6QuFh1vJ27vt3HY7p3rKikvt3nYzp3sLQ9YHKRYRr3zLiBdX5yzfyKACCVytBSm523t4Nx7PvPhKJRJExoc1jQoVwXa8epbIoPSMzPT0j/e7dSykJuY/zXJ1dPDzc/Hy8/H29rayM05Fl3rRrlazlG9hmslmjXw+2sZIZrg6KHGvFEQoPt44a4n71+M0hg16tqOTV4zeHDOpmuJoA6AIxCoC+GGrscSV9ZlfM3FCzg5aD47iz++LP7ovX+56NwooamJNN4R3F1eQb548nFDIKIkbOy81ILie5GW8hIlEtVGPMvIGVF8hNTSDiu0/YOaJXo2G9g8xkYgPXqM5/wwZTgBgFQOgqT6NMXzG2JjtXKor2xB69fDKRiBo38391eHu5ubwmOxS+nNy85OTUW7eSb9y8nZqW5mDfwMfb08fH09vb08/XSyLR/6figjE/VpkLY5UFHwxvMrBb4I+brrz6zs5xb4b26+wvFtfVVBaAXiBGARC8Sq9vXA1agjKTs7av3P/ofq5EKmnft0XzjmE13GGdYGNjHR4eEh4eQkQcy927f/9OcnpKStrxuLMZGZlubq6BAb7e3p6+Ph6uri56m5GF56l4orbKeDhbzh0flXgnZ9nGy7/8ee29IRFd23hiVhgwWYhRAPSkmpf2krHHFW9e+Y55jqvOUXk6d+DywS0nOZZz9nLoPSrGzsW2eruq0xiGXF2cXV2cW7VoSkSFhYWpaRkpKenXribu2bM/JzfP3c01MNA3wN/Hz8/bugYdWXietpwtf5jMyo9+37k9srgQEREF+dh+M6X12SvZi9ZcWrnl6vvDw1s3ca32obUqUvyzvkeiUD8gRgEQusrncOO4F77Y5D8u2L32yO3LqQxDkR1C2/eNEkvE1dhP/SOVyvz9fPz9fNR/5uU9Tk5JS0lJP3zk1Jq1m8QSsZenh4+3R0CAj7+vj0z+Ap1bqzERX7MQx3ULYo5fzFzwywVHW/P3h4WHNbR/0Z0A1GmIUQAEr4o8yotd/FKu3/177aGnuQXmVubdhrb1C/XScSccy1Z5oRWJxPWpYcLayiospHFYSPG8Jrm5j1NS05JuJ+/YuS89PcPeztbb28PLy9Pby93Xx0ssrrSXa3UjwNZNXLd90/Wf42nvfXk8LND+vSHhvh7W1dwXQF2DGAVAXww2rkdP/VFYljv9z6W43ReI572C3LoNb29pY6H75vPff9vJ1aeSAvlP8hqGR7w6YKSOO6xzrG2sQkMbh4Y2JiKO4+7fz0pOvZuamn7y9Ln797M93F29vDy8vDx8vNxdXJy1YrWqJuKrbK2IoW5tPDu2dN+6787w2fs7RLlPHBjmbG9Ws2eDtBnUAYhRAARPH3mUvIdPdq85lHEnSyQSRXVt0qprE2KYF8rBOLl69Rn0XiUFsu+lJd06rbXPu8m3RnYOGzf7q9eGT9D9WJpyHmQtmjH2RsJZsVjSJLrDf/+3RG5uoVlgz6bVf6xcrCpS8jzfqe+QYZNm/7poDsuq/jN1HhFtXbX0l0UfbT13TyKVqVRF/Zq5rTlwzdbesVBRsGrxx0d2bxWJxBaW1j0Hj+45eIzutWKIcXF2dnF2btHsJSIqVBampWempqZfv35j795DuXl5bi4u/gE+/r7ePj7eRHoICaQS0Ztd/Xu0916362bf9/a83slv9OvBNlZCvwMAQE0gRgHQnZHue1xFf5SqO7peO510aMtJZWGRtZ1V12Ft3XydOf4Fek1mptw++PfmO4lXtm9Y2nPABHWGIPX2VY7l7J3crG01OknwvFZ9/tmyNqJFu3+3/NZ76DgdD6eFZVXdB7zd/PsNHMvOe2/Yhh+/HPbuR6Vr05Nv/vzV7O+3nnBwcVcWKu4kXuY4LrR5m9il89Q1uXT6iG9Q6LWLp0Mio69dPO3s4WXdwJ7juHnvDZObW/yw/YyFlXXuw+y/N/6iyytZEalE6ufj5efjpf4zL+9xalp6atrdY8dPx67fohAp16zf6OHu6u3l6ePlKa3BrYUszSWj+zXu18nv1z+vd5/494heQcN6NazBZCrIpoCgIUYBELoqxvVUurqoUHVw88nrZ5OIKLCJd8yb0TIz2YveACjl9nU//8guPcdsXv0VEU/EENHyBZOiX3nt5tVzTaJiYnoOLa2M5s55nt//14a5K7Z+/E6/O4mXfRqGKAsVg9r49hg4OvteenZm+uhp8xuGRZa7sFuBLqEAAA4rSURBVHQnDRycW3R4lYhEInF4VNs7iZc1D/Ew6565pbWtgxPP81KZvGFYJM/zIU1bJV2PVxQ8lZtZpNy82m/Ue/GnjwY3bRV/+mhY87Y8z99JvBx/+uiag4nmFpY8z9vYOQwYO0WP90WytrYKCW4UEtxI/ec3H6x6KSI8OTV1/6GjmZn3G9jauLu5uru7ubu5erq7VWP/9rbyD4ZHDOwW8OOmq6+O+3vcmyH9OvlhMhWofxCjAOiL4e57XM1xPffTHvwbezQ3+7FYKol+9aWIdo0rL1/h8Tk6vn/L+bi9t66eL11oadWg18CJykLFlzOHasQoz+3/0qnDtvaOHr4NY3oN/Hdr7NsffsZxfMHTJxEt20e26ZR848r8ycOWbz9T7sKyfW+VhYp/t/42/L8fax6iUUSUm5ffyI6h4S3aNY1+pX33/hKpTG5u6R3Q+Mr5U3aOLu4+gaGRbVbMn9r/P3zC6WMxvQdxHH/z8gWfwGC5mUXtjGaSkDgsuFFYcCMi4jgu+8HD9IzMlLS0M2fP5+blMYz4858oNNAuLKBBgJeN7p2OPZwt5o5vlngnd9nGK7/8ef29IWFdW3tUtbkO5xuAYCBGARC6ckOUAdHO6l927Sq3DYX5fPmpE7vOcSzn6G7XeUjbBo42LzoCqFSTVh0aRUStX/bFu3NWMEzxzPHKwoLzcXvjzxyMjO6iUVVe8yj7tsW+0msQz/Gv9Bo0bXiXEe99wnO8RCJ9qVUMz/HeAcGqImXW3TRbe8eyC53cPDXrwLKqL6e83bR1x6j23TQPIWLEc3/clnzzyuUzx3ZuWLl706oFv/7NiEShzVonnD5m5+gcGtnazcs/IyWpSKm8ej5u0idLeI7nOJ5/8SFRNVH6JjKMyMnR0cnR8aXwMCIqVCpXfbHRy9XyxIV732+4kvu4MCzQPjLYITTQrkmQg71t1XP+BvnafjM1+uyV7EVr4lduuf7+8LDWTVwM+lwAag1iFAChq6g/SkVtEzzPt2z57rHtZxiGIto2btXtJZFYVJPrccKpowd3bmIY8ZLPxk5bsF79TZ3j2CKlosOrg7wDQp+ra8mBFAX5J/Zuvxh3cOuv3xLR49xH547uC49qx3Ecq1KJxRIiUqmK1JuUu7B0rxzHLpr+H1s7x5GTPy33iXj7B3v7B3fsM3RQW+/MtGRXT9/Qpq13rP+xgYNzr8Hv8Bzv0zBk/5/rbOwd7RxdeY73bxSRcvNqwZMnZhaW1X5ZXkhFb6JMJjXjzYf3aqj+8/5DxeVbDy/ffPT77qQZ356RSkWh/g2ahThGBjuGBjQwk1f4id0sxHHdgleOX7y34JeLjrZm7w8Lw2QqUA8gRgHQF0ONPa6kreeLL75QKpVTpkyRy5994WYYJifnjpdvsw79W3g3cicijq/RBLLKosJ2nd9sGNJcsz+K3MyyRfueZWrKlx7r2L/bgpu2+mjpRvWf/2xete+vdaHN23Ice2DHhpjegy+dPCSTmdk5uxYplWUXlu6H5/klcyZIZfKxsxaVfSKZqbcf3M8IbdaaiBITzjIMY2PvyPFccGSrr2eOtnN09Q+O4HguuGn0pp8XhzZrrd6Dd8Pg4JdaLvl/e3ceHGV5xwH8CTdBjiSAQ0FAkwHkUCniFNAZSbVStR49PIrUoSroFByqSEXjVFu0WlBkwhQq9UIBr1rL4XgVjzocM+qoIIeCFJERBQQRvJBs/wguEZKwhA37bPh8/tp99919n+Xd7PPleX7vs7eMuPLGu5o1b7lty6ZnHr//gmHXHcy/0n6kdu1x2/zGbfPbDey7u0jlk0+/emP5pvIxkhVrtv6gTW6PwlY9ivL7HFvQ7ZhW9evtPa3T//i2T9192nML1o8av6hnUd6owT06t29eMuKO5A5Hbf3iqM4F6xa8vm7Z8hBCycjJIYRxpSPS9jYhrWQUiF01vdvgwYPHjh3bs2fPSZMmnXnmmcntq1Y9fcu99zQ9oklapjNat+3w0rzHnn7i763btC8PKCGEZA3K95oa9sz1zJ8968fn/jp5t1/xOfffddOObVtzj2ixYd3/Rg8u/nbnzt/fdk9IhJBI7LsxOUr03tI35s+Zldf6yMvP6BFC6HniKaPGTU0esays7PF/TLj7xvcaNGzUtFnzMeMfbNy4aaIscUTzvLbtO7XMa12vXoNEWaJ77x/dO37sry6/Ntme0Xfc//DkP1/9i34hJ6dZ85ZnXzS8Vqd+alaP2za/yaABHQYN6BBC2LUrsWb950tXb3lj+abHnn1/w+Yvu3Rq2aOwVY+ivJ6FeUUdW5Q/pV5OzneLqaz9TcnLp/Zt9+WuBnfeVVTVIUquW5G8vXHjZz/se9ULz97RtetRIYTBQ/5ybLeOw64467eXT3jt9XcbNKhfPPCEqX8blZtbx391knjIKFBRZgoJlyzdPmNmlY++9cryfTcWFHQJIbRv33769Onz588fMWLElClTSktLO3fuHEJIJMoa5zZOV0Foh2O6XjLyppmTb/v5kNHJjf2Lz993z0QikTzozVP+FSqU6OY2b/Xwy2t3fvN1COHC4ddfOPz68u1lZbufstfG5GsWdu/9z9c2VzxKxUePbH/0TaVPVProxEdeTd7t3OW48hdJPtqwUZOh19w69JpbK33ZtDv4i4bq188p6tiiqGOL8wZ2CiHs+PLbFWu2vrN668I3P548a9m27d98V8jS6oSuBXktGl9wxtGDBnSY9uSK5TtS/ZmhNm1a3n7bZZddcecrL018b+2GlR9ufOC+0Zs3bxs+7KynBt28a1fZBReNu/2vs/5086UH+V4gRTIKpEvNr+tZsmT7kiXbq9rj7f+u2Hdjfn6X5O3i4uJFixb179+/b9++ixYtKiwsDOnoFPey85uvNm74oJodPt20oeL4R6XKH91rn0o31jX7eXMH/N6bNa3fp3tBn+4FIRSG3YUsW95ZteXRZ9ZcP+m1Rg3r9Tgmr0/3glNPbLdp8WchVPmThB/V7z7h+Y577rcZ+kVhp/P++NmCHT+9dNRPJr1UEEIIjXuvfDGEEBr0HvPiJ1snPF/dcsNk0ILVrTLdhDSTUSCTjuu1n//jzpz1ca+Tu+27ffHiicnb5eMohYWFc+fOLR9HCbUwKtD9xAErly+ufp9uvftVf9z6DRo98J/Ve+1T6cY6pga/KXhA2uY3SRaylCUS76/7fMmqLW+/++kzC97M+by6fuujnO5P75U52gz96OvQsM/PZi4NYeleu3cKueHO59PdeqiCjAKZ1KtXs169qru0ZOasj3ud3HXf7ZtveDeEsH79+rFjxy5cuHCvepRQCxfW9u53Wiq7HcoLerPIoRwkqpeze1bo/OJOIYSSEa+H4GpkslIqGcU3DqSi1v5Squ7fZsyY0aVLl2nTplW8rqfcQV7LQ5odxG8KQk1l/efKOArErprebcyYMVU+y3hGTKIttmmXWFZ8+trk3Zkz5xcVtT/ppK7znnx15doNw4ednZvb+N+zF4QQzj2nf+pr4JJxy+ctq6YOKVvIKBC7qkoZqu8wZJSo1HY9So2127Vs9Om7S6EfeviF3NVzH71vYk7OB1tnzz79lPy3Hr362mt+OWbqyHbt8ifNqRdCGHjq8Q89+IeMNpmUlMxeFkJxpltxsGQUiF5lvdv0Fz8MITwyfs7FY86p9El1uwQ1+2TD2RhyyWlDLtlTdXTD2IvLbyS+fS5DLeJwJ6NA6jJTUpDK1bxEbn+nqXZPYsWF2g790aHGZBSIXfW9W1mZ2tgskMEkOW7y6Eq3l4yYMK70d4e4MXBAZBSIX7XjKOZ0soPTBAdMRoF0qb25nuoeLTPXkw32d5acRKiEjAKx2089inGUbKBsCGpARoHoVdu9uX4nO8gocOBkFEiXzMz1JNTMZgNzPVADMgrEr9pxFP9Bzw5OExwwGQViV30ImTPlhUPVEGpOkoQakFEgXTKwhtv5I8+opYOSXpldww2ylIwC0dN/AYclGQUqijEORPtzdNR1PnhkmIwCsVPKAByeZBRIl1qLEkJK3ecUQyVkFEhdZjoSEYVa47NF1GQUiJ16FODwJKNAutTeXE9tvTDRcI6hEjIKxG7OVKu0AYejVDKKgA8ZM29O10w3AchSWd99G0eBdMn6rwOAqMgokCYiCkBa1ct0AwAAKmEcBdLFQApAOhlHAQBiJKMAADGSUQCAGKlHgXRRjwKQTsZRAIAYGUeB1BkpoY7xkSZqMgqki697gHQy1wMAxMg4ClRkLASS/DmQYTIKpIsvdIB0MtcDAMRIRgEAYiSjAAAxUo8C6aIeBSCdjKMAADGSUQCAGKUy12MEG1LhLwWIStZ/KalHgfQoGTk1000AqFNkFEiDcaVXZboJAHWNehQAIEbGUSB1WT+5C5BFjKMAADGSUQCAGMkoAECMZBQAIEYyCgAQIxkFAIiRa48hVVaSBTiUZBSoqMoVUMaVXnko2wERsCAQGWauBwCIkYwCAMRIRgEAYiSjAAAxklEAgBjJKABAjGQUACBGMgoAEKNU1nCzjA8AZJ2s776tMwt7WO0eIB4yCuw2rvSqTDcBgD3UowAAMZJRAIAYySgAQIxkFAAgRjIKABAjGQUAiJGMAgDESEYBAGIkowAAMZJRAIAYySgAQIxkFAAgRjIKABAjGQUAiJGMAgDESEYBAGIkowAAMZJRAIAYySgAQIwapLBPotZbAQDwfcZRAIAYySgAQIxkFAAgRjIKABAjGQUAiJGMAgDESEYBAGIkowAAMZJRAIAY7X+d2ZKRUw9BOwAAKspJJCx1DwBEx1wPABAjGQUAiJGMAgDESEYBAGIkowAAMZJRAIAYySgAQIxkFAAgRv8HzYpf4SffnCQAAAAASUVORK5CYII=",
+ "image/svg+xml": [
+ "Vehicle Equipment compartment Server Compute Card 1 Card 1 OS Camera Driver SWC App 1 SWC Cooling Fan X2 Compute Card 2 Card 2 OS App 2 SWC X2 Network Switch Switch Firmware Switch Configuration P1 P3 P2 Sensor compartment Camera Assembly Camera Firmware car d... PL 1 Eth Cable 2 Eth Cable 3 C 1 C 2 C 3 C 4 C 5 C 6 card1 - card2 connection D 7 D 8 PL 1 C 10 "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "diagram = model.pa.diagrams.by_name(\"[PAB] A sample vehicle arch\")\n",
+ "diagram"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1c479ca3",
+ "metadata": {},
+ "source": [
+ "## Example 1: List components that are visible on a diagram\n",
+ "\n",
+ "To start, let's get all parts on that diagram and turn them into PhysicalComponents."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "711574aa",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "PhysicalComponent "Vehicle" (b327d900-abd2-4138-a111-9ff0684739d8)PhysicalComponent "Equipment compartment" (3d68852d-fcc0-452c-af12-a2fbe22f81fa)PhysicalComponent "Server" (9137f463-7497-40c2-b20a-897158fdba9a)PhysicalComponent "Compute Card 1" (63be604e-883e-41ea-9023-fc74f29906fe)PhysicalComponent "Card 1 OS" (7b188ad0-0d82-4b2c-9913-45292e537871)PhysicalComponent "Camera Driver SWC" (74067f56-33bf-47f5-bb8b-f3604097f653)PhysicalComponent "App 1 SWC" (b80a6fcc-8d35-4675-a2e6-60efcbd61e27)PhysicalComponent "Cooling Fan" (65e82f3f-c5b7-44c1-bfea-8e20bb0230be)PhysicalComponent "Compute Card 2" (3a982128-3281-4d37-8838-a6058b7a25d9)PhysicalComponent "Card 2 OS" (09e19313-c824-467f-9fb5-95ed8b4e2d51)PhysicalComponent "App 2 SWC" (ca5af12c-5259-4844-aaac-9ca9f84aa90b)PhysicalComponent "Network Switch" (b51ccc6f-5f96-4e28-b90e-72463a3b50cf)PhysicalComponent "Switch Firmware" (c78b5d7c-be0c-4ed4-9d12-d447cb39304e)PhysicalComponent "Switch Configuration" (23c47b69-7352-481d-be88-498fb351adbe)PhysicalComponent "Sensor compartment" (3f416925-9d8a-4e9c-99f3-e912efb23d2f)PhysicalComponent "Camera Assembly" (5bfc516b-c20d-4007-9a38-5ba0e889d0a4)PhysicalComponent "Camera Firmware" (db2d86d7-48ee-478b-a6fc-d6387ab0032e) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] \n",
+ "[5] \n",
+ "[6] \n",
+ "[7] \n",
+ "[8] \n",
+ "[9] \n",
+ "[10] \n",
+ "[11] \n",
+ "[12] \n",
+ "[13] \n",
+ "[14] \n",
+ "[15] \n",
+ "[16] "
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "components_on_diagram = diagram.nodes.by_type(\"Part\").map(\"type\")\n",
+ "components_on_diagram"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "aab38c3e",
+ "metadata": {},
+ "source": [
+ "We could also get all components across the entire PA layer by doing `model.pa.all_components`, but we will not go there in this example.\n",
+ "\n",
+ "We can review any single component from that list above:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "21ef5c4d",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/dahbar/projects/py-capellambse/capellambse/model/common/element.py:295: FutureWarning: PhysicalComponent.functions is deprecated, use allocated_functions instead\n",
+ " value = getattr(self, attr)\n",
+ "/home/dahbar/projects/py-capellambse/capellambse/model/common/element.py:363: FutureWarning: PhysicalComponent.functions is deprecated, use allocated_functions instead\n",
+ " value = getattr(self, attr)\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "Cooling Fan (org.polarsys.capella.core.data.pa:PhysicalComponent) allocated_functions (Empty list)
applied_property_value_groups (Empty list)
applied_property_values (Empty list)
components (Empty list)
constraints (Empty list)
context_diagram Context of Cooling Fan (uuid: 65e82f3f-c5b7-44c1-bfea-8e20bb0230be_context)deployed_components (Empty list)
deploying_components Backreference to PhysicalComponent - omitted: can be slow to compute. Display this property directly to show. description diagrams (Empty list)
exchanges (Empty list)
filtering_criteria (Empty list)
functions (Empty list)
is_abstract False is_actor False is_human False kind <Kind.HARDWARE: 2> name Cooling Fan nature <Nature.NODE: 1> owned_components (Empty list)
owner PhysicalComponent "Compute Card 1" (63be604e-883e-41ea-9023-fc74f29906fe)parent PhysicalComponent "Compute Card 1" (63be604e-883e-41ea-9023-fc74f29906fe)parts Backreference to Part - omitted: can be slow to compute. Display this property directly to show. physical_links (Empty list)
physical_paths (Empty list)
physical_ports (Empty list)
ports (Empty list)
progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f4a9f006190> realized_components (Empty list)
realized_logical_components (Empty list)
realizing_components Backreference to - omitted: can be slow to compute. Display this property directly to show. related_exchanges Backreference to ComponentExchange - omitted: can be slow to compute. Display this property directly to show. requirements (Empty list)
state_machines (Empty list)
summary None traces (Empty list)
uuid 65e82f3f-c5b7-44c1-bfea-8e20bb0230be xtype org.polarsys.capella.core.data.pa:PhysicalComponent
"
+ ],
+ "text/plain": [
+ "\n",
+ ".allocated_functions = []\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".components = []\n",
+ ".constraints = []\n",
+ ".context_diagram = \n",
+ ".deployed_components = []\n",
+ ".deploying_components = ... # backreference to PhysicalComponent - omitted: can be slow to compute\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".exchanges = []\n",
+ ".filtering_criteria = []\n",
+ ".functions = []\n",
+ ".is_abstract = False\n",
+ ".is_actor = False\n",
+ ".is_human = False\n",
+ ".kind = \n",
+ ".name = 'Cooling Fan'\n",
+ ".nature = \n",
+ ".owned_components = []\n",
+ ".owner = \n",
+ ".parent = \n",
+ ".parts = ... # backreference to Part - omitted: can be slow to compute\n",
+ ".physical_links = []\n",
+ ".physical_paths = []\n",
+ ".physical_ports = []\n",
+ ".ports = []\n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".realized_components = []\n",
+ ".realized_logical_components = []\n",
+ ".realizing_components = ... # backreference to - omitted: can be slow to compute\n",
+ ".related_exchanges = ... # backreference to ComponentExchange - omitted: can be slow to compute\n",
+ ".requirements = []\n",
+ ".state_machines = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".uuid = '65e82f3f-c5b7-44c1-bfea-8e20bb0230be'\n",
+ ".xtype = 'org.polarsys.capella.core.data.pa:PhysicalComponent'"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "components_on_diagram[7]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "22343924",
+ "metadata": {},
+ "source": [
+ "However we may need just a few of those attributes in a view.\n",
+ "\n",
+ "Now that we have a list of components lets collect some of the attributes of interest in a table. To keep it simple we'll introduce an attribute extractor function that will turn fields of interest into a nice dictionary."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "63ff286c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def extract_attrs_of_interest(component):\n",
+ " return dict(\n",
+ " name=component.name,\n",
+ " nature=component.nature,\n",
+ " kind=component.kind,\n",
+ " components=\"; \".join([cmp.name for cmp in component.components])\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "55d509d0",
+ "metadata": {},
+ "source": [
+ "We can then apply that extractor function to our list of components and use `pandas` to display it for us in a tabular form:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "6d8ff25c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " name \n",
+ " nature \n",
+ " kind \n",
+ " components \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " Vehicle \n",
+ " NODE \n",
+ " SOFTWARE_DEPLOYMENT_UNIT \n",
+ " Equipment compartment; Sensor compartment \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " Equipment compartment \n",
+ " NODE \n",
+ " FACILITIES \n",
+ " Server; Network Switch \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " Server \n",
+ " NODE \n",
+ " HARDWARE \n",
+ " Compute Card 1; Compute Card 2 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " Compute Card 1 \n",
+ " NODE \n",
+ " HARDWARE \n",
+ " Card 1 OS; Cooling Fan \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " Card 1 OS \n",
+ " BEHAVIOR \n",
+ " SERVICES \n",
+ " Camera Driver SWC; App 1 SWC \n",
+ " \n",
+ " \n",
+ " 5 \n",
+ " Camera Driver SWC \n",
+ " BEHAVIOR \n",
+ " SOFTWARE \n",
+ " \n",
+ " \n",
+ " \n",
+ " 6 \n",
+ " App 1 SWC \n",
+ " BEHAVIOR \n",
+ " SOFTWARE \n",
+ " \n",
+ " \n",
+ " \n",
+ " 7 \n",
+ " Cooling Fan \n",
+ " NODE \n",
+ " HARDWARE \n",
+ " \n",
+ " \n",
+ " \n",
+ " 8 \n",
+ " Compute Card 2 \n",
+ " NODE \n",
+ " HARDWARE \n",
+ " Card 2 OS \n",
+ " \n",
+ " \n",
+ " 9 \n",
+ " Card 2 OS \n",
+ " BEHAVIOR \n",
+ " SOFTWARE \n",
+ " App 2 SWC \n",
+ " \n",
+ " \n",
+ " 10 \n",
+ " App 2 SWC \n",
+ " BEHAVIOR \n",
+ " SOFTWARE \n",
+ " \n",
+ " \n",
+ " \n",
+ " 11 \n",
+ " Network Switch \n",
+ " NODE \n",
+ " HARDWARE \n",
+ " Switch Firmware; Switch Configuration \n",
+ " \n",
+ " \n",
+ " 12 \n",
+ " Switch Firmware \n",
+ " BEHAVIOR \n",
+ " HARDWARE_COMPUTER \n",
+ " \n",
+ " \n",
+ " \n",
+ " 13 \n",
+ " Switch Configuration \n",
+ " BEHAVIOR \n",
+ " DATA \n",
+ " \n",
+ " \n",
+ " \n",
+ " 14 \n",
+ " Sensor compartment \n",
+ " NODE \n",
+ " FACILITIES \n",
+ " Camera Assembly \n",
+ " \n",
+ " \n",
+ " 15 \n",
+ " Camera Assembly \n",
+ " NODE \n",
+ " HARDWARE \n",
+ " Camera Firmware \n",
+ " \n",
+ " \n",
+ " 16 \n",
+ " Camera Firmware \n",
+ " BEHAVIOR \n",
+ " SOFTWARE_EXECUTION_UNIT \n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " name nature kind \\\n",
+ "0 Vehicle NODE SOFTWARE_DEPLOYMENT_UNIT \n",
+ "1 Equipment compartment NODE FACILITIES \n",
+ "2 Server NODE HARDWARE \n",
+ "3 Compute Card 1 NODE HARDWARE \n",
+ "4 Card 1 OS BEHAVIOR SERVICES \n",
+ "5 Camera Driver SWC BEHAVIOR SOFTWARE \n",
+ "6 App 1 SWC BEHAVIOR SOFTWARE \n",
+ "7 Cooling Fan NODE HARDWARE \n",
+ "8 Compute Card 2 NODE HARDWARE \n",
+ "9 Card 2 OS BEHAVIOR SOFTWARE \n",
+ "10 App 2 SWC BEHAVIOR SOFTWARE \n",
+ "11 Network Switch NODE HARDWARE \n",
+ "12 Switch Firmware BEHAVIOR HARDWARE_COMPUTER \n",
+ "13 Switch Configuration BEHAVIOR DATA \n",
+ "14 Sensor compartment NODE FACILITIES \n",
+ "15 Camera Assembly NODE HARDWARE \n",
+ "16 Camera Firmware BEHAVIOR SOFTWARE_EXECUTION_UNIT \n",
+ "\n",
+ " components \n",
+ "0 Equipment compartment; Sensor compartment \n",
+ "1 Server; Network Switch \n",
+ "2 Compute Card 1; Compute Card 2 \n",
+ "3 Card 1 OS; Cooling Fan \n",
+ "4 Camera Driver SWC; App 1 SWC \n",
+ "5 \n",
+ "6 \n",
+ "7 \n",
+ "8 Card 2 OS \n",
+ "9 App 2 SWC \n",
+ "10 \n",
+ "11 Switch Firmware; Switch Configuration \n",
+ "12 \n",
+ "13 \n",
+ "14 Camera Assembly \n",
+ "15 Camera Firmware \n",
+ "16 "
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "pd.DataFrame(list(map(extract_attrs_of_interest, components_on_diagram)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91a9ab15",
+ "metadata": {},
+ "source": [
+ "## Example 2: Create HW-SW allocation table\n",
+ "\n",
+ "Now let's assume that components of \"Node\" nature are hardware things and \"Behavior\" corresponds to software components. Assuming that, let's identify leaf hardware components (lowest replaceable units), and for each of those indicate which software components they have.\n",
+ "\n",
+ "To get there, let's first filter out the list of components of \"Node\" nature that have at least one subcomponent of \"Behavior\" nature. We'll use the `.filter` method of our object list. To use that method we'll need to provide a function or lambda that determines whether an object should be selected. We can also make use of the implicit \"truthiness\" of non-empty list attributes:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "01644c9d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "PhysicalComponent "Sub PC" (793e6da2-d019-4716-a5c5-af8ad550ca5e)PhysicalComponent "Deploy Sub PC" (8a6c6ec9-095d-4d8b-9728-69bc79af5f27)PhysicalComponent "Compute Card 1" (63be604e-883e-41ea-9023-fc74f29906fe)PhysicalComponent "Compute Card 2" (3a982128-3281-4d37-8838-a6058b7a25d9)PhysicalComponent "Network Switch" (b51ccc6f-5f96-4e28-b90e-72463a3b50cf)PhysicalComponent "Camera Assembly" (5bfc516b-c20d-4007-9a38-5ba0e889d0a4)PhysicalComponent "Computer" (b14ff190-9198-4d05-95db-b121c11e9f17)PhysicalComponent "ISP Network" (221cef9f-0582-419c-b67e-96ddb678dd4c) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] \n",
+ "[5] \n",
+ "[6] \n",
+ "[7] "
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cmps = model.pa.all_components[1:].by_nature(\"NODE\")\n",
+ "# Note: the above [1:] assumes that 0th component is the root component and is not of interest (+ see issue #41)\n",
+ "cmps_with_sw = cmps.filter(lambda i: i.components.by_nature(\"BEHAVIOR\"))\n",
+ "cmps_with_sw"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4286bd9d",
+ "metadata": {},
+ "source": [
+ "For sure we could come to the above list filtering by `kind` attribute, however in practice not all projects strictly use the `kind` attribute / it needs manual setting and maintenance and therefore is a bit less reliable.\n",
+ "\n",
+ "Our next stop is to list the SW components of those HW components. As SW components may be nested (i.e. apps on OS or partitions, etc.) we would simply \"flatten\" that hierarchy. We can create function `get_sw_components` that would recursively crawl down the SW components tree and give us back a flat list and test it on one component."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "70abf6f9",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "PhysicalComponent "Card 1 OS" (7b188ad0-0d82-4b2c-9913-45292e537871)PhysicalComponent "Camera Driver SWC" (74067f56-33bf-47f5-bb8b-f3604097f653)PhysicalComponent "App 1 SWC" (b80a6fcc-8d35-4675-a2e6-60efcbd61e27) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] "
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "def get_sw_components(sw_component):\n",
+ " subcmp = sw_component.components.by_nature(\"BEHAVIOR\")\n",
+ " for cmp in subcmp:\n",
+ " subcmp += get_sw_components(cmp)\n",
+ " return subcmp\n",
+ "\n",
+ "get_sw_components(cmps_with_sw.by_name(\"Compute Card 1\"))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8086d62c",
+ "metadata": {},
+ "source": [
+ "Let's apply the `get_sw_components` function to the complete list of components with SW, `cmps_with_sw`, and turn the results into a table. In this table we'll serialize SW components into a semicolon-separated string:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "faa00eb0",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " hardware_component \n",
+ " deployed_sw_components \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " Sub PC \n",
+ " PC 16 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " Deploy Sub PC \n",
+ " PC 17 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " Compute Card 1 \n",
+ " Card 1 OS; Camera Driver SWC; App 1 SWC \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " Compute Card 2 \n",
+ " Card 2 OS; App 2 SWC \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " Network Switch \n",
+ " Switch Firmware; Switch Configuration \n",
+ " \n",
+ " \n",
+ " 5 \n",
+ " Camera Assembly \n",
+ " Camera Firmware \n",
+ " \n",
+ " \n",
+ " 6 \n",
+ " Computer \n",
+ " Mail client \n",
+ " \n",
+ " \n",
+ " 7 \n",
+ " ISP Network \n",
+ " Mail server \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " hardware_component deployed_sw_components\n",
+ "0 Sub PC PC 16\n",
+ "1 Deploy Sub PC PC 17\n",
+ "2 Compute Card 1 Card 1 OS; Camera Driver SWC; App 1 SWC\n",
+ "3 Compute Card 2 Card 2 OS; App 2 SWC\n",
+ "4 Network Switch Switch Firmware; Switch Configuration\n",
+ "5 Camera Assembly Camera Firmware\n",
+ "6 Computer Mail client\n",
+ "7 ISP Network Mail server"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "def describe_hw_component_sw_allocations(hw_component):\n",
+ " return dict(\n",
+ " hardware_component=hw_component.name,\n",
+ " deployed_sw_components=\"; \".join(i.name for i in get_sw_components(hw_component))\n",
+ " )\n",
+ "\n",
+ "df = pd.DataFrame(list(map(describe_hw_component_sw_allocations, cmps_with_sw)))\n",
+ "df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "851b0540",
+ "metadata": {},
+ "source": [
+ "To complete the picture, we could also list all HW components that don't have software (so that a sanity check could be performed):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "e48d4998",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "PhysicalComponent "PC 1" (8a6d68c8-ac3d-4654-a07e-ada7adeed09f)PhysicalComponent "PC 3" (f5d7980d-e1e9-4515-8bb0-be7e80ac5839)PhysicalComponent "Vehicle" (a2c7f619-b38a-4b92-94a5-cbaa631badfc)PhysicalComponent "Vehicle" (b327d900-abd2-4138-a111-9ff0684739d8)PhysicalComponent "Equipment compartment" (3d68852d-fcc0-452c-af12-a2fbe22f81fa)PhysicalComponent "Server" (9137f463-7497-40c2-b20a-897158fdba9a)PhysicalComponent "Cooling Fan" (65e82f3f-c5b7-44c1-bfea-8e20bb0230be)PhysicalComponent "Sensor compartment" (3f416925-9d8a-4e9c-99f3-e912efb23d2f)PhysicalComponent "Router" (69bfe48d-78f0-4b1f-89c0-917dc2339ff9)PhysicalComponent "PA 1" (a0847e9c-8b82-407d-8143-e908e2db97a1) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] \n",
+ "[5] \n",
+ "[6] \n",
+ "[7] \n",
+ "[8] \n",
+ "[9] "
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cmps_without_sw = cmps.filter(lambda i: not i.components.by_nature(\"BEHAVIOR\"))\n",
+ "cmps_without_sw"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/_sources/examples/03 Data Values.ipynb.txt b/_sources/examples/03 Data Values.ipynb.txt
new file mode 100644
index 000000000..cb55718ab
--- /dev/null
+++ b/_sources/examples/03 Data Values.ipynb.txt
@@ -0,0 +1,601 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1a1fe414",
+ "metadata": {},
+ "source": [
+ "# Data Types and Data Values\n",
+ "\n",
+ "This Jupyter notebook demonstrates how Data Values in Capella can be handled.\n",
+ "First, let's load the model again..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3e28d1c9",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Cannot load PVMT extension: ValueError: Provided model does not have a PropertyValuePkg\n",
+ "Property values are not available in this model\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import capellambse\n",
+ "path_to_model = \"../../../tests/data/melodymodel/5_2/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)\n",
+ "model"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "48ce0c1e",
+ "metadata": {},
+ "source": [
+ "As explained in the notebook 01, please ignore the warning about PVMT missing above."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7e68b88c-b4bc-4c20-a39f-48094c0eabdd",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "## Example 1: Look into the Data package of the Logical Architecture\n",
+ "\n",
+ "Let's have a look into the data package on the Logical Architecture. It works the same with the other architectures, just replace the `oa` accordingly. We can see the defined classes, collections, enuemrations, and so on."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "da8b86b7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Data (org.polarsys.capella.core.data.information:DataPkg) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
classes Class "Wand" (c710f1c2-ede6-444e-9e2b-0ff30d7fd040)Class "Class 2" (1adf8097-18f9-474e-b136-6c845fc6d9e9)Class "Branch" (2b34c799-769c-42f2-8a1b-4533dba209a0)collections (Empty list)
complex_values (Empty list)
constraints (Empty list)
description diagrams [CDB] Harry's Wand (uuid: _kqdwsF9REe2rko4oG1H6IQ)enumerations Enumeration "Wand Core" (546cd75a-c7ac-4e07-9d2d-8a1f93d82419)Enumeration "Wand Wood" (60314ce6-bc96-4b57-8965-7187241148ae)filtering_criteria (Empty list)
name Data packages DataPkg "Wand Objects" (880af86d-6fac-4fba-a559-2fffd036fa9a)parent LogicalArchitecture "Logical Architecture" (853cb005-cba0-489b-8fe3-bb694ad4543b)progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
requirements (Empty list)
summary None traces (Empty list)
unions (Empty list)
uuid 39e99d4a-a32c-4b70-b4b6-d03fec612e17 xtype org.polarsys.capella.core.data.information:DataPkg
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".classes = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ ".collections = []\n",
+ ".complex_values = []\n",
+ ".constraints = []\n",
+ ".description = ''\n",
+ ".diagrams = [0] \n",
+ ".enumerations = [0] \n",
+ " [1] \n",
+ ".filtering_criteria = []\n",
+ ".name = 'Data'\n",
+ ".packages = [0] \n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".unions = []\n",
+ ".uuid = '39e99d4a-a32c-4b70-b4b6-d03fec612e17'\n",
+ ".xtype = 'org.polarsys.capella.core.data.information:DataPkg'"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.la.data_package"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e01263c2",
+ "metadata": {},
+ "source": [
+ "For Enumerations we can see the Literals assigned to it. We can see both the literals that have been inherited by the specialized super class, and the literals that are defined within this model element (own_literals)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "abcd8693",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Wand Core (org.polarsys.capella.core.data.information.datatype:Enumeration) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
constraints (Empty list)
description diagrams (Empty list)
filtering_criteria (Empty list)
literals EnumerationLiteral "Unicorn Hair" (79263437-b45d-410d-a264-8aa28d7574d1)EnumerationLiteral "Dragon Heartstring" (6bb9876c-f3a7-4d59-a6d1-819372368fa0)EnumerationLiteral "Pheonix Feather" (492fd9ca-88cb-4e9d-b92e-df14a1c1543b)EnumerationLiteral "Thestral Tail-Hair" (1e73d13b-1c26-4537-834d-e467f993befe)name Wand Core owned_literals EnumerationLiteral "Unicorn Hair" (79263437-b45d-410d-a264-8aa28d7574d1)EnumerationLiteral "Dragon Heartstring" (6bb9876c-f3a7-4d59-a6d1-819372368fa0)EnumerationLiteral "Pheonix Feather" (492fd9ca-88cb-4e9d-b92e-df14a1c1543b)EnumerationLiteral "Thestral Tail-Hair" (1e73d13b-1c26-4537-834d-e467f993befe)parent DataPkg "Data" (39e99d4a-a32c-4b70-b4b6-d03fec612e17)progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
requirements (Empty list)
sub Backreference to Enumeration - omitted: can be slow to compute. Display this property directly to show. summary None super None traces (Empty list)
uuid 546cd75a-c7ac-4e07-9d2d-8a1f93d82419 xtype org.polarsys.capella.core.data.information.datatype:Enumeration
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".constraints = []\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".literals = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ ".name = 'Wand Core'\n",
+ ".owned_literals = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".requirements = []\n",
+ ".sub = ... # backreference to Enumeration - omitted: can be slow to compute\n",
+ ".summary = None\n",
+ ".super = None\n",
+ ".traces = []\n",
+ ".uuid = '546cd75a-c7ac-4e07-9d2d-8a1f93d82419'\n",
+ ".xtype = 'org.polarsys.capella.core.data.information.datatype:Enumeration'"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.la.data_package.enumerations[0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dfcbe9cf",
+ "metadata": {},
+ "source": [
+ "Let's do the same for a class. Again, we can see the properties of the super class and the properties of the own model element.\n",
+ "\n",
+ "![Harry's Wand](../_static/img/harrys_wand.png)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "a968821f",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Wand (org.polarsys.capella.core.data.information:Class) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
constraints (Empty list)
description diagrams (Empty list)
filtering_criteria (Empty list)
is_abstract False is_final False is_primitive False name Wand owned_properties Property "owner" (9b1f6d9c-58d6-4e5e-a0f1-822cb5440a51)Property "core" (32f70910-a1fd-4ec9-8d22-4c585ceaf7b9)Property "wood" (df884a71-e774-49e1-8aee-0a675179c647)parent DataPkg "Data" (39e99d4a-a32c-4b70-b4b6-d03fec612e17)progress_status NOT_SET properties Property "owner" (9b1f6d9c-58d6-4e5e-a0f1-822cb5440a51)Property "core" (32f70910-a1fd-4ec9-8d22-4c585ceaf7b9)Property "wood" (df884a71-e774-49e1-8aee-0a675179c647)Property "wood" (87f356eb-c79e-4155-b297-8d733685621c)property_value_groups (Empty list)
property_values (Empty list)
realizations InformationRealization "" (793520e1-acbf-4f93-a219-587840aa5a3b)realized_by Backreference to Class - omitted: can be slow to compute. Display this property directly to show. realized_classes Class "SpecialTwist" (0fef2887-04ce-4406-b1a1-a1b35e1ce0f3)requirements (Empty list)
state_machines (Empty list)
sub Backreference to Class - omitted: can be slow to compute. Display this property directly to show. summary None super Class "Branch" (2b34c799-769c-42f2-8a1b-4533dba209a0)traces (Empty list)
uuid c710f1c2-ede6-444e-9e2b-0ff30d7fd040 visibility <VisibilityKind.UNSET: 1> xtype org.polarsys.capella.core.data.information:Class
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".constraints = []\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".is_abstract = False\n",
+ ".is_final = False\n",
+ ".is_primitive = False\n",
+ ".name = 'Wand'\n",
+ ".owned_properties = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".properties = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".realizations = [0] \n",
+ ".realized_by = ... # backreference to Class - omitted: can be slow to compute\n",
+ ".realized_classes = [0] \n",
+ ".requirements = []\n",
+ ".state_machines = []\n",
+ ".sub = ... # backreference to Class - omitted: can be slow to compute\n",
+ ".summary = None\n",
+ ".super = \n",
+ ".traces = []\n",
+ ".uuid = 'c710f1c2-ede6-444e-9e2b-0ff30d7fd040'\n",
+ ".visibility = \n",
+ ".xtype = 'org.polarsys.capella.core.data.information:Class'"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.la.data_package.classes[0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b7bc5a40",
+ "metadata": {},
+ "source": [
+ "We can investigate the properties of a Class"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "56bb4b44",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "owner (org.polarsys.capella.core.data.information:Property) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
association Backreference to Association - omitted: can be slow to compute. Display this property directly to show. constraints (Empty list)
default_value None description diagrams (Empty list)
filtering_criteria (Empty list)
is_abstract False is_derived False is_ordered False is_part_of_key False is_read_only False is_static False is_unique False kind <AggregationKind.UNSET: 1> max None max_card LiteralNumericValue "": 1 (43e39098-ace4-47c4-8f1c-1df1986063e2)min None min_card LiteralNumericValue "": 1 (95d6a6e5-6442-408d-afb2-d8f7a24c5f56)name owner null_value None parent Class "Wand" (c710f1c2-ede6-444e-9e2b-0ff30d7fd040)progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
requirements (Empty list)
summary None traces (Empty list)
type GenericElement "String" (b2f035e6-78c8-4dfd-99f0-bf4a40ea3e81)uuid 9b1f6d9c-58d6-4e5e-a0f1-822cb5440a51 visibility <VisibilityKind.UNSET: 1> xtype org.polarsys.capella.core.data.information:Property
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".association = ... # backreference to Association - omitted: can be slow to compute\n",
+ ".constraints = []\n",
+ ".default_value = None\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".is_abstract = False\n",
+ ".is_derived = False\n",
+ ".is_ordered = False\n",
+ ".is_part_of_key = False\n",
+ ".is_read_only = False\n",
+ ".is_static = False\n",
+ ".is_unique = False\n",
+ ".kind = \n",
+ ".max = None\n",
+ ".max_card = \n",
+ ".min = None\n",
+ ".min_card = \n",
+ ".name = 'owner'\n",
+ ".null_value = None\n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".type = \n",
+ ".uuid = '9b1f6d9c-58d6-4e5e-a0f1-822cb5440a51'\n",
+ ".visibility = \n",
+ ".xtype = 'org.polarsys.capella.core.data.information:Property'"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.la.data_package.classes[0].properties[0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "36670ae2",
+ "metadata": {},
+ "source": [
+ "As you can see the `kind` attribute is `UNSET`. That means this property isn't modelled as an association. An example for a `COMPOSITION`:\n",
+ "\n",
+ "![Waypoint](../_static/img/waypoints.png)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "7ca2429b",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "waypoints (org.polarsys.capella.core.data.information:Property) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
association Backreference to Association - omitted: can be slow to compute. Display this property directly to show. constraints (Empty list)
default_value None description diagrams (Empty list)
filtering_criteria (Empty list)
is_abstract False is_derived False is_ordered False is_part_of_key False is_read_only False is_static False is_unique False kind <AggregationKind.COMPOSITION: 4> max None max_card LiteralNumericValue "": inf (57d146cf-6e40-42f4-9413-1cd0240d1431)min None min_card LiteralNumericValue "": 1 (1df38231-5a0a-4c47-8c99-96119b8b8af8)name waypoints null_value None parent Class "Trajectory" (c3c96805-d6f6-4092-b9f4-df7970651cdc)progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
requirements (Empty list)
summary None traces (Empty list)
type Class "Waypoint" (c89849fd-0643-4708-a4da-74c9ea9ca7b1)uuid 424efd65-eaa9-4220-b61b-fb3340dbc19a visibility <VisibilityKind.UNSET: 1> xtype org.polarsys.capella.core.data.information:Property
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".association = ... # backreference to Association - omitted: can be slow to compute\n",
+ ".constraints = []\n",
+ ".default_value = None\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".is_abstract = False\n",
+ ".is_derived = False\n",
+ ".is_ordered = False\n",
+ ".is_part_of_key = False\n",
+ ".is_read_only = False\n",
+ ".is_static = False\n",
+ ".is_unique = False\n",
+ ".kind = \n",
+ ".max = None\n",
+ ".max_card = \n",
+ ".min = None\n",
+ ".min_card = \n",
+ ".name = 'waypoints'\n",
+ ".null_value = None\n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".type = \n",
+ ".uuid = '424efd65-eaa9-4220-b61b-fb3340dbc19a'\n",
+ ".visibility = \n",
+ ".xtype = 'org.polarsys.capella.core.data.information:Property'"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "prop = model.sa.all_classes.by_name(\"Trajectory\").properties[0]\n",
+ "prop"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7ab5f3a6",
+ "metadata": {},
+ "source": [
+ "The role name is exposed as the `name` attribute of the property. As you can see the only *navigable* role is `waypoints` and its min- and max-card are also accessible. The `Class` can be accessed via the `type` attribute and the `association` is there to receive information about the incoming role/property. Let's have a look at it:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "90c3cf8c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "waypoint association (org.polarsys.capella.core.data.information:Association) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
constraints (Empty list)
description diagrams (Empty list)
filtering_criteria (Empty list)
members Property "trajectory" (c0e5b34c-297e-4b3c-8957-58bbe4d36199)name waypoint association navigable_members Property "waypoints" (424efd65-eaa9-4220-b61b-fb3340dbc19a)parent DataPkg "Data" (814464a3-3278-48eb-b66c-e255ed11afa8)progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
requirements (Empty list)
roles Property "trajectory" (c0e5b34c-297e-4b3c-8957-58bbe4d36199)Property "waypoints" (424efd65-eaa9-4220-b61b-fb3340dbc19a)source_role Property "trajectory" (c0e5b34c-297e-4b3c-8957-58bbe4d36199)summary Find waypoints and you will finish consistently. traces (Empty list)
uuid 3d738685-83e8-45f9-ade2-d5bcc6de1a0c xtype org.polarsys.capella.core.data.information:Association
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".constraints = []\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".members = [0] \n",
+ ".name = 'waypoint association'\n",
+ ".navigable_members = [0] \n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".requirements = []\n",
+ ".roles = [0] \n",
+ " [1] \n",
+ ".source_role = \n",
+ ".summary = 'Find waypoints and you will finish consistently.'\n",
+ ".traces = []\n",
+ ".uuid = '3d738685-83e8-45f9-ade2-d5bcc6de1a0c'\n",
+ ".xtype = 'org.polarsys.capella.core.data.information:Association'"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "prop.association"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "19c3fffc",
+ "metadata": {},
+ "source": [
+ "An `Association` has `navigable_members` which can be at most 2 (the source and target roles) and a `source_role`. Whenever the `is Navigable` option is ticked in Capella the property element will appear underneath the target `Class` of the `Association`."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eb05ea54",
+ "metadata": {},
+ "source": [
+ "## Example 2: Complex Values (instances of Classes)\n",
+ "\n",
+ "Capella allows to create Complex Values which have the type of a class model element. Complex Values can contain Value Parts that instantiate the properties of the class. Let's have a look at Harry's wand:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "77a5dc04",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Harry's Wand (org.polarsys.capella.core.data.information.datavalue:ComplexValue) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
constraints (Empty list)
description diagrams (Empty list)
filtering_criteria (Empty list)
name Harry's Wand parent DataPkg "Wand Objects" (880af86d-6fac-4fba-a559-2fffd036fa9a)progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
requirements (Empty list)
summary None traces (Empty list)
type Class "Wand" (c710f1c2-ede6-444e-9e2b-0ff30d7fd040)uuid 3a467d68-f53c-4d66-9d32-fe032a8cb2c5 value_parts ValuePart "": \n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".constraints = []\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".is_abstract = False\n",
+ ".name = 'LiteralStringValue'\n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".type = \n",
+ ".uuid = 'f7b00d88-cf53-4ae0-a0e6-bb2049b4bdea'\n",
+ ".value = 'Harry Potter'\n",
+ ".xtype = 'org.polarsys.capella.core.data.information.datavalue:LiteralStringValue' (c996225b-5b1f-4d53-83cb-2bc72597e8ad) ValuePart "": \n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".constraints = []\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".name = 'EnumerationReference'\n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".type = \n",
+ ".uuid = '3406b669-4572-44e9-b703-1e319c350e9b'\n",
+ ".value = \n",
+ ".xtype = 'org.polarsys.capella.core.data.information.datavalue:EnumerationReference' (66da894f-6261-47ac-9ad7-217db04671d2) ValuePart "": \n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".constraints = []\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".name = 'EnumerationReference'\n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".type = \n",
+ ".uuid = '9645687f-9485-45f0-a10b-01f8b9d24914'\n",
+ ".value = \n",
+ ".xtype = 'org.polarsys.capella.core.data.information.datavalue:EnumerationReference' (a10de770-c6de-43fc-8d9f-868efe5cd29f) xtype org.polarsys.capella.core.data.information.datavalue:ComplexValue
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".constraints = []\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".name = \"Harry's Wand\"\n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".type = \n",
+ ".uuid = '3a467d68-f53c-4d66-9d32-fe032a8cb2c5'\n",
+ ".value_parts = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ ".xtype = 'org.polarsys.capella.core.data.information.datavalue:ComplexValue'"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.la.data_package.packages[0].complex_values[0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8e7b17c0",
+ "metadata": {},
+ "source": [
+ "and let's see what wood Harry's wand is made of:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "0557c2a5",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "The owner of Harry's Wand is Harry Potter.\n",
+ "The core of Harry's Wand is Pheonix Feather.\n",
+ "The wood of Harry's Wand is Holly.\n"
+ ]
+ }
+ ],
+ "source": [
+ "from capellambse.model.crosslayer.information import datavalue\n",
+ "\n",
+ "instance = model.la.data_package.packages[0].complex_values[0]\n",
+ "for value_part in instance.value_parts:\n",
+ " value = value_part.value.value\n",
+ " if isinstance(value, datavalue.EnumerationLiteral):\n",
+ " value = value.name\n",
+ "\n",
+ " print(f\"The {value_part.referenced_property.name} of {instance.name} is {value}.\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/_sources/examples/04 Intro to Jinja templating.ipynb.txt b/_sources/examples/04 Intro to Jinja templating.ipynb.txt
new file mode 100644
index 000000000..bfc6cbd0e
--- /dev/null
+++ b/_sources/examples/04 Intro to Jinja templating.ipynb.txt
@@ -0,0 +1,656 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Using capellambse with Jinja2\n",
+ "\n",
+ "Welcome to the py-capellambse jinja2 templating showcase. When using capella\n",
+ "for systems engineering you might want to generate documentation for your model\n",
+ "you can use M2DOC, one of capella's [addons] which we found too challenging or\n",
+ "you can use Jinja2 a richful templating language with high degree of freedom.\n",
+ "\n",
+ "This notebook will introduce you into writing jinja2 templates where you'll plant model\n",
+ "information and diagrams. Additonally we'll give a side-note on how to handle\n",
+ "unique identifiers professionally with PVMT and some hints onto how to use jinja\n",
+ "in a professional manner which could give you the option onto developping an\n",
+ "automated document generation system.\n",
+ "\n",
+ "With Jinja2 you are able to generate any text-based format(HTML, XML, CSV, LaTex,...)\n",
+ "but during this tutorial we will only generate .html files. The jinja2 syntax is\n",
+ "inspired by python. Check out their [docs]!\n",
+ "\n",
+ "[docs]: https://jinja2docs.readthedocs.io/en/stable/\n",
+ "[addons]: https://www.eclipse.org/capella/addons.html\n",
+ "\n",
+ "Below code loads the needed libraries and instantiates a test model:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Cannot load PVMT extension: ValueError: Provided model does not have a PropertyValuePkg\n",
+ "Property values are not available in this model\n"
+ ]
+ }
+ ],
+ "source": [
+ "import jinja2\n",
+ "import capellambse\n",
+ "\n",
+ "from IPython.core.display import HTML\n",
+ "\n",
+ "path_to_model = \"../../../tests/data/melodymodel/5_0/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)\n",
+ "env = jinja2.Environment()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In the following we want to make a template to document all modelled actors from\n",
+ "the logical layer. Therefore we define a template string where we iterate over\n",
+ "all actors and plant the name, uuid and description into it.\n",
+ "\n",
+ "*Hint: Make sure that you know of capella's [metamodel] as we are implementing the\n",
+ "capellambse.layers as close as possible to it while being as efficient and pythonic\n",
+ "we can be currently. This knowledge can shorten used statements in the template immensely!*\n",
+ "\n",
+ "[metamodel]: https://dsd-dbs.github.io/py-capellambse/start/intro-to-api.html"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "Actor definitions \n",
+ "\n",
+ " Prof. A. P. W. B. Dumbledore \n",
+ " Actor definition \n",
+ " UUID: 08e02248-504d-4ed8-a295-c7682a614f66
\n",
+ "
Principal of Hogwarts, wearer of the elder wand and greatest mage of all time.
\n",
+ "
\n",
+ "\n",
+ " Prof. S. Snape \n",
+ " Actor definition \n",
+ " UUID: 6f463eed-c77b-4568-8078-beec0536f243
\n",
+ "
Good guy and teacher of brewing arts.
\n",
+ "\n",
+ "\n",
+ " Harry J. Potter \n",
+ " Actor definition \n",
+ " UUID: a8c46457-a702-41c4-a971-c815c4c5a674
\n",
+ "
\n",
+ "\n",
+ " R. Weasley \n",
+ " Actor definition \n",
+ " UUID: ff7b8672-84db-4b93-9fea-22a410907fb1
\n",
+ "
\n",
+ "\n",
+ " Voldemort \n",
+ " Actor definition \n",
+ " UUID: 3e0ee19f-0e3f-49d4-ae99-29bd4a3260c5
\n",
+ "
\n",
+ "\n",
+ " Multiport \n",
+ " Actor definition \n",
+ " UUID: b3888dad-a870-4b8b-97d4-0ddb83ef9251
\n",
+ "
\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "templ = \"\"\"\n",
+ "Actor definitions \n",
+ "{% for actor in model.la.all_components.by_is_actor(True) %}\n",
+ " {{ actor.name }} \n",
+ " Actor definition \n",
+ " UUID: {{ actor.uuid }}
\n",
+ " {{ actor.description }}
\n",
+ "{% endfor %}\n",
+ "\"\"\"\n",
+ "\n",
+ "HTML(env.from_string(templ).render(model=model))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "As an extra: We don't use the UUID from capella in our documents. If you still\n",
+ "need an identifier, in the following it's explained how we are doing it:\n",
+ "\n",
+ "With the capella PVMT, one of the various capella addons, you can make property\n",
+ "value groups and then set arbitrary values with these. Capellambse is able to recognize\n",
+ "the pvmt extension and gives read and write access. In our workflows we are maintaining\n",
+ "an ID database for all model elements. If that is done you can access pvmt attributes\n",
+ "like:\n",
+ "\n",
+ "```html\n",
+ "{{ ... }}\n",
+ "ID: {{ actor.pvmt[\"Group.Identification.MY MODEL ID\"] }}
\n",
+ "{{ ... }}\n",
+ "```\n",
+ "\n",
+ "For a PVMT showcase look into [TODO: pvmt-showcase notebook]."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Filters and object manipulation\n",
+ "\n",
+ "Now to step up our templating-game, we'll bring in more complexity.\n",
+ "We want a template that documents functional context of all actors. For that\n",
+ "iff the actor has a non-empty functions attribute we make a table with columns\n",
+ "for function's uid, name, description and `FunctionalExchange`s.\n",
+ "\n",
+ "We can define variables in the template via the set statement. Furthermore\n",
+ "the builtin jinja [filters] already give much power for object manipulation during\n",
+ "rendering. Here we use map(.) to create `FunctionalExchange` iterators and sum these\n",
+ "up into one large list that stores all `FunctionalExchange`s that have an an actor\n",
+ "as either source or target. In the table for-loop we then filter on this lookup\n",
+ "container and set outgoing and incoming `FunctionalExchange`s that we need for\n",
+ "the last column.\n",
+ "\n",
+ "The jupyter environment is great for writing templates b/c you can investigate\n",
+ "possible attributes of objects right away in another cell.\n",
+ "\n",
+ "*Hint: You can define custom filter-functions and add them to the Environment.filters.*\n",
+ "\n",
+ "[filters]: https://jinja.palletsprojects.com/en/3.0.x/templates/#builtin-filters"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "Actor definitions \n",
+ "\n",
+ "\n",
+ " Harry J. Potter \n",
+ " Actor definition \n",
+ "
\n",
+ " Actor functions \n",
+ " \n",
+ " The table below identifies functions of Harry J. Potter.
\n",
+ " \n",
+ " \n",
+ " \n",
+ " ID \n",
+ " Function \n",
+ " Description \n",
+ " Involved Subsystems \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " aa9931e3-116c-461e-8215-6b9fdbdd4a1b \n",
+ " kill He Who Must Not Be Named \n",
+ " \n",
+ " Learning \n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ " Functions of Harry J. Potter
\n",
+ " \n",
+ "\n",
+ " Prof. A. P. W. B. Dumbledore \n",
+ " Actor definition \n",
+ "
Principal of Hogwarts, wearer of the elder wand and greatest mage of all time.
\n",
+ "\n",
+ " Actor functions \n",
+ " \n",
+ " The table below identifies functions of Prof. A. P. W. B. Dumbledore.
\n",
+ " \n",
+ " \n",
+ " \n",
+ " ID \n",
+ " Function \n",
+ " Description \n",
+ " Involved Subsystems \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " f708bc29-d69f-42a0-90cc-11fc01054cd0 \n",
+ " manage the school \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " beaf5ba4-8fa9-4342-911f-0266bb29be45 \n",
+ " advise Harry \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ " Functions of Prof. A. P. W. B. Dumbledore
\n",
+ " \n",
+ "\n",
+ " Prof. S. Snape \n",
+ " Actor definition \n",
+ "
Good guy and teacher of brewing arts.
\n",
+ "\n",
+ " Actor functions \n",
+ " \n",
+ " The table below identifies functions of Prof. S. Snape.
\n",
+ " \n",
+ " \n",
+ " \n",
+ " ID \n",
+ " Function \n",
+ " Description \n",
+ " Involved Subsystems \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " a7acb298-d14b-4707-a419-fea272434541 \n",
+ " Teaching \n",
+ " \n",
+ " Teacher Responsibilities \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 4a2a7f3c-d223-4d44-94a7-50dd2906a70c \n",
+ " maintain a layer of defense for the Sorcerer's Stone \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ " Functions of Prof. S. Snape
\n",
+ " \n",
+ "\n",
+ " Multiport \n",
+ " Actor definition \n",
+ "
\n",
+ " Actor functions \n",
+ " \n",
+ " The table below identifies functions of Multiport.
\n",
+ " \n",
+ " \n",
+ " \n",
+ " ID \n",
+ " Function \n",
+ " Description \n",
+ " Involved Subsystems \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 9c1885f5-fac7-48fd-9d54-a11092508867 \n",
+ " LAF 1 \n",
+ " \n",
+ " C 5 \n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ " Functions of Multiport
\n",
+ " \n",
+ "\n",
+ " Voldemort \n",
+ " Actor definition \n",
+ "
\n",
+ " Actor functions \n",
+ " \n",
+ " No actor functions were identified.
\n",
+ " \n",
+ "\n",
+ " R. Weasley \n",
+ " Actor definition \n",
+ "
\n",
+ " Actor functions \n",
+ " \n",
+ " The table below identifies functions of R. Weasley.
\n",
+ " \n",
+ " \n",
+ " \n",
+ " ID \n",
+ " Function \n",
+ " Description \n",
+ " Involved Subsystems \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " c1a42acc-1f53-42bb-8404-77a5c08c414b \n",
+ " assist Harry \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " edbd1ad4-31c0-4d53-b856-3ffa60e0e99b \n",
+ " break school rules \n",
+ " \n",
+ " Punishment \n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ " Functions of R. Weasley
\n",
+ " \n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "templ1 = \"\"\"\n",
+ "Actor definitions \n",
+ "{% set fexs = model.la.actor_exchanges.map(\"func_exchanges\") %}\n",
+ "{% for actor in model.la.all_actors %}\n",
+ " {{ actor.name }} \n",
+ " Actor definition \n",
+ " {{ actor.description }}
\n",
+ " Actor functions \n",
+ " {% if actor.functions %}\n",
+ " The table below identifies functions of {{ actor.name }}.
\n",
+ " \n",
+ " \n",
+ " \n",
+ " ID \n",
+ " Function \n",
+ " Description \n",
+ " Involved Subsystems \n",
+ " \n",
+ " \n",
+ " \n",
+ " {% for fnc in actor.functions %}\n",
+ " {% set outs = fexs.by_source.owner(fnc) %}\n",
+ " {% set ins = fexs.by_target.owner(fnc) %}\n",
+ " {% set subs = (ins + outs) | map(attribute=\"owner.name\") | unique | sort %}\n",
+ " \n",
+ " {{ fnc.uuid }} \n",
+ " {{ fnc.name }} \n",
+ " {{ fnc.description }} \n",
+ " {{ subs | join(', ') }} \n",
+ " \n",
+ " {% endfor %}\n",
+ " \n",
+ "
\n",
+ " Functions of {{ actor.name }}
\n",
+ " {% else %}\n",
+ " No actor functions were identified.
\n",
+ " {% endif %}\n",
+ "{% endfor %}\n",
+ "\"\"\"\n",
+ "HTML(env.from_string(templ1).render(model=model))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Beautiful SVG diagrams\n",
+ "\n",
+ "Finally we will render a template that displays a diagram. There are many ways\n",
+ "to do this and with jinja2 you have full control. We like our figures inside\n",
+ "tables such that a caption can be displayed"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Unknown global filter 'hide.sequencing.information.filter'\n",
+ "Unknown global filter 'ModelExtensionFilter'\n",
+ "Unknown global filter 'hide.simplified.diagram.based.component.exchanges.filter'\n",
+ "Unknown global filter 'hide.simplified.oriented.grouped.component.exchanges.filter'\n",
+ "Unknown global filter 'hide.simplified.group.of.component.exchanges.filter'\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "Hogwarts \n",
+ "This instance is the mighty Hogwarts. Do you really need a description? Then maybe read the books or watch atleast the epic movies.
\n",
+ "\n",
+ "\n",
+ " Figure 1: [LAB] Wizzard Education \n",
+ " LF Hogwarts produce Great Wizards protect Students against the Death Eaters Campus School educate Wizards Whomping Willow defend the surrounding area against Intruders Prof. A. P. W. B. Dumbledore manage the school advise Harry Prof. S. Snape Teaching maintain a layer of defense for the Sorcerer's Stone Harry J. Potter kill He Who Must Not Be Named R. Weasley assist Harry break school rules wizardry Headmaster Responsibilities Teacher Responsibilities Help for Harry Knowledge Punishment Learning educate & mature friendship assistance Care punish educate \n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "templ = \"\"\"\\\n",
+ "{{ component.name }} \n",
+ "{{ component.description }}\n",
+ "\n",
+ " Figure {{ fig_id }}: {{ fig_caption | e }} \n",
+ " {{ figure.as_svg | safe }} \n",
+ "
\n",
+ "\"\"\"\n",
+ "diagram = model.diagrams.by_name(\"[LAB] Wizzard Education\")\n",
+ "rendered = env.from_string(templ).render(\n",
+ " component=model.search(\"LogicalComponent\").by_name(\"Hogwarts\"),\n",
+ " fig_id=1,\n",
+ " fig_caption=diagram.name,\n",
+ " figure=diagram,\n",
+ ")\n",
+ "HTML(rendered)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "*Hint: Take notice of the [jinja.Environment]. Instead of handing the figure_table-markup\n",
+ "over in the rendering call you could also set an insert_figure_as_table function,\n",
+ "which you ideally defined before, in the environment globals or you can define\n",
+ "[macros] right in the template. These tools can automate repetitive content placement.*\n",
+ "\n",
+ "[jinja.Environment]: https://jinja.palletsprojects.com/en/3.0.x/api/#jinja2.Environment\n",
+ "[macros]: https://jinja.palletsprojects.com/en/3.0.x/templates/#macros"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Template inheritance\n",
+ "\n",
+ "The last cell will present a routine where a full .html document is generated.\n",
+ "Earlier rendered content were HTML-fragments to be precise. On top you can see\n",
+ "a showcase on jinja's [template-inheritance] functionality. The special DictLoader\n",
+ "gives support for finding the base template called \"template.html\". This was just\n",
+ "needed because we are dealing with content in memory and didn't create template.html\n",
+ "in our FileSystem before. Per default jinja is using the FileSystemLoader when\n",
+ "creating an Environment. It's not a bad idea to check the [Loaders] they have, if\n",
+ "you want to understand how template loading is working and/or plan on developing\n",
+ "a pipeline system for document distribution.\n",
+ "\n",
+ "[template-inheritance]: https://jinja.palletsprojects.com/en/3.0.x/templates/#template-inheritance\n",
+ "[Loaders]: https://jinja.palletsprojects.com/en/3.0.x/api/#loaders"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " Hogwarts \n",
+ "This instance is the mighty Hogwarts. Do you really need a description? Then maybe read the books or watch atleast the epic movies.
\n",
+ "\n",
+ "\n",
+ " Figure 1: [LAB] Wizzard Education \n",
+ " LF Hogwarts produce Great Wizards protect Students against the Death Eaters Campus School educate Wizards Whomping Willow defend the surrounding area against Intruders Prof. A. P. W. B. Dumbledore manage the school advise Harry Prof. S. Snape Teaching maintain a layer of defense for the Sorcerer's Stone Harry J. Potter kill He Who Must Not Be Named R. Weasley assist Harry break school rules wizardry Headmaster Responsibilities Teacher Responsibilities Help for Harry Knowledge Punishment Learning educate & mature friendship assistance Care punish educate \n",
+ "
\n",
+ "\n",
+ "\n",
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fig_templ = \"\".join(\n",
+ " (\n",
+ " '{% extends \"template.html\" %}',\n",
+ " \"{% block content %}\",\n",
+ " templ,\n",
+ " \"{% endblock %}\",\n",
+ " )\n",
+ ")\n",
+ "final_templ = \"\"\"\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " {% block content %}\n",
+ " {% endblock %}\n",
+ "\n",
+ "\n",
+ "\"\"\"\n",
+ "\n",
+ "env = jinja2.Environment(loader=jinja2.DictLoader({\"template.html\": final_templ}))\n",
+ "rendered = env.from_string(fig_templ).render(\n",
+ " component=model.search(\"LogicalComponent\").by_name(\"Hogwarts\"),\n",
+ " fig_id=1,\n",
+ " fig_caption=diagram.name,\n",
+ " figure=diagram,\n",
+ ")\n",
+ "HTML(rendered)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_sources/examples/05 Introduction to Libraries.ipynb.txt b/_sources/examples/05 Introduction to Libraries.ipynb.txt
new file mode 100644
index 000000000..cd52065b4
--- /dev/null
+++ b/_sources/examples/05 Introduction to Libraries.ipynb.txt
@@ -0,0 +1,260 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Introduction to Libraries\n",
+ "\n",
+ "This notebook illustrates the use of Capella Libraries. When trying to load a\n",
+ "model that uses a library, you may encounter an error similar to this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "MissingResourceLocationError: 'Library Test'\n"
+ ]
+ }
+ ],
+ "source": [
+ "import capellambse\n",
+ "path_to_model = \"../../../tests/data/Library Project/Library Project.aird\"\n",
+ "\n",
+ "try:\n",
+ " capellambse.MelodyModel(path_to_model)\n",
+ "except Exception as err:\n",
+ " print(f\"{type(err).__name__}: {err}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This tells us the name that was given to the library: `Library Test`. So, we need to define a resource location with that name. As there can be arbitrarily many resource locations (i.e. linked libraries) with arbitrary names given to them, these locations are handed over in a Python `dict`.\n",
+ "\n",
+ "There are three ways of defining a resource location:\n",
+ "\n",
+ "1. A simple `str` containing only a path or URL, similar to the first positional argument of `MelodyModel`.\n",
+ "2. A nested dictionary with a `path` key, as well as other keys needed to find and access that resource. These may include `subdir` or `username` and `password`.\n",
+ "3. A constructed `FileHandler` object.\n",
+ "\n",
+ "The following cell shows a concrete example of each of them."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Simple `str`\n",
+ "resources = {\n",
+ " \"Library Test\": \"/data/models/Library Test\",\n",
+ "}\n",
+ "\n",
+ "# Nested `dict`\n",
+ "resources = {\n",
+ " \"Library Test\": {\n",
+ " \"path\": \"https://raw.githubusercontent.com/DSD-DBS/py-capellambse/master/tests/data/Library%20Test\",\n",
+ " # More options can be added here if necessary, e.g.:\n",
+ " # \"username\": \"demouser\",\n",
+ " # \"password\": \"super secret passphrase\",\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "# `FileHandler` object\n",
+ "# (Be aware that constructing a ´FileHandler` may already involve network access,\n",
+ "# for example cloning a remote git repository into a local cache.)\n",
+ "lib_handler = capellambse.get_filehandler(\n",
+ " \"git+https://github.com/DSD-DBS/py-capellambse.git\",\n",
+ " subdir=\"tests/data/Library Test\",\n",
+ " revision=\"master\"\n",
+ " # More options can be added here as well, e.g.:\n",
+ " # username=\"demouser\",\n",
+ " # password=\"super secret passphrase\",\n",
+ ")\n",
+ "resources = {\"Library Test\": lib_handler}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Equipped with this `resources` dictionary, we can now try to load the model again:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Cannot load PVMT extension: ValueError: Provided model does not have a PropertyValuePkg\n",
+ "Property values are not available in this model\n"
+ ]
+ }
+ ],
+ "source": [
+ "model = capellambse.MelodyModel(path_to_model, resources=resources)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you receive more `MissingResourceLocationError`s, add them to the same `resources` dictionary and pass them to the `MelodyModel` as well."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Once you no longer receive errors during loading, you can use the model as normal."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "[CDB] Library Product (uuid: _q-c-0KN2EeyJNLcTD9ngpQ)[LAB] E-Commerce (uuid: _SMS4sKFFEeyn0YWM8vjd5w) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] "
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.diagrams"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Unknown global filter 'hide.sequencing.information.filter'\n",
+ "Unknown global filter 'hide.simplified.diagram.based.component.exchanges.filter'\n",
+ "Unknown global filter 'hide.simplified.oriented.grouped.component.exchanges.filter'\n",
+ "Unknown global filter 'ModelExtensionFilter'\n",
+ "Unknown global filter 'hide.simplified.group.of.component.exchanges.filter'\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "LF E-Commerce offer products assign order Client select product get product Truck Company receive order deliver product product list supply details order details "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.diagrams.by_name(\"[LAB] E-Commerce\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Common pitfalls\n",
+ "\n",
+ "In order for `capellambse` to be able to find your elements, ensure that you:\n",
+ "\n",
+ "1. Created a replicable element collection (REC) in the Capella Library. To do that, right-click the element in the library, and choose \"REC / RPL\" > \"Create REC\".\n",
+ "2. Have instantiated the REC as a so-called Replica (RPL) in your primary project. For this, right-click any element in your project and choose \"REC / RPL\" > \"Instantiate RPL from REC\".\n",
+ "\n",
+ "For more information, watch this [short video about REC / RPL](https://youtu.be/h-ax61eVlxM)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Logical System\n",
+ "E-Commerce\n",
+ "Truck Company\n",
+ "Client\n"
+ ]
+ }
+ ],
+ "source": [
+ "for component in model.la.all_components:\n",
+ " print(component.name)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Saving a model\n",
+ "\n",
+ "You can save the model as usual by calling `model.save()`. However, **this will only save the primary model**. Modifications to elements that are defined only in a library will be lost.\n",
+ "\n",
+ "This is normally not a problem when following the standard REC / RPL based workflow, as the definitions of those elements will be copied to and modified in the primary model.\n",
+ "\n",
+ "In order to modify elements in one of the used libraries, you can load the library itself as a model. This allows you to apply any needed modifications and then save the library. Afterwards, the updated library can be used in the `resources` of other models."
+ ]
+ }
+ ],
+ "metadata": {
+ "interpreter": {
+ "hash": "e5607734f15d1b90b8506e690cd35fc527f703262c75faee6ce3cf6c6d2ff5b2"
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_sources/examples/06 Introduction to Requirement access and management.ipynb.txt b/_sources/examples/06 Introduction to Requirement access and management.ipynb.txt
new file mode 100644
index 000000000..76030d9dc
--- /dev/null
+++ b/_sources/examples/06 Introduction to Requirement access and management.ipynb.txt
@@ -0,0 +1,686 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7bcee230",
+ "metadata": {},
+ "source": [
+ "# Introduction to Requirement access and management\n",
+ "\n",
+ "Welcome to the ReqIF extension Showcase notebook. This notebook will show you some basic (and not so basic) things that you can get done using this library.\n",
+ "\n",
+ "The below code loads the library and one of the test models:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "a52777dd",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import capellambse\n",
+ "\n",
+ "path_to_model = \"../../../tests/data/melodymodel/5_0/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)\n",
+ "model"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d8442183",
+ "metadata": {},
+ "source": [
+ "You can access a lookup for all requirements defined in a specific layer."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "42a46a49",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Requirement "TestReq1" (3c2d312c-37c9-41b5-8c32-67578fa52dc3)Requirement "TypedReq2" (0a9a68b1-ba9a-4793-b2cf-4448f0b4b8cc)Requirement "TestReq3" (79291c33-5147-4543-9398-9077d582576d)Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)Requirement "TestReq" (1092f69a-5f3a-4fe6-a8fd-b2dffde90650) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] "
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.oa.all_requirements"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "904c842b",
+ "metadata": {},
+ "source": [
+ "Have a look at all of the available attributes for a Requirement ModelElement:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "cb0a5b75",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "TestReq1 (Requirements:Requirement) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
attributes BooleanValueAttribute "AttrDef" (9c692405-b8aa-4caa-b988-51d27db5cd1b)DateValueAttribute "AttrDef" (b97c09b5-948a-46e8-a656-69d764ddce7d)IntegerValueAttribute "AttrDef" (85dfd42c-7f6e-4236-a181-bdd784040431)RealValueAttribute "AttrDef" (d2231d14-854d-4625-b48b-6cf1c2554367)StringValueAttribute "AttrDef" (ee8a69ef-61b9-4db9-9a0f-628e5d4704e1)BooleanValueAttribute "None" (dcb8614e-2d1c-4cb3-aa0c-667a297e7489)chapter_name 2 constraints (Empty list)
description This is a test requirement of kind 1. diagrams (Empty list)
filtering_criteria (Empty list)
foreign_id 1 identifier REQTYPE-1 long_name 1 name TestReq1 owner Folder "Folder" (e16f5cc1-3299-43d0-b1a0-82d31a137111)parent Folder "Folder" (e16f5cc1-3299-43d0-b1a0-82d31a137111)prefix 3 progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f3afe4e68d0> related Entity "Weather" (4bf0356c-89dd-45e9-b8a6-e0332c026d33)SystemFunction "Sysexfunc" (00e7b925-cf4c-4cb0-929e-5409a1cd872b)Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)LogicalComponent "Hogwarts" (0d2edb8f-fa34-4e73-89ec-fb9a63001440)relations CapellaIncomingRelation "Controlling the weather" (078b2c69-4352-4cf9-9ea5-6573b75e5eec)CapellaIncomingRelation "Test req" (24c824ef-b187-4725-a051-a68707e82d70)InternalRelation "None" (7de4c1a5-e106-4171-902a-502b816b60b0)CapellaOutgoingRelation "None" (57033242-3766-4961-8091-ce3d9326ed67)requirements Entity "Weather" (4bf0356c-89dd-45e9-b8a6-e0332c026d33)SystemFunction "Sysexfunc" (00e7b925-cf4c-4cb0-929e-5409a1cd872b)Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)LogicalComponent "Hogwarts" (0d2edb8f-fa34-4e73-89ec-fb9a63001440)summary None text Test requirement 1 really l o n g text that is way too long to display here as that
\n",
+ "\n",
+ "< > " '
\n",
+ "\n",
+ "\n",
+ "\tThis is a list \n",
+ "\tan unordered one \n",
+ " \n",
+ "\n",
+ "\n",
+ "\tOrdered list \n",
+ "\tOk \n",
+ " \n",
+ "traces (Empty list)
type RequirementType "ReqType" (db47fca9-ddb6-4397-8d4b-e397e53d277e)uuid 3c2d312c-37c9-41b5-8c32-67578fa52dc3 xtype Requirements:Requirement
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".attributes = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ " [4] \n",
+ " [5] \n",
+ ".chapter_name = '2'\n",
+ ".constraints = []\n",
+ ".description = 'This is a test requirement of kind 1.'\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".foreign_id = 1\n",
+ ".identifier = 'REQTYPE-1'\n",
+ ".long_name = '1'\n",
+ ".name = 'TestReq1'\n",
+ ".owner = \n",
+ ".parent = \n",
+ ".prefix = '3'\n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".related = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ ".relations = [0] to (078b2c69-4352-4cf9-9ea5-6573b75e5eec)>\n",
+ " [1] to (24c824ef-b187-4725-a051-a68707e82d70)>\n",
+ " [2] to (7de4c1a5-e106-4171-902a-502b816b60b0)>\n",
+ " [3] to (57033242-3766-4961-8091-ce3d9326ed67)>\n",
+ ".requirements = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ ".summary = None\n",
+ ".text = Markup('Test requirement 1 really l o n g text that is way too long to display here as that
\\n\\n< > " '
\\n\\n\\n\\tThis is a list \\n\\tan unordered one \\n \\n\\n\\n\\tOrdered [...]\n",
+ ".traces = []\n",
+ ".type = \n",
+ ".uuid = '3c2d312c-37c9-41b5-8c32-67578fa52dc3'\n",
+ ".xtype = 'Requirements:Requirement'"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.oa.all_requirements[0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "896e3633",
+ "metadata": {},
+ "source": [
+ "## Filtering for requirements by type\n",
+ "\n",
+ "You probably know about typing of your Requirements. You can have a view of all requirement type folders directly on a specific layer and see the stored requirement_types:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "8dad0bed",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "CapellaTypesFolder (CapellaRequirements:CapellaTypesFolder) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
constraints (Empty list)
data_type_definitions DataTypeDefinition "DataTypeDef" (3b7ec38a-e26a-4c23-9fa3-275af3f629ee)EnumerationDataTypeDefinition "EnumDataTypeDef" (637caf95-3229-4607-99a0-7d7b990bc97f)description None diagrams (Empty list)
filtering_criteria (Empty list)
identifier None long_name Types module_types ModuleType "ModuleType" (a67e7f43-4b49-425c-a6a7-d44e1054a488)name None parent OperationalAnalysis "Operational Analysis" (ddbef16d-ddb9-4162-934c-f1e40e6f8bed)prefix None progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f3ad72c8f50> relation_types RelationType "RelationType" (f1aceb81-5f70-4469-a127-94830eb9be04)requirement_types RequirementType "ReqType" (db47fca9-ddb6-4397-8d4b-e397e53d277e)requirements (Empty list)
summary None traces (Empty list)
type None uuid 67bba9cf-953c-4f0b-9986-41991c68d241 xtype CapellaRequirements:CapellaTypesFolder
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".constraints = []\n",
+ ".data_type_definitions = [0] \n",
+ " [1] \n",
+ ".description = None\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".identifier = None\n",
+ ".long_name = 'Types'\n",
+ ".module_types = [0] \n",
+ ".name = None\n",
+ ".parent = \n",
+ ".prefix = None\n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".relation_types = [0] \n",
+ ".requirement_types = [0] \n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".type = None\n",
+ ".uuid = '67bba9cf-953c-4f0b-9986-41991c68d241'\n",
+ ".xtype = 'CapellaRequirements:CapellaTypesFolder'"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.oa.requirement_types_folders[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "28c463c1",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "RequirementType (Requirements:RequirementType) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
attribute_definitions AttributeDefinition "AttrDef" (682bd51d-5451-4930-a97e-8bfca6c3a127)AttributeDefinitionEnumeration "AttrDefEnum" (c316ab07-c5c3-4866-a896-92e34733055c)AttributeDefinitionEnumeration "MultiEnum" (f31d4dd3-99f7-41d1-b1ce-f07b20d26eac)AttributeDefinition "version" (0bd40628-10a5-451e-86da-187c93bc3b10)constraints (Empty list)
description None diagrams (Empty list)
filtering_criteria (Empty list)
identifier None long_name ReqType name None owner CapellaTypesFolder "Types" (67bba9cf-953c-4f0b-9986-41991c68d241)parent CapellaTypesFolder "Types" (67bba9cf-953c-4f0b-9986-41991c68d241)prefix None progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f3ad72f7910> requirements (Empty list)
summary None traces (Empty list)
type None uuid db47fca9-ddb6-4397-8d4b-e397e53d277e xtype Requirements:RequirementType
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".attribute_definitions = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ ".constraints = []\n",
+ ".description = None\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".identifier = None\n",
+ ".long_name = 'ReqType'\n",
+ ".name = None\n",
+ ".owner = \n",
+ ".parent = \n",
+ ".prefix = None\n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".type = None\n",
+ ".uuid = 'db47fca9-ddb6-4397-8d4b-e397e53d277e'\n",
+ ".xtype = 'Requirements:RequirementType'"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "reqtype = model.oa.requirement_types_folders[0].requirement_types[0]\n",
+ "reqtype"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "62baecda",
+ "metadata": {},
+ "source": [
+ "Now we actually want to filter the requirements by this type with name 'ReqType'. Very original name, we know. You wouldn't really see the filtering effect since all requirements in the oa layer are of that type. So let us create one new requirement dynamically:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "2d985277",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "New showcase req1 (Requirements:Requirement) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
attributes (Empty list)
chapter_name None constraints (Empty list)
description None diagrams (Empty list)
filtering_criteria (Empty list)
foreign_id None identifier None long_name None name New showcase req1 owner CapellaModule "Test Module" (f8e2195d-b5f5-4452-a12b-79233d943d5e)parent CapellaModule "Test Module" (f8e2195d-b5f5-4452-a12b-79233d943d5e)prefix None progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f3afc3ddd50> related (Empty list)
relations (Empty list)
requirements (Empty list)
summary None text traces (Empty list)
type None uuid 0ce7877e-68d6-4113-8aca-be69b2e25253 xtype Requirements:Requirement
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".attributes = []\n",
+ ".chapter_name = None\n",
+ ".constraints = []\n",
+ ".description = None\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".foreign_id = None\n",
+ ".identifier = None\n",
+ ".long_name = None\n",
+ ".name = 'New showcase req1'\n",
+ ".owner = \n",
+ ".parent = \n",
+ ".prefix = None\n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".related = []\n",
+ ".relations = []\n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".text = ''\n",
+ ".traces = []\n",
+ ".type = None\n",
+ ".uuid = '0ce7877e-68d6-4113-8aca-be69b2e25253'\n",
+ ".xtype = 'Requirements:Requirement'"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Requirement "TestReq1" (3c2d312c-37c9-41b5-8c32-67578fa52dc3)Requirement "TypedReq2" (0a9a68b1-ba9a-4793-b2cf-4448f0b4b8cc)Requirement "TestReq3" (79291c33-5147-4543-9398-9077d582576d)Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)Requirement "New showcase req1" (0ce7877e-68d6-4113-8aca-be69b2e25253)Requirement "TestReq" (1092f69a-5f3a-4fe6-a8fd-b2dffde90650) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] \n",
+ "[5] "
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "new_req = model.oa.requirement_modules[0].requirements.create(name=\"New showcase req1\")\n",
+ "display(new_req)\n",
+ "model.oa.all_requirements"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "58941b28",
+ "metadata": {},
+ "source": [
+ "Info about creation: Whenever you have an ElementList which deals with one\n",
+ "specified classtype, here it is Requirement, then the classtype name doesn't\n",
+ "need to be included."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "9156aac3",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Requirement "TestReq1" (3c2d312c-37c9-41b5-8c32-67578fa52dc3)Requirement "TypedReq2" (0a9a68b1-ba9a-4793-b2cf-4448f0b4b8cc)Requirement "TestReq3" (79291c33-5147-4543-9398-9077d582576d)Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)Requirement "TestReq" (1092f69a-5f3a-4fe6-a8fd-b2dffde90650) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] "
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.oa.all_requirements.by_type(\"ReqType\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f6687b07",
+ "metadata": {},
+ "source": [
+ "We see our Requirements with type `ReqType` are missing the new one.\n",
+ "Let's change that, without using capella."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "19f5f917",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Requirement "TestReq1" (3c2d312c-37c9-41b5-8c32-67578fa52dc3)Requirement "TypedReq2" (0a9a68b1-ba9a-4793-b2cf-4448f0b4b8cc)Requirement "TestReq3" (79291c33-5147-4543-9398-9077d582576d)Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)Requirement "New showcase req1" (0ce7877e-68d6-4113-8aca-be69b2e25253)Requirement "TestReq" (1092f69a-5f3a-4fe6-a8fd-b2dffde90650) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] \n",
+ "[5] "
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "new_req.type = reqtype\n",
+ "model.oa.all_requirements.by_type(\"ReqType\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3878d8d5",
+ "metadata": {},
+ "source": [
+ "If you are sure about attributes when creating a Requirement you can also include\n",
+ "it during creation. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "f46766d6",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Requirement "TestReq1" (3c2d312c-37c9-41b5-8c32-67578fa52dc3)Requirement "TypedReq2" (0a9a68b1-ba9a-4793-b2cf-4448f0b4b8cc)Requirement "TestReq3" (79291c33-5147-4543-9398-9077d582576d)Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)Requirement "New showcase req1" (0ce7877e-68d6-4113-8aca-be69b2e25253)Requirement "ReqType during Creation" (ec5f6680-501c-4a6c-a2ce-3ae8fe93be00)Requirement "TestReq" (1092f69a-5f3a-4fe6-a8fd-b2dffde90650) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] \n",
+ "[5] \n",
+ "[6] "
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.oa.requirement_modules[0].requirements.create(\n",
+ " name=\"ReqType during Creation\",\n",
+ " type=reqtype,\n",
+ ")\n",
+ "model.oa.all_requirements.by_type(\"ReqType\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "2530e4a4",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "TestReq1 (Requirements:Requirement) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
attributes BooleanValueAttribute "AttrDef" (9c692405-b8aa-4caa-b988-51d27db5cd1b)DateValueAttribute "AttrDef" (b97c09b5-948a-46e8-a656-69d764ddce7d)IntegerValueAttribute "AttrDef" (85dfd42c-7f6e-4236-a181-bdd784040431)RealValueAttribute "AttrDef" (d2231d14-854d-4625-b48b-6cf1c2554367)StringValueAttribute "AttrDef" (ee8a69ef-61b9-4db9-9a0f-628e5d4704e1)BooleanValueAttribute "None" (dcb8614e-2d1c-4cb3-aa0c-667a297e7489)chapter_name 2 constraints (Empty list)
description This is a test requirement of kind 1. diagrams (Empty list)
filtering_criteria (Empty list)
foreign_id 1 identifier REQTYPE-1 long_name 1 name TestReq1 owner Folder "Folder" (e16f5cc1-3299-43d0-b1a0-82d31a137111)parent Folder "Folder" (e16f5cc1-3299-43d0-b1a0-82d31a137111)prefix 3 progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f3ad72dfd90> related Entity "Weather" (4bf0356c-89dd-45e9-b8a6-e0332c026d33)SystemFunction "Sysexfunc" (00e7b925-cf4c-4cb0-929e-5409a1cd872b)Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)LogicalComponent "Hogwarts" (0d2edb8f-fa34-4e73-89ec-fb9a63001440)relations CapellaIncomingRelation "Controlling the weather" (078b2c69-4352-4cf9-9ea5-6573b75e5eec)CapellaIncomingRelation "Test req" (24c824ef-b187-4725-a051-a68707e82d70)InternalRelation "None" (7de4c1a5-e106-4171-902a-502b816b60b0)CapellaOutgoingRelation "None" (57033242-3766-4961-8091-ce3d9326ed67)requirements Entity "Weather" (4bf0356c-89dd-45e9-b8a6-e0332c026d33)SystemFunction "Sysexfunc" (00e7b925-cf4c-4cb0-929e-5409a1cd872b)Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)LogicalComponent "Hogwarts" (0d2edb8f-fa34-4e73-89ec-fb9a63001440)summary None text Test requirement 1 really l o n g text that is way too long to display here as that
\n",
+ "\n",
+ "< > " '
\n",
+ "\n",
+ "\n",
+ "\tThis is a list \n",
+ "\tan unordered one \n",
+ " \n",
+ "\n",
+ "\n",
+ "\tOrdered list \n",
+ "\tOk \n",
+ " \n",
+ "traces (Empty list)
type RequirementType "ReqType" (db47fca9-ddb6-4397-8d4b-e397e53d277e)uuid 3c2d312c-37c9-41b5-8c32-67578fa52dc3 xtype Requirements:Requirement
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".attributes = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ " [4] \n",
+ " [5] \n",
+ ".chapter_name = '2'\n",
+ ".constraints = []\n",
+ ".description = 'This is a test requirement of kind 1.'\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".foreign_id = 1\n",
+ ".identifier = 'REQTYPE-1'\n",
+ ".long_name = '1'\n",
+ ".name = 'TestReq1'\n",
+ ".owner = \n",
+ ".parent = \n",
+ ".prefix = '3'\n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".related = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ ".relations = [0] to (078b2c69-4352-4cf9-9ea5-6573b75e5eec)>\n",
+ " [1] to (24c824ef-b187-4725-a051-a68707e82d70)>\n",
+ " [2] to (7de4c1a5-e106-4171-902a-502b816b60b0)>\n",
+ " [3] to (57033242-3766-4961-8091-ce3d9326ed67)>\n",
+ ".requirements = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ " [3] \n",
+ ".summary = None\n",
+ ".text = Markup('Test requirement 1 really l o n g text that is way too long to display here as that
\\n\\n< > " '
\\n\\n\\n\\tThis is a list \\n\\tan unordered one \\n \\n\\n\\n\\tOrdered [...]\n",
+ ".traces = []\n",
+ ".type = \n",
+ ".uuid = '3c2d312c-37c9-41b5-8c32-67578fa52dc3'\n",
+ ".xtype = 'Requirements:Requirement'"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.oa.all_requirements[0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ec7a07c8",
+ "metadata": {},
+ "source": [
+ "## Export all requirements to excel with pandas\n",
+ "\n",
+ "With `Pandas` you are able to generate data tables and export to many file-types\n",
+ "like .xlsx for excel. Note that this requires the `xlsxwriter` module in\n",
+ "addition to `pandas` itself."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "acbe3e06",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "\n",
+ "requirements = [{\"id\": f\"Req_{i}\", \"uuid\": req.uuid, \"text\": req.text} for i, req in enumerate(model.oa.all_requirements)]\n",
+ "data = pd.DataFrame(requirements)\n",
+ "data.to_excel(excel_writer=\"Test_requirements.xlsx\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "03bf76ca-0703-4ae7-9270-e743063d7372",
+ "metadata": {},
+ "source": [
+ "## Export a Requirements module as Requirements Interchange Format (`.reqif`) file\n",
+ "\n",
+ "`capellambse` features basic export functionality for requirements modules, which allows to write `.reqif` or compressed `.reqifz` files. These can then be imported into other ReqIF-compliant applications, like CodeBeamer or IBM DOORS.\n",
+ "\n",
+ "Let's first take a glance at the module we're going to export:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "e3f44e4c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Test Module (CapellaRequirements:CapellaModule) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
attributes EnumerationValueAttribute "AttrDefEnum" (11a2e07a-41f7-4eee-a94e-f3e33738c487)constraints (Empty list)
description This is a test requirement module. diagrams (Empty list)
filtering_criteria (Empty list)
folders Folder "Folder" (e16f5cc1-3299-43d0-b1a0-82d31a137111)identifier 1 long_name Module name Test Module parent OperationalAnalysis "Operational Analysis" (ddbef16d-ddb9-4162-934c-f1e40e6f8bed)prefix T progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f3ad4787a10> requirement_types_folders (Empty list)
requirements Requirement "TypedReq1" (85d41db2-9e17-438b-95cf-49342452ddf3)Requirement "New showcase req1" (0ce7877e-68d6-4113-8aca-be69b2e25253)Requirement "ReqType during Creation" (ec5f6680-501c-4a6c-a2ce-3ae8fe93be00)summary None traces (Empty list)
type ModuleType "ModuleType" (a67e7f43-4b49-425c-a6a7-d44e1054a488)uuid f8e2195d-b5f5-4452-a12b-79233d943d5e xtype CapellaRequirements:CapellaModule
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".attributes = [0] \n",
+ ".constraints = []\n",
+ ".description = 'This is a test requirement module.'\n",
+ ".diagrams = []\n",
+ ".filtering_criteria = []\n",
+ ".folders = [0] \n",
+ ".identifier = '1'\n",
+ ".long_name = 'Module'\n",
+ ".name = 'Test Module'\n",
+ ".parent = \n",
+ ".prefix = 'T'\n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".requirement_types_folders = []\n",
+ ".requirements = [0] \n",
+ " [1] \n",
+ " [2] \n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".type = \n",
+ ".uuid = 'f8e2195d-b5f5-4452-a12b-79233d943d5e'\n",
+ ".xtype = 'CapellaRequirements:CapellaModule'"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "req_module = model.by_uuid(\"f8e2195d-b5f5-4452-a12b-79233d943d5e\")\n",
+ "req_module"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "5c555118-246d-47be-b462-6ce01822e156",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "req_module.to_reqif(req_module.name + \".reqif\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "94297761-841e-4900-945c-b5f87825627f",
+ "metadata": {},
+ "source": [
+ "And that's it! This code has created the file \"Test Module.reqif\" next to this notebook, which contains all Requirements defined in that module."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/_sources/examples/07 Code Generation.ipynb.txt b/_sources/examples/07 Code Generation.ipynb.txt
new file mode 100644
index 000000000..7a9eed909
--- /dev/null
+++ b/_sources/examples/07 Code Generation.ipynb.txt
@@ -0,0 +1,402 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Introduction to Code Generation\n",
+ "\n",
+ "This notebook exemplifies how to generate automatically code in terms of interfaces. For this three examples are provided. The first one creates a ROS message, the second a standard python class and the last a protobuf interface."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import capellambse"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "path_to_model = \"../../../tests/data/melodymodel/5_0/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In particular, we want to create code from our class:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Unknown global filter 'hide.technical.interfaces.filter'\n",
+ "Unknown global filter 'ModelExtensionFilter'\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "Trajectory lat : float lon : float alt : float Waypoint test : str Example float str "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.diagrams.by_name(\"[CDB] CodeGeneration\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In order to access the classes, we can simply access the `data_package` of the operational layer, and from there access the attribute `classes`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Class "Twist" (8164ae8b-36d5-4502-a184-5ec064db4ec3)Class "Trajectory" (c5ea0585-7657-4764-9eb2-3a6584980ce6)Class "Waypoint" (2a923851-a4ca-4fd2-a4b3-302edb8ac178)Class "Example" (a7ecc231-c55e-4ab9-ae14-9558e3ec2a34) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] "
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "data_pkg = model.oa.data_package\n",
+ "data_pkg.classes"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## ROS2 IDL Message\n",
+ "\n",
+ "Let's have a brief look into the structure of ROS2 Message descriptions. They are stored in `.msg` files and comprised of a type and name, separated by whitespace, i.e.:\n",
+ "\n",
+ "```\n",
+ "fieldtype1 fieldname1\n",
+ "fieldtype2[] fieldname2\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def class_to_ros2_idl(cls):\n",
+ " filename = f\"{cls.name}.msg\"\n",
+ " lines = []\n",
+ " for prop in cls.properties:\n",
+ " multiplicity = (\"\", \"[]\")[prop.max_card.value > 1]\n",
+ " lines.append(f\"{prop.type.name}{multiplicity} {prop.name}\")\n",
+ " text = \"\\n\".join(lines)\n",
+ " with open(filename, \"w\") as file:\n",
+ " file.write(text)\n",
+ " print(f\"# file: {filename} \\n{text}\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In our example, files would be generated with the following content:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "# file: Twist.msg \n",
+ "\n",
+ "\n",
+ "# file: Trajectory.msg \n",
+ "Waypoint[] waypoints\n",
+ "\n",
+ "# file: Waypoint.msg \n",
+ "float lat\n",
+ "float lon\n",
+ "float alt\n",
+ "Example[] examples\n",
+ "\n",
+ "# file: Example.msg \n",
+ "str test\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "data_pkg = model.oa.data_package\n",
+ "for cls in data_pkg.classes:\n",
+ " class_to_ros2_idl(cls)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Interface for python classes\n",
+ "\n",
+ "A python class has the following structure:\n",
+ "\n",
+ "\n",
+ "```\n",
+ "class class_name:\n",
+ " name1: type \n",
+ " name2: [type]\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "A python interface can be generated as follows:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def class_to_python(cls, current_classes=None):\n",
+ " lines = [f\"class {cls.name}:\"]\n",
+ " current_classes = [cls]\n",
+ " if not cls.properties:\n",
+ " lines.append(4*\" \" + \"pass\")\n",
+ " for prop in cls.properties:\n",
+ " if (\n",
+ " isinstance(\n",
+ " prop.type, capellambse.model.crosslayer.information.Class\n",
+ " )\n",
+ " and prop.type not in current_classes\n",
+ " ):\n",
+ " nested_text = class_to_python(prop.type, current_classes)\n",
+ " lines = [nested_text] + [\"\\n\"] + lines\n",
+ " multiplicity = (f\"{prop.type.name}\", f\"list[{prop.type.name}]\")[\n",
+ " prop.max_card.value > 1\n",
+ " ]\n",
+ " lines.append(4*\" \" + f\"{prop.name}: {multiplicity}\")\n",
+ " text = \"\\n\".join(lines)\n",
+ "\n",
+ " return text"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "# file: trajectory.py \n",
+ "class Example:\n",
+ " test: str\n",
+ "\n",
+ "\n",
+ "class Waypoint:\n",
+ " lat: float\n",
+ " lon: float\n",
+ " alt: float\n",
+ " examples: list[Example]\n",
+ "\n",
+ "\n",
+ "class Trajectory:\n",
+ " waypoints: list[Waypoint]\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "trajectory = data_pkg.classes.by_name(\"Trajectory\")\n",
+ "text = class_to_python(trajectory)\n",
+ "filename = f\"{trajectory.name.lower()}.py\"\n",
+ "with open(filename, \"w\") as file:\n",
+ " file.write(text)\n",
+ "print(f\"# file: {filename} \\n{text}\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Interface for Protocol Buffers (Protobuf) \n",
+ "\n",
+ "Protobuf Message descriptions are stored in `.proto` files where a class definition starts with `message` and each property of the class is defined by at least three parts: the data type, name and its order number. Classes can also be nested in other classes. An example is shown in the following:\n",
+ "\n",
+ "\n",
+ "```\n",
+ "syntax = \"proto3\";\n",
+ "\n",
+ "message class1 {\n",
+ " datatype class1_name1 = 1;\n",
+ " datatype class1_name2 = 2;\n",
+ " message class2 {\n",
+ " datatype class2_name1 = 1;\n",
+ " }\n",
+ " repeated class2 class_name = 3;\n",
+ "}\n",
+ "\n",
+ "```\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def class_to_proto(cls, current_classes=None, indent=\"\"):\n",
+ " if current_classes is None:\n",
+ " current_classes = [cls]\n",
+ " lines = ['syntax = \"proto3\";\\n']\n",
+ " indent += \" \"*4\n",
+ " lines.append(f\"{indent[:-4]}message {cls.name} {{\")\n",
+ " else:\n",
+ " lines = [f\"{indent[:-4]}message {cls.name} {{\"]\n",
+ "\n",
+ " for counter, prop in enumerate(cls.properties, start=1):\n",
+ " multiplicity = (\"\", \"[]\")[prop.max_card.value > 1]\n",
+ " if (\n",
+ " isinstance(\n",
+ " prop.type, capellambse.model.crosslayer.information.Class\n",
+ " )\n",
+ " and prop.type not in current_classes\n",
+ " ):\n",
+ " current_classes.append(prop.type)\n",
+ " nested_text = class_to_proto(\n",
+ " prop.type, current_classes, indent + \" \"*4\n",
+ " )\n",
+ " lines.append(nested_text)\n",
+ " lines.append(\n",
+ " f\"{indent}repeated {prop.type.name}{multiplicity} {prop.name} = {counter};\"\n",
+ " )\n",
+ " else:\n",
+ " lines.append(\n",
+ " f\"{indent}{prop.type.name}{multiplicity} {prop.name} = {counter};\"\n",
+ " )\n",
+ " lines.append(f\"{indent[:-4]}}}\")\n",
+ " text = \"\\n\".join(lines)\n",
+ " return text"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The protobuf interface of class `Trajectory` would look as follows:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "# file: Trajectory.proto \n",
+ "syntax = \"proto3\";\n",
+ "\n",
+ "message Trajectory {\n",
+ " message Waypoint {\n",
+ " float lat = 1;\n",
+ " float lon = 2;\n",
+ " float alt = 3;\n",
+ " message Example {\n",
+ " str test = 1;\n",
+ " }\n",
+ " repeated Example[] examples = 4;\n",
+ " }\n",
+ " repeated Waypoint[] waypoints = 1;\n",
+ "}\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "trajectory = data_pkg.classes.by_name(\"Trajectory\")\n",
+ "text = class_to_proto(trajectory)\n",
+ "filename = f\"{trajectory.name}.proto\"\n",
+ "with open(filename, \"w\") as file:\n",
+ " file.write(text)\n",
+ "print(f\"# file: {filename} \\n{text}\\n\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "c5ea7dc634d8047a259e5b898f154d237fbe6934b444b1a949475949608d751e"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_sources/examples/08 Property Values.ipynb.txt b/_sources/examples/08 Property Values.ipynb.txt
new file mode 100644
index 000000000..60ace52e0
--- /dev/null
+++ b/_sources/examples/08 Property Values.ipynb.txt
@@ -0,0 +1,342 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f4599550",
+ "metadata": {},
+ "source": [
+ "# Property Values\n",
+ "\n",
+ "capellambse provides access to property values and property value groups, as well as the Property Value Management (PVMT) extension.\n",
+ "\n",
+ "This notebook will show how to access and work with basic property values and groups."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "fb62b658",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import capellambse\n",
+ "\n",
+ "path_to_model = \"../../../tests/data/melodymodel/5_0/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f4effeec",
+ "metadata": {},
+ "source": [
+ "Model objects can own property values and PV groups. To access those, use the `property_values` and `property_value_groups` attributes respectively:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "3491dc40",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "obj = model.search(\"LogicalComponent\").by_name(\"Whomping Willow\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "6f1304b7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "IntegerPropertyValue "cars_defeated": 1 (a928fa22-cef7-4357-9b87-675a432f6591) "
+ ],
+ "text/plain": [
+ "[0] "
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.property_values"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "573ce32d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "cars_defeated (org.polarsys.capella.core.data.capellacore:IntegerPropertyValue) applied_property_value_groups (Empty list)
applied_property_values (Empty list)
constraints (Empty list)
description diagrams (Empty list)
enumerations (Empty list)
filtering_criteria (Empty list)
name cars_defeated parent LogicalComponent "Whomping Willow" (3bdd4fa2-5646-44a1-9fa6-80c68433ddb7)progress_status NOT_SET property_value_groups (Empty list)
property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f7a6eb58b10> requirements (Empty list)
summary None traces (Empty list)
uuid a928fa22-cef7-4357-9b87-675a432f6591 value 1 xtype org.polarsys.capella.core.data.capellacore:IntegerPropertyValue
"
+ ],
+ "text/plain": [
+ "\n",
+ ".applied_property_value_groups = []\n",
+ ".applied_property_values = []\n",
+ ".constraints = []\n",
+ ".description = ''\n",
+ ".diagrams = []\n",
+ ".enumerations = []\n",
+ ".filtering_criteria = []\n",
+ ".name = 'cars_defeated'\n",
+ ".parent = \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = []\n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".requirements = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".uuid = 'a928fa22-cef7-4357-9b87-675a432f6591'\n",
+ ".value = 1\n",
+ ".xtype = 'org.polarsys.capella.core.data.capellacore:IntegerPropertyValue'"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.property_values[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "3c105268",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "PropertyValueGroup "Stats" (81bcc3d3-24d2-411e-a296-9943029acfd9) "
+ ],
+ "text/plain": [
+ "[0] "
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.property_value_groups"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "06426fae",
+ "metadata": {},
+ "source": [
+ "## dict-like access to property values\n",
+ "\n",
+ "In addition to standard attribute-based access, these property value-related attributes can also behave like dicts in some cases. Here the dict key equates to the `name` of a property value or group, and the dict value equates to either the `value` of a property value object, or a list of PV objects in the group (which again can behave dict-like)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "574022f7",
+ "metadata": {},
+ "source": [
+ "This significantly shortens the way to a specific value. For comparison, this would be the \"usual\" attribute-based way of accessing it:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "a10cf035",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "150"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.property_value_groups.by_name(\"Stats\").property_values.by_name(\"WIS\").value"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "12800ba6",
+ "metadata": {},
+ "source": [
+ "And here is the same again, leveraging the dict-like behavior:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "0e03011b",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "150"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.property_value_groups[\"Stats\"][\"WIS\"]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3e8f3666",
+ "metadata": {},
+ "source": [
+ "This of course works for all property value related attributes."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "c56a533f",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.property_values[\"cars_defeated\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "2cc26810",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "IntegerPropertyValue "HP": 8000 (0e95950d-272f-4b50-b68d-ee8fed002c94)IntegerPropertyValue "STR": 42 (32be6f26-4b33-4861-b501-3bfce3df94cb)IntegerPropertyValue "AGI": 0 (addb1e4a-9ecc-411c-b7ef-b76388e5840d)IntegerPropertyValue "WIS": 150 (7c8c9c21-86b9-4dba-9c7c-cd9db2f09c11)IntegerPropertyValue "INT": 12 (647a5565-a1de-4e15-ab21-eb628eea413c) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] "
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.property_value_groups[\"Stats\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "b7943324",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "150"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.property_value_groups[\"Stats\"][\"WIS\"]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "65b98527",
+ "metadata": {},
+ "source": [
+ "These property values can also be written to:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "b34fdf10",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "IntegerPropertyValue "HP": 8000 (0e95950d-272f-4b50-b68d-ee8fed002c94)IntegerPropertyValue "STR": 42 (32be6f26-4b33-4861-b501-3bfce3df94cb)IntegerPropertyValue "AGI": 0 (addb1e4a-9ecc-411c-b7ef-b76388e5840d)IntegerPropertyValue "WIS": 150 (7c8c9c21-86b9-4dba-9c7c-cd9db2f09c11)IntegerPropertyValue "INT": 18 (647a5565-a1de-4e15-ab21-eb628eea413c) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] "
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.property_value_groups[\"Stats\"][\"INT\"] = 18\n",
+ "obj.property_value_groups[\"Stats\"]"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/_sources/examples/09 Context Diagrams.ipynb.txt b/_sources/examples/09 Context Diagrams.ipynb.txt
new file mode 100644
index 000000000..c33542fb7
--- /dev/null
+++ b/_sources/examples/09 Context Diagrams.ipynb.txt
@@ -0,0 +1,852 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "2cdf5dd5",
+ "metadata": {},
+ "source": [
+ "# Context Diagrams Extension\n",
+ "\n",
+ "We have an extension that visualizes contexts of Capella objects. The viewpoint\n",
+ "definiton depends on the object type. The extension is external to\n",
+ "`capellambse` library and needs to be installed separately. You may use the\n",
+ "below command to install it or find more guidance in the [package\n",
+ "documentation](https://dsd-dbs.github.io/capellambse-context-diagrams/)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e49dac7a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "!pip install capellambse_context_diagrams"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c93ced3d",
+ "metadata": {},
+ "source": [
+ "Now that the lib is installed we can load a test model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "d64ff435",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Cannot load PVMT extension: ValueError: Provided model does not have a PropertyValuePkg\n",
+ "Property values are not available in this model\n"
+ ]
+ }
+ ],
+ "source": [
+ "from IPython.display import display, HTML # we'll need that later\n",
+ "import capellambse\n",
+ "\n",
+ "path_to_model = \"../../../tests/data/melodymodel/5_2/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e88f088c",
+ "metadata": {},
+ "source": [
+ "## Logical Component Context"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "71d8da10",
+ "metadata": {},
+ "source": [
+ "and now as the model is loaded lets have a look at a context diagram for the `School` component"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "09c4d2ee",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "LF Whomping Willow R. Weasley School Punishment Care "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cmp = model.la.all_components.by_name(\"Whomping Willow\")\n",
+ "cmp.context_diagram"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e721cfa4",
+ "metadata": {},
+ "source": [
+ "## Component Exchange Context\n",
+ "\n",
+ "We also found it useful to spell-out the `ComponentExchange`s - this gives us a nice overview of functional interactions between the components"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "040bfc14",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "LF Whomping Willow defend the surrounding area against Intruders R. Weasley break school rules punish "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cmp.related_exchanges.by_name(\"Punishment\").context_diagram"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8cff65de",
+ "metadata": {},
+ "source": [
+ "it also works for more complex arrangements but we dont have one in the current test model ;-)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e9ecb867",
+ "metadata": {},
+ "source": [
+ "## Functional (dataflow) Context\n",
+ "\n",
+ "same applies for functions - we saw it useful to see what functions are dependent on an output of a function of interest and what inputs it needs to do what it should. We frequently use that view in documentation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "ba760fda",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "LF educate Wizards kill He Who Must Not Be Named Teaching educate & mature educate "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fnc = model.la.all_functions.by_name(\"educate Wizards\")\n",
+ "fnc.context_diagram"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b073bfc3",
+ "metadata": {},
+ "source": [
+ "## Layers, other than LA\n",
+ "\n",
+ "Other layers are supported too - for complete list see https://dsd-dbs.github.io/capellambse-context-diagrams/ (Features section)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "99743283",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Context of Root Operational Activity "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Root Operational Activity "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Sleep "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAeUAAAA7CAIAAADKEQXeAAAABmJLR0QA/wD/AP+gvaeTAAAakElEQVR4nO2deVxU1fvHz7nLbMCwDfu+74uCaIAiKihqGvzMNEvU1Or7LU1BS63ENbMySytTv2WaZiqKa+5CoLK4AAKKrCKLgrEN68zce35/oMYqywwOy3m/5sVruPe5Z5577uc89znn3AUihAAGg8Fg+jyEsh3AYDAYTJfA8RqDwWD6BzheYzAYTP8Ax2sMBoPpH+B4jcFgMP0DHK8xGAymf4DjNQaDwfQPcLzGYDCY/gGO1xgMBtM/oJTtAKbvkpv7JC4u91Zy4ZOymqrKepbtr7fCkiShoSUwNFT3ecXCz89aKOQp2yNMhwwY1XWEPGqE3b0fvV/UJm6fclJcXLX7l/jsnCdD/KwdPc209YSqGnyCgMr2q4ewDFtVXveooDw5NvvujYKQELeQYDeKwp3LvsUAU11HyKPGbsTrflSbuH3KQ1LSg2+3Ro8Odved7EzRpLLdUTAVpeKjP8dJxA1rI4LU1PCJvK8wsFXXEd1VY1fjdf+tTdw+u0VS0oOt38eErphgZqurbF96C4TA2f2JGfF533w1FUuiLzAYVNcR3VJjl+K1omoTISSurFRRUyOplzpujttnFykurgpbFjV3VdBgaDanf0t4kle2fu2kvtlHHDwMKtV1RBfV2Hm8flqbK3temw319ZHbN1U/SOdDqYpA0Ig4tYhLqOm8tuADHQODnpXZA07vxe2zE9auP6dnp+/3mps8hTAyWfyFM+lXLwGZBBEUV03LY+xEF6/hinJSUbAs2rX61Ghv86lTXJTty6BGIaoTV1bGHD/0IO0mj6YkiNQ2thg1dZq+sYminOxtuqjGzuO1nLX5IPPu4YiFy/xVzMxMoEAE+SIoEEGBdjXD2/S/kw7+E18JGN+zkrsLbp8vJjf3ScS6c8u3z5BnvOv62aikg9umuvB93G04Ql3IF9UC1XM38i/czJ32Ybi5rZ0CHZafRwXlO1ef3L1rpkDAUbYvgxT5VYcQOvj155Ls2De8dB3srJoiTEkNPHQl7UE1mLdiNV9FRbE+9xJdUSMZERHxgiJyc58cjbozc/EYgujJZB3DMLsXBX83CWhqqGTcKjicTZnb6JUnJsZx7F0NNQP8/Y8fPSUyt1ITqrfYrO7C4RmfXL0ak3r2TPLZv+6Wmzm56LZIidmS7L/SoZUxvzuJMoTQ2Epn7/aYoCBHul8Nwb8cTp5ME5po2Q7peUoSd+JQzdmNK8drmhtqk1wVSAsgLeAKhE4O9pMC/HZs36lrZSvU1Gy1FVNxL/NKdFbyvfI6WlVPi6pNT71WpWWh/RJmh1XV+Q+zSgmGtbIS9f6vYdpBftXtXPHuVP7VN0bo6oi0miQHaYFQQ/sVL4+hzg6bNn49fNx42Dp8IXHy8cSLCfl30koKKgiRsRpf+RcjdEWNnXgZF5frPtKapEkEQA8+yddip5g8Jgkoy8n9rcbkdfX722IfHr+edvavfBkAAICP3nvn/OE/224I9cZP3vLDnK0/zNm6feabTrCVAfso+/S1crbb/uiZalk4GsTF5Sq0ngcIt5IL7T3MenKYn32SI7ctGE4DgDIu3QjfE/PRgbyKnPPj3z6cLAMkSW76bNnp335ptQmb++fBzw6UkrraBkJp1p2yWgSq01IvZ0rYnrvRrY+rt3XsVawHpSGn6grz8kwqrrobc5G49KudSau3Rx8oqotav3rBGTECQE9H9N7b0y8di2yzIVtz62Rug6WRraVaY8LZ8HVpZUhBikLiE8v3H3uMekeNncz73UouDAz1BqiHB6O+tkaPQgAAxLCIJLk0RRZlRBcLZEVJ9xgvFwD4fJ60sbF1+ejZ32fL2bzjUd+dqkRARth6L1usHb/3Xn5B4Wf/lLwZ4eNMd8slV2/r2Oh7gYH2PdylgUtpaY22vrCnhxrIpFJ1VAWAAKD6KyXCJQu8Uv5IP3tN8FoAcyGLGeIBOByaS5Ity2fLrkXDwLW+gToQAOADAACoBoDnAhbn5Vy9VUFa2owaosEFoM0SJM64n8XTYjLzi0m9EaNN9bo9rGFso3Nm7/We7jRGXuRUXfadm8P06gDQkub8UzfC53PD/A037lJGfiZ371QhC00APNzd9p/Z2rZ8BKDAwsPSUwA8vVQfzU1IrnEcpwaBtDr976zMGlVXf1trIQRseWJcvaF2VfK9Bi13h1es+BCA1jaooeh2zq1sMatt7OtnxM1Mjcspk+6LpccNneiu0s2Zsk7V2El+XVpao60nRAj07DPUd0zUA00AAG1r9Rad/3u51Wwnq48j5u5+11bWAAAAv+4/5BM0ue2G7OMLp5ct2hu2aG94WEyqDBoFBH25c+7WnbMm18SfuKf76mw7Mx//NRu8nejuumRsrVNQUNG9WhwciKvqVdT4Pc4sKIquBmoAAAB5I0VV3/+REKemkZ32qPBxcfzlAgYAhmEaZbKWW0FVU6PKc/vTsyvZ5ssBAAiA+tToL359xDdWF5+M+vq8mG1vSfWdhPVrrz/kCXnZf3/2ZXp5t7MkdU2Vin9qlVrxgxo5VWfh4J78RAAAoC00yfjbm882mkrzbpaICzNuXa4BAIA76XdNrGzb3xw0fZE0NnBUNbgQoapzX5y+VCc05j/c9dnf9yQAseWxW47+FC/T1G68svHQ75mytjZsdUn8jWpaVx0mX/hsZyHQN7DQVrHytHQw4oJu706nauwkvxZX1asI+T0++3EFAs/Zn68/tGHZBNLN19FdIIJ8kZWAgAZDdPno14PH/0Eqo1zd25YPdQMmbp6v/2yQGQEgvR+Tdjun8m5uJa+KAaqgWZ13C6EWbp/tw7IIErDHxxoAYD9pwYGEbbN8CNcJw9wEIigQQf54KBBBgQggtHLjlsCZ77QsH/J9loRI9sdtffeyxMxu6ryRQfa8Z0e2If5YjsH4EHtzgn3VLPZkQX2gVWLrJQ4AEM7TxrzmrwJHaZR+cOV6ucNE7W7lNJAkGIaVY6cxciGn6kysrE9xPDIfZ9pZGH66sElyonkCERRoQwGoqKz6bvfeRZu/by+/Zp7E7ou9n5tyMo07dum0IRzEZCWfqLEM89JRAVr+108nPmDsLADUtZsR6uJMIVf0aPn5oteJ/NY2NuYhC80BYBvtauK/KKzUcDLUEDAOBhY6sPsBqlM1dhKvWRZBCHs8HgIAGDZuioGFw6fb1wgkD4dY1GhpVNTBkpSHNaV1hPeUN4J9/dopvPV4CGpM3Bp53mLM/OnOzrL8k2zbAZOuQxC4fXaMPNEaAP9pc6IhsfzUrzM9yaFOoqa4KZUxl2NvRMWmB839r7mtfZufUNH1XxjiP7/hQfTf36w5K/hpqs3TccCGqnJx5t93zmdDAMhhPiKy7ZLmuRKpYaRXV1iBUPfiNUb5yKe6dzf/um9juOD8rbd9+camT2fqqsS1h04kpjysWhixiaY57f0EITB1Mx1iW5fyQOo9XB0CwFTVVT4pjz3bSAAALBydNJtOIxABgADkGWkQsbXStjaSsvPb/k6UquqpVD2WGMkUs1Md0fl9K918vkg7GFnavLfld5lUmnf/XmFZqapQfeJ0e4Gq6osLbxq+aKK2sJB2nGWkpyZJf1DF2iNEkWxdowQgfJWHQpH/WPuFzB4xcXrsiUOHzsYDJpegChFH1XVk4IdfLyYIouPyCa6pv5f/yeNFFci6yRMo0DfiGXh6zhzz/CogWZslCAHUUC9FAAG28lG5mq42QL3UUjC9hZyqgwQ5+9Nvnzx+tO/wnvJbOVy6SsLm8jX1fKa8OdLWvqPyEYICM1cTF4HBe+m/7TnxZOibIqivoU9LvN/ytXzer5chtlxcziIEQOPjakLHmmpjI01IOk56bAkz49SkPf64mgUIIcR297FMXeXl3WdI0bSNU1cvfGZLL/z1SSoHAgAgx3NhyKjJwk2r9t3UV+OLBTQBKBv7UdXnV698OGnxWD89nE/1Kbg83rjps8H02V2wZSsu/pDwyMTEUocSZ6ZehPbhJpCXRj3JKiissh/yf25HNpw5TA9z4onLVax8HXltlnABYDMjL0bquOvm3b5h7bFGA4thcCLS05/2wSc92JBymu4hCLue8OpkbyOXYKs/ftwmnDVWs75YZhZgaQQAkOYf+zmF48HEH2kcu8yQY6TZykZfpEanp1+Ol9G3bqfLLCHk6+vWnozOs/PWtzcVKFqOLyO/7ja8gJCDAS0XOU38dty//yFg8Prm0Neffsf5VM+oFYtV1NSaL3npx5pQ953hmnyzpLCAUbHxWTvbQJMCIMB/ljQ3p7TRyGb4mvUFV+NL7kI1ex8SAERatV4CAOkU5KT5zz9iS59VI/X5UAlyxXSHPqA6AACh6j7VXp2DEABA12nuvIaCMhlS448In6Fz9f6d9EcCU3MhRAggqGMzzp0tLqFGLZ/qbgQQaG1DWA3/+D93r9+vVB0TuMxFIoSk8XuT6y/k3y/SsDblKzof7kJ5uAEMRFiW/ey99zS0tKbNm+c4ZIiy3IBcHYPhEwxa3KzOE40IeToMyTU0HRNi2nxlyyUIAEBpG/tP7u6FUxil0EdUBwBUdXv1+SW9lLn/cPOmr4TAaqS7VXNLgmv6irtT8zjZ2obSG+LyWtO+NBWppucbotc7fnchv+6dH8YolztJSaXFxaXFxRuXLnX29AwJDQXKyXTkoumuBIT7WP2E/qe6ZwLrIwzG/JpiSo/u2aNsL5TP+du3XczNDTQ1027cSLtxQ43QKsrwNXJwVrZf3UHV2Xk0hwPkUinWw8ukX6mO0BwxBeqSfScGDsb8mmZLj/52RdleKJ+yqqrLKSmOpqZDLC0BABRbvv/jD/3mvOsVMkPZrnUZVSenUQDIp1Ksh5dJv1IdoeE1WaMvxcA+Od/Yy0gJ3TdDPZXthfJ5nuk0/SsjtGZvXGPk4NyH5PlSwHp4mWDVycNgHA+Rkbohc+YosMDExMQrV54maHw+f+7cuWotZ8AzMjKOHTvWfImjo2NwcLACfeguKQkJgc8mfJpGEpd8HGfo4DzgjnbnKFwPmI7AqpOTwTgeonBiYmIO/vylt5MeQXIeVsj2/LLresINLpf73CA1NfXAvj1TAnxYWSOS1d/NepB801S58dpl2DBdQ8OWM/Vx+GArhLq6usbGxqbvPB6Pz+e3MpBIJM8NmuByuRzOwH8GN1adnAzG/Lo3eMVRb9WsYSRPSPKEczb9tX3b92Hhy5obODvYRCwNZeoqmPrKI2eizyRXPVsjS1rhOumIqpUISutYg6nrd0aMN+j8YbxInLQ/in31reHqPbuSjSCIdTt29IErYQcgSz5atG/fPi6HBgAQJLX7f78EB4c0N9i8efO6des4NN3UuiQSaVh4+MaNG5Xj7ksEq05OBuP4da9AkATFIygeQfE/Dg14bcna8GXLm6+nSSJq7NDJIx1ZaQOSSVqeBjmjIi4dmaUGGtI3T5gacTHt58BOXzKJqhJ//002clZP4zUAoFWzwSgMVvb5dPvZE1xInvq94oZp898ZNszL2Ni4uUn4f2avXjRLVl/J1Fd89fMRWfs3TYvvX4y6kFIiEVp4jJvga6n2sh6qX3Pt25W3R27+r6fiX3aKVScPL/W9twMYSFAEzYM0H9I8VwcdigB3VxvoC/99vsmth5I567dPPLUFyRoQI22/FJ6dn5fgWkk9Ajy28PSqj767XVnXqPPGN7s/9FCRZh1Y/OHOTIm0Sjb663OL/lm5+VK0JHjyvSXbt79tqaDnqOBzs4KAkKQJik/QPGc73blThk8Lmerm6vp8dUpKKgWlNXMnc1E9kjYgVtZOGajsxMKgbziz3w+wI8uz4xILvC0din+YOEf28/nFZi8M3Gxhl8xeAFfXboiNqHtPlu8xWHVdB+fXCoIgIc0naB5B80gO31BX83G1pHm8HmrCYaTigsJiAyFEjLS9amVqc8/si7ee8oE6RE8iP95Cf3LqnCd1/5uJS/YFn3yncNeWqvlXLk17mp2wG5ePLZb9fKrnbRLTi0CShjQPUjyC4r0+fvjvJ76ZYZ73fK2DBTh3V7J6846NS6az0g7O3w0xf8R4rU5bNObZsDaqvLbvaEpq4/p13FnvLhzFz7ly+nxyMWvwSsg0HyMy69ThMjvbR5euwqGu9/41G61PAADYqqzmxhwAJA+vHjke/49ohAtdJnr1Ncf6FgYkkkkRAQFgsk5HlZnrFsTceKIzakaIhwg/YU2pdNLYSZJgZd1/71Yf/iAG9cb70SFBNY2HQIoHKV5tfaOA0/pXZAxLARlqp31KotcEjvaw0LFbKl2xa44pAaQpV2Lzr37/n7lzF264UFyYW8hQ5p62SavfXLo18ubjDrJz+enxiyn69acXgJCkm07ekObZ21hU1DTO9BTMGaHy/LNpqtrRs3FI2sDKmvLrNn7Q1g7C899+ezGv9ukqyDcf5mpo6B443sdaCMsTTlx4yDMxJaKXTFoR28Dcj/ww+K3tGVCkq231r1lT+0atjNmi/bP/76scLQuNzC9CQ/fekbQ2YO4f33H2AQMAc//I+2+tjJYamkqOhAZ/c5fphcpSugD61OfFdJJfa2gKqivr1LVVFXZwlI24qk5dQ6DwYiFBQZoHaR5B86SIKnxcYa6t29zgTpGUy+XoCGmmvhYxkpY1zxm9+vyRWfy0Db6zLmdKgrx5kMtXdZ37/a9va/xrNH1fgsuFyIO/LfD9fdHlyNm98sAM3JdSEJCgm07eBM0naB5NkRIZ4lL/HjRjDepJVV1DXS0pqwftjodQ7iuidnwf8UWQ7QItv3kr1y+fbKlvb60jknl5uRgTAASGbQoEQFbn+ehE6PUCxgnwx37y06fBXADYwmZmAAAARS2M89L//lE8P/LTN/WhzCTj2OY2BgWM03M3CKMpYZ+8PYpmbO9FrkqsRg6aClceVl2X6SRem5hqFuWWCbUGTrwuL60W6Sh+dyBBNuVTBM0/ffm2hoaa7vKi5gY0RexYNRNJG1hpA2IkCLS+xgsAyun95S4jNuxbdHKBiVuQX9amX+6+vtSBB1iWJQhCUteo5jBh/prRRsXDT2bKQt24dE25WIFSJ0mCYViCHFzjK4jthf4WBICkIM0jaD5B8crFEoqEarwWFXu/VGppqEFBKSNtYBlZux7QxuPCdo8La3gYvf2/80I2Gt5Y3SwFaEj/ZfGnpxsNzYR5+Q3eUgAIkZ6oo2PX0rixpKjWZJgWBAAADpcD2yut2c5ACAAAUKDCl0okPa+U9hmcquuITtXYSbwe6WMZnZjt4GGhUK+Uyf3kAo+hxp3bdZOm8RBI8WWA+mrnkR9+2t388uqDBw8e2fPda6McmPpKJK1HjLTdnAJqTfkk9Ms3vomdtdVv3Nofb/zn3YDx6poUb1TEgfAhd3e99UFklYCPZKKFX3tzIG/8W05vvDPhzrQ1e5d5K2IaX0NTIK4YUH2prlBT2Sv9LYKkmzJrSPPiE9JFQv6SY/++hY6RMalFksmjvZG0HskaENt+vH4Kz2T0ov+O/XFPnhToAvT0SfiSK1u/pz6I/3ksr3JfflB+azmhFg/Mb2VMGBjzs++VsIFmBGBkDOq0tF5kcKquIzpVY2fxeqTVb3sTS4sqdIw0FeqYcpBJmfSErBkRQQov+WpKXsSOU5DiZuSWWFjbtb0XJj2rYN3us0jaiGQN9wueqJiInq2hhn2RfOTZd+dVCelNX3VGrTj894p/C3BbfDR2cfMSTd7437U3FLgLJqaaRXllwkHWcsrLeqO/BSFBN81kEBRv15/n/Ce97uHh8Xz1mTNnTHkPlof6sw3VrLQBtDvfWHNpw6IzHB8vG2027/S2m+NWfMEjBBYmj344dMFrylBPQ2PutQP7TjdyLu2Ikwa1iPeE1nOzEfY6BABES2PSfmYoPXnB51ofuD/+/WAms661wUt8OO3gVF1HdKpGMiIi4gWrORySosiLp1NdRtg+7Rf1Z+LPpahz4JQpXX3NTRehaVqgLlLVMVPRNnZ29/xi0yaSbDGPThAEh68m0LVW0bdXMXQ2dfAaGzDewcFBsW7IiVTCJCXmO3padW46gEi6nGFvru7maqTAMk+dPKFC1ttbW0gBfeDM9Zike1FRx728vDyekZ2dDWuLXc00a6orxdWV8emFXD3HsePGtSiFY+pixy3Ly84tadQbG/blYm9NCGhrX29OxrVMZDFs1MQJttUpd8p0Jr0/y83QytFMhdS297RWhwA0M/Ow1SYBIPRHBDQ3dnLzCw7UL76TyzoM5SfnWM6fPsY3oP3SIHxeLCT4xm4uBoq9C3Nwqq4jOlUj7PRFYyyLVn16Wt1Yx3/a8Bdb9nEKcx4f2Xb22y3B+vpCZfvSF6mtlcxf8Mdby6cMjL5UV5BJmR9X/LEuIsjCQluBxS5d8tGePb8CAAEAxsZGkUejbGxsmhts3bp144Z1z64GQAChJWHLV6xcqUAfukh15NtBtz+KWe+hrBsxBqHqOqIrauw8XgMAxOKGsPDjVu4WfsFe/TTJLsx5HPnjubAl/h4eJsr2pe8SdfzO5bj8WWGTYS9c8tgHufbX7dqislUrA5XtyMtGlrp37V/Iw6HhzHcXh+36c76lMqf7BpvqOqIrauxkPKQJLpcaPdrm5NHbGTdzjaz0eQJup5v0HWRSJuF8yoU/roYvHYOD9YuxtdWNjckqKao0d1D8lGxfozDn8YU/rq74JEBVtT/pWSFAvipdlX33IX9c+Kchli/pPsaOGFSq64guqrFL+XUTMhl77FjqkchkK2dTBy9rXSNNNQ2VvnkhDmJRbXVdeWl1dmpBRmKWg73uO/NG4GGQrjAA+lJdAfe3+hSDRHUd0XU1diNeNyEWN8TEZMddzSsuqa4sr2UYVg4/ewuCgEJ1gY6OqoeHsa+PpWJHJwc8YnHj5xF/QS4n8M2RGqKB9nQemZRJupSaeD41PAz3t/oQA1t1HdFdNXY7XmMGA/2oL9UVcH+rXzDAVNcR8qgRx2tMh/SLvlRXwP2tfsSAUV1HyKNGHK8xGAymfzDQ+hoYDAYzUMHxGoPBYPoHOF5jMBhM/wDHawwGg+kf4HiNwWAw/QMcrzEYDKZ/gOM1BoPB9A9wvMZgMJj+wf8Dvpid0DRee00AAAAASUVORK5CYII=",
+ "image/svg+xml": [
+ "OA Sleep Eat Repeat Rest Start again "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Eat "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Eat Make Food Sleep Munch Prepared food Rest "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Spawn wild animal "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Spawn wild animal "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Make Food "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoMAAAA4CAIAAAAJnmVGAAAABmJLR0QA/wD/AP+gvaeTAAAdU0lEQVR4nO2dd1gUVxfGz5RdttB77yogiBQbiKgJYkVFxZbPHvWLGkVjjMauSfzsiZpoEmNPYkONYjdqNDawgKBIE+lNyi4sW6Z8f4BIX2AXEby/Zx+f3Zk77z3geefsvTNzwViWBQQCgUAgEK0E3toBIBAIBALxQYMqMQKBQCAQrQmqxAgEAoFAtCaoEiMQCAQC0ZqgSoxAIBAIRGuCKjECgUAgEK0JqsQIBAKBQLQmqBIjEAgEAtGaoEqMQCAQCERrQjb1gOTk/Nu3kx89Sc/PKykuKmMYtETXO4UgcF19gbm5jm8vO39/R21tXmtHhGhBkN2UghzxIdAmjKBKKmKNX+0yM7P419/uJSble/g7unjbGJhoa+rycRxrVsyIZsLQTHGBJDu14MmtxOeRqcHB7sEj3UkSzW20N5DdGglyRPumDRlBlVRsbCWOiHi1bfuNviO79h7qSnII1QJGqIfCXHHYnttysXTt6kFaWmgo0H5AdmseyBHtjLZrhKamYqMqcUTEq+0/3Jy8dKBNR2MV4xMVFfEFAg6Xq6IOohyWhYtHHjy793LLpuHo1NM+UKPdSsVigiR5fL5aAmsTIEe0G9RlBJZlxUVFQi0tgmzy1VjV+m1CKiqvxJmZxYsWn566bFCzfx0Kufz0nq15LyIFGCUU8GQMpwwT0DzdoBmfmVvbNE8TUZXwg/fzX+atXzvk/Zy0QTQe1e0GANeOH35+8yyflWoLeQyuIaa4UkLgP2qiW/ceagz1fQY5oq2juhGkZWUnd24QvYrlYwqhQCBjuaWsBq5lNOLTuUZmZuqNtgEamYrKK/Ha9ZdMOpn6j3BvXhzZaa8OLJm0wFejk4M1JjDEBAYY3xATGEpAuPngBVP3nv1HjGqesnqhil8rhAZ8dXxnUqNUI2EY9pdV5/r62A4Pcnt3vSJaABXtJpNKd8wbN8q2qJ+HDSYwxASG5XZjefoHzt1LEjOTv1iq3oDfT5Aj2joqGuHVi+fHV89c3E9oY2NV6QJMYCCieRv2nnXuN7hXQKB6A66PRqaikovJycn5iUn5voNdgYXmvQ4tnbo1UNHRjP86IWnX6bgoMat4+XDv3UK+gL964UzJq8SkZ88aVKAz9844cU3y5mNZ7Lrpf8fRjeudlcddefq8lFXakhHH71pwNUIKLJW4ZeblaKrqXiZp/2/rr8kb+SO/lWr8b6mOTpv0wjFs+Azfo0cfSSRytWYR4p2iut0Orpq7xC2tbydNxeucQ6eizr+Sg+TVkdPxYgyfNm5YgKfzxaN/1Ht46ZXjwZ/fz2DebpFEnJ/06T9JNe3GZhw9tPxcKaMsntIrx4PH/Pz5nH3z5+ybP/f4iQSmaT+O/Nm3M28kNNLsyBHtBxWNQFP0sVUztg9mrQ05sfee7bqSkcuwqbevn0tjdLQ0Nyydl/Lg36zU1IbT9fcjsTXTlc5KDL9XSLdIKiqpxLdvJ3f1cyQ4RPPODPGxMb66GRokDrK8XbfJ0b7MoePJt6/HXLl5P50BAJg7Y/Lfp040LFJOjS2NDEAafyUqrkR5S0zLeemhoT15TdVXKtX4l0qdAphY69u5mN2+nayKARCti4p2Y1gWMh9Z6HGAlZ8Iz3bob53y14MH96Iv37p/VcQCQL/ePq+exTSkII+NCIuSV3xki66deiFiQYV0xUwCh27dNWX7rinbd44e1QF7h6ZAjmi7qGiEJ3duBVnlEDhGJSUfKLEaoxO/41bambsxFy+kUAAAsGD29MvHjzacruMndK6Zrkx2YvidAqbJ8TQmFZVMoT56kj5gsk+FJ5qOTFKmyaEBAIBRAM7lEhqQfSZSoiGLOJc9YY4jcLlchqaV61f68u3HkqfrlomnbPexwqn7Gw9EDZo60zl567RbIluBrFAsMfRYsMxT7+71o49SqRVHU0cHzhmghwMTt+fXIxYT1w4V0k+vfrpKMutIUE++ImLL79EDfIp3pAz4McD17QmALbh/44dDqcU0LcrOs537ZntR0m/rbjwuxShG0GfuyPEuaduqdeplhyVu/ezlgB8DXCGxIp4CscTEOcCmIDKmKL+I6zd/5BiLtH3VRN6edVSgi4/jrRtxAwY4qaSCaD1UtBtDMyQwAADAUjTG4RIaJHX3agKFc87cLh09xhAASJyoV58Fwq6/VcrJ2LyuXQ0xkD97dNfQqUshsMAknzn9/bkiFii8o8/ihZ0r2lMFF9aejR84el5X8fldN+/kKqSEaciij3oaYW8EK/5926Ms/9pP1y6lSCUKrX5zBge78LDaW8pyz/9w5UqanCHoYtqRbb4vkCPaKCoaoay0xIRkAIClGZYgNDgkkfHsRqaAyoiIo7u7AfD5PIVMVlO/VroyL6um/XyDewfjUlLTV7zOmrDa15XTpJCUpqKSSpybW2Jgot3oR45r4uTusWOrwVAA0DCZ26v4yA3BmI/NCgYM6meYd13CAMCxU395+PVrWJ9lqdTfvzwYXj58ZyTpVMfRwLJQPudc/Y1E0OuLMQO05Pc2HjgZ4bbIr+8YTzG9KGSECQbAsoDZd7fOP59WNrRD1qNcgUFZ5DNFD/fsqFQTDwe4+UYEAFhgmZKE/ftLAjf8p6e25NJXex682QU6VmPXTZkmwBUvbiza92zgOs2anXavUCiPx2fxmABNyY1Vv17SnvbNRi1F9NXQ358PXOdcQ+TNIapg6Wh0/uBdlSQQrYqKdsNxQsS3LZVlavI1QoYY/XkxxWKwK0/UZ15v7etPSxiApKRknp5+vfossIRN18EpN8++cJ3SSfbv6Xyv8c5xmwpYwCwDBv0viMcFyd+r//gr1mkYALBlUXsv3HIJXOnDe3ngVFTXEesDBJJ7F5b/meo1z5qsEGRyroQvjuZiAJhWh0/Xdhf+dfmaacD6BYZ0/K2lm++6/tin9hbe6Uv/2AT+b4kRlnp3yVo5NN8XyBFtFBWN4Nm7/2+H9H1dgdPR4ZPHKYcLHCd15r8e0cMuMz1LCqAJ+44c8x00tKZ+tXTl2Ez6Xx+nqmkfN3X6pE7Xrndcs9CObHJOKk1FJZVYXFwm1OY3u0DgJPnRvE0r9ny5dBBj4uQ417P8ji0uJnAPEJDHzl5+mlM2YdSUhvVZIK0mbAzuJwAAgLJn38zNrTVzVf4eMH09cwEAxrG1F14okLG1hpocF4eOe5IT5UaJSfoTpzAnIrLlRqnJZrbjuXCz+oQYnfQy0c5prg4A8Do46z2s3IsR2OuXl89lpqdliItIEatZq9PKwADT1zPjA2A8azstTS0uDizXxtBEXFIMhEF1kVrD/magrS8sfF2qmgaiNVHRbgAwfs3uJaFjln8kM7cwnzLyzR1bpGGAr+Gj6Gc/n7o577ttDepj/F5jLMOPxxVMKPqb22WJBRUHAMByuIr4mzGPk4qeJxfximkAJv/ahR0C1w3fGGuwopgnGQlR17Y9wkH6ukBeKGWtNCtGxZhxwOCNM0wrHgRlSy88pD3m6nOA5XTo3EdwPja3lFdri0YUeM014AALpjpGeK4KvkCOaKOoaAQNgcB70sr1x75ZPJBw7+3SVWCI8Q0dBDhm5mHMZ/f9eeY1K+zTpWtt/erpCixA9bQvHzE1JyGVpqKSSswwLIZhqpQI1x59jCyPr9m2QkOS7m5bYqxfWIZnx2aUZYpYz8ARE0ICGyVex+w0ALAsU2V7tbkFDGNr7QIA0LD0tLofHZ2Spm07wBO7fzIpyixP6OnOgyyoXtVZHAearq3PvHqwdoto2IJeYwdop38trq/Tmm8wrOKaA4axAPSrB2u31SPSfHAcp2lGJQlEq6K63QyMTP+7+8Lu7atlD2KdzcR2piKKkxefRyXny8ycPT//bjtONDQ7DQBAdvT8WHZi3Va+d2hPAfYCAICV3d9+8rJd/xkhrq5UylkGWMB0HMzpiMTHOV0+NiG5PH2/yUOmOuE1pGolNkvTNFVxNYrAOQTgtbdgOM5QdDXfNX+SADmiTaK6Ebp9HGRm57x85xqBPM3DrkRft1CCZUWlleRKcJ+gsSN7+9chXjNdWdmDmmlfvUETUJqKyh+1UXHKFACMza1mbdpPU9TLhBfpuTl8gfCjUU6a2jqNFC9vU9mShfKJXx5fuyQ5rZSx0pQVFshrTlNXNMNJUi6SVO2F06Ub/+zhOONhw3l83Mvo7qGLgoA1PKhyLNA0DSxuY2b5IvbOa0d/A3lyQgFtVTE7TWfnF9k4edgLybRSEcNCHZ3WNW1e8SNURMLm1BQp71TlXzWiraN6DvCFmpO+3gwAqUmJWZkZBEl2HWgfYGrWSH2WxTT7hFhdOGk6yB5jFeWHlKanc1wmWphoyWNfFTNOLAtA2nnPd7m6fMM9h4093Lrxz4QnB3dy0MZYlsUwrLpgZacY39mV3nEtO2iaKZkZH0lZTzcW0DW38KiO1M6/s4OmmnILSgpZ1a/aINoiqv+nW9h3mL31MKVQvIyPS8/L1dTWGRziJNDUbFi8SrrWTnuSYCQyObAtsNjXu3volSBJR+fOjs6d1aRH2gSNjN4W+vslEyGVh9nV2QbjewYY/m/j0Vf+fgvHWXABADAtTxtyZ0JnDx4G4N5dc0eqmbshBpXfVgijLna39m+MWrDEbfKU9O+/OnTZWEtQLKg8txBubn7HLy8OjTTWgzLConmx465ufieqiLzt1N26La3ohnifsXZwtHZwbM6RGm4fba367COm22uo9oavDz001eKLBZyKoS9m2D9wdswfW/dabJgWGPLTlbULH2rzMJPAQTP7atazhgFuOzqwz5arS+cTPJ5ev3kfWeM4W8eWAN+Nl79cwDMxZEXYu1uCAdEeITmcDp0b+0w5k3vlwlfRXAwAMK73zOA+1dOe7ODUR3R51bK0IfM/8jdR75IxSlb2GDJk94Zjs9XaI6IF+Spkd3g4+v9qM5SKxUItrcqPyG5qBzmiTfAhGKHhVGzEmBhNDSEQLQDDMCtmz9bV1x89bZqLh0fFVmQ3xAcGMgI06jrxO4gCgfjweBoRkZuZmZuZ+e3Cha7e3sGTJwOyG+LDAxkB0Ji4nUHSuWH797d2FIjGcvnxYzdbWzM9vZjIyJjISC1cP+NZbwtn19aOq52Q9vQJXxGDHPH+g4yAxsTtCg6TG3bgemtHgWgsecXFf0dFuVhbe9jbAwDJFBxZMs9/yqzuweNaO7T2QGrME54iNuxAbGsHglACMsK7eIoJ8c5Q4MYTJnu3dhSIxlI5FCj/SOH6//l2jYWzKzKdWrB07SrlRE6YgBzxvoOMgGan2xUUYRw8ZYoaBRMSEsLCwsrfEwTxySefmJqaVm2QnZ29d+/eqltMTU2nT5+uxhjaK1H37w94c39K+eWx0CW3LZxckePUhVXnrmUcV/U6AqF2kBEAzU4jGiY2Nvbn778b6GmKkVyRFOvx/baIh4+Njd/+7e6MjIydO36YEjKYoWSsQpqTm3s8uaDNVGJalJWHm5hqKvmTZC2DW7duxubm1W8ZvY3s9j4jkUhkMln5ex6Px+fzazSQy+WVDcrR0NDgcrnvKL62CTICKP2riABVFndGr/f/1QJ0tDb8eqL3ism9t84fNNyv48rly2o0MDc1XrNwyup5Y1fMDpo+ole9cYgOj/JYFklVfKIeLfcMPlTUyCDol+d/Dk+mlbaTHh/vtfwRpbRdRQxRW0eO+zFOuexbmMTNfYf+kqOOXzWO4+t27165Y8fbJzegtfOn/b3USuiCzy3MTe1trextrSwtzE6dCqvRYOPGjYaGhuZmZuZmpuZmpoYGBqtXr1ZzEO2OD8UIDYKuEyOUgGE4TvIwkoeR/IWfBLiMWrPnl73VG8D2PYfmjA9gKSmrkNWnoxL0y/O7z5JThtirdQky0nP1vRvqFGwqVVczKAfZ7b2GoVaGOE0a6EbwdOIypaNnTO/WrbulpWXVJl98NmnV5xOpsiK6rHDTnhNUff+jsqd/bg57QWGkpqmL//Bh3ibvar1D6tnJ37J9ZvQ3qxiGUXmRp479W2QfOG6gk1YTFo6qqaMKyAjvbrVLRFsFxzEOD+fwcQ5PX0vbvZPVcl+Rr4NG5f4cEd1zy+GJA72EhIyl5U0diFAPvvL50efW/iANOmFT/4V6x/+aJtriP+KCuT03LyuT9f/uj40DMnauC4uJuzMsK+LrY1/7yR/vDl1+KlUiIT2+/HlzkCUOJVF75oUeiJdQhCxfMaRS+elPE2b+nEyDjOP11YHd42F7ddnBxsmb+y/QOXr2U6Okzf4jLlg4cHMysog+04fQN6/GpqeXuS07vHtUyc/VRRAfMhhGcHCSj3N4rp2Mpwb1GB083L1Ll8rdUVHRJKYomTpUgy1jFVKWqX96RhZ17MDz/tun2BTHnv6v34HPLodNtX0nV0mo2BN7ouymVVRQ+tnW8V+L5i721+WSTVu/sboOQjXQmBihBAzDy089GIeHcXiWpkY54sKqDUy0CVdL/uOYeF8XE4aSNjARQ786/GnfW+WLErMlr1Ksv6m3U0HvpcfXdCXiN/afdiAhcMncFcGHjwWd3T2AC9STDYtu9P394icmovCZgzb9M+h7v8RdC44777y+rzMWt6H/uJI3ImTHib9cn63Dg9zDYwJ33R09p6bsYqJqj35Lj692Zx+t6DkucdPD8O+FGb8MG/pTRPC6miItCrLbew5GcDAODyN5OMkbE9jj8F9bxtm+rNzrbAeXnstXbdz9bWgIo5CytKIhKaF9zwEDvcmBg1zEPWf9/nxov6cPhF78x5dS7EdP8TMpjgk/eS2ZdBs6tr89H9iCe2GRgk70w78TiS7DQvra8kCWFXnx/O34YqHLwLGDXbQK7x69W+/hAMAWxYSfuBIPdmXiyiQre3Jk/cF/Mzr3umv1cZePAdiShGsnL8ZILf1HDfcwxKHOLXXoqJ8PzQhKvs4QBM5QTOvPsKNXI14szeK4epclBwAADK889eAkr7RMJuTWTBuKZnGgGErKUnK2gXSy+eSXG7fKubF3km39U824saUZF4C07eIkzc6t+tfEmKzbN+5H7lsyfeq00AMxWS9TxEzePzeZwJFOGgBcWwerKqIaPEn0iV3frthw9Glydh7TkCzgxhamHAANJ9dOWnr6fADc2MUJcnOZWiItB7Lbe+8IDCM4OIdX/sXUqYNdYYlsvLdgSk9h5WvDcK2wi7dZhZShysfEDRiiAlxXX5dDEgX/7pg6fnF4oaaZrkDyz9KxKx9pdbQu/HnC5EMZDLAFt7eMHr8hTmApfLJqyNQ/s1kq/sqpx2VGdoYZP4VM+DWVbvBwkN5bFfRZuMLaUnb+1B35m545lh7upgKrboGBvo5amOzRd8GzTkktLMpOz/h4wRURQO0tdeuomfZnBKWpqGRMrKsnEBVJdAw01fp7RrQI4mKJjq5A7bIYhpefenAOD+PwXyRnOPhUS5v8EiY2XeJub8QoSlla1phTTw2Y+r8AY1iNqo9p8ISOY1bu3dD9TRBsHkHQVO1pQLb43JwRv7lu3rLwP/7yazur1dBaspVU8QuGYQ2KqB1kN/XSEo7AcE75bRPl12s4JCGnWI0qE7uWumR+sUQqKSWoMmhgdhqAzn16/dq1AkXm3b1HjWf94UgcI91n79g0zwqHoj9CLjhMDuvpQjKz+p3Yc6v0PyEA3D7ztywYa4KNckj1+epM9thZk75xA2DlRcK7fseiFP2ggcOHXv0x3Gv9nf/20YDBcKt3dEUIpGGnLnY2md16dHflQOmZH8I6r/53Vh8NGGSU5P396de9dGpu6alVp46aaX9GUJqKSiqxlbVeRnKetn77+Y20YwpyRYZGLfA/VXnHFocfm5xVXCrttkFUdT+OwapZg3kkTUukLNXk68S4kYlWQkyiYnhnKi0li9arOwYulxGL5QBczLDfAMMffr38RbfBhhjLMBiO63l7yWb/8fjztd687MycymLJ5r9IEPot87XTF916nkp3b8aPDgCva4hgGNBUU+62bgLIbupF/Y7AAAiy4rYJklcglpMEpsWr9q0uPldhb65LYgpaIWVoqoFxECt6GfnvHcrAstu68BWuupAImAaPiwEAU5yXkx4RdmD/EwKAN3i4M6eyewAg7Tva5L/IoXJivlmw64WWjXn+P2kaAQANHM4UpGfp2dpwAMq/YNYFk5+SrlvRhtfJ1eZ1dl5uYc0t+cVKddRA+zOC0lRUUon9fO1vPEh09qr7z/8i3ivin6R6eVoqb9dUMLzy1LN+59Evlyz7csmSyp0PHz6cMWncvBA/qqyQoaQM1eQxMW47cUnvsRN637C20CnGMY86G3E8QkJezxs07J85O7eNm/njV4s+H95/p4EQs5v867YxZu4Lfhg1fU6fvgY25vRrvFulcPCn1iFBvhdsLbQKjXnNu68Es6kugpv7+Jd+Nmml/fG1gXrqPhMhu6mXlnAETnDKR8MYh3fvfqyhNj/0VGnlXpqiozPkQ/v6sIoylpKyTEOVmHQMWrxyhfebc3CV+RbcyMHB0H7A/JXjDLC3e9nSEgkLgNGpL7PNbUxeHQm943vw4lwr+s6iizuqztbUcbjEwiTrSrwUbOofl+F6pgYZ119IwUYAVFrKawsPM0O25hYTUqmOGmh/RlCaisoqsZ/DgYMPcjMKjSzqHqsg3hMoBR17P2Hc6kFqV457mbVmTzhGaGS+FqflFC4IDa3RICv39bpfzpev7JFbUAxQzzoG2p+cfPz2E+m5/lH505iY8cCN1wdWbWn8xY1z5e+4gXseBAIAcHouuxjx5knmThN2XZpQ9QDdXotP3l9cs0PCbuL+iIlVt9SSfdORY2WPvDF/PBwDAAAcn82PfAAAaois+ecxtAzIbmqkZRyBYTgHIytum/jl6KV+Q8Z4eXlV7j5//rw179WXk/sxUhGjkEKDd2w1gCBg/rSNn0z/jrugjzA9S2fI6J46AIp734duspxpG/PTha7zwk30L5mm7d0b5tgl9bcz6YRvw4frBUwLWLv4sx0lwdp3f7wh961lFgDQHvLfQRsXfbZDMkrrnx0PBq5dqaNN19wioJTrqE47M0JjUpFo+MFzLpcgSeJqeLRbz44tOBmBUJl7l6J0uFhQkJt6ZQmCEGjqaBrZCg0sLe06/fDDDqFQWLUBjuMcDZ7A2FFo2klo3tnYweujgIGenp7qDeMDAdlNjbSEI86d/UtIlDk52imA8/v5uzcj4k6fPtO9e3evNyQmJmKlmV1s9EpERWJR0b3YdA0Tl48+/rguMQwjTV297ao8wovhAquubmZcACBMe48NNM54FBlXoOvk7WqjQxbcORzTeWZvRWKx4+Q1oX4GBN+5v68g6XEy02XqrIGWVi6djIj6D+do2AUEe9FxMfkGgdPHe5jbu9hWdIxhhEEnb0ddDIBrGzC6B/bicQreY+7aGR6aWB1b6tVRJ+3MCI1JRYxVdrc4w7BfLw/XsTTqN7qHWsNDqI30pJwTOy5u2zrS1FS7tWNBqASym1poIUcsDF2wf/++8uu1lpYWJ8NOd+jQoWqD7du3f/vNujeP4LDAsqGLvly6rOaydM2ASax49t2kzRemRtFujNDIVFReiQFALJYu+uKMQ1c7/5Hd2/4XlPZGelLOyR8vLQrt5+Vl1dqxINQAspuKtEtHfGiVGNqFERqfio2qxAAgFstWrr6AaXAHTPDTNay5MhmiVaAUdMS16AeXo79Y1L89nXQQyG7Nox07gi24e/CSxujxnkLlbdsPbdcITU3FxlZiAKAo5tSp6BMnnzi4Wjt3dzS20NPSFeIEWursncIybKlIUpArSoxOffYgwdnJePq0nmhSuv2B7NZIkCPaN23ICKqkYhMqcTlisfTmzcTb/77MzBIVFZTSdMuudYCoAY5j2joCIyNNLy/L3r72dnYGrR0RogVBdlMKcsSHQJswgiqp2ORKjEAgEAgEQo28j2N8BAKBQCA+HFAlRiAQCASiNUGVGIFAIBCI1gRVYgQCgUAgWhNUiREIBAKBaE1QJUYgEAgEojVBlRiBQCAQiNYEVWIEAoFAIFqT/wPjHcqWyAVBiQAAAABJRU5ErkJggg==",
+ "image/svg+xml": [
+ "OA Make Food Hunt wild animal Eat Hunted animal Prepared food "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Hunt wild animal "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Hunt wild animal Search for animals Make Food Animal location Hunted animal "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Search for animals "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Search for animals Hunt wild animal Run away Animal location Spot it "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Play games "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Play games "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Spawn tree "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Spawn tree Create landslide Tree "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Create landslide "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Create landslide Spawn water Spawn tree Build house Unstable ground Tree Wood "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Spawn water "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Spawn water Create landslide Unstable ground "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Build house "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Build house Create landslide Wood "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Run away "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Run away Search for animals Spot it "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Repeat "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Repeat Sleep Kill Start again Hunt "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Kill "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "OA Kill Repeat Hunt "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for act in model.oa.all_activities:\n",
+ " display(HTML(f\"Context of {act.name} \"))\n",
+ " display(act.context_diagram)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b9b28af3",
+ "metadata": {},
+ "source": [
+ "## Customizing context views\n",
+ "\n",
+ "For almost every context view you can do some tuning. Just like in Capella itself you can apply view filters, like hide or show exchange items instead or next to exchange names. You can see more of the tuning options here: https://dsd-dbs.github.io/capellambse-context-diagrams/extras/filters/#capella-filters"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "2c88ed82",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Context of Stay alive "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "Stay alive Escape predators Eat food Functional Human Being "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Escape predators "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "Escape predators Stay alive Prey Predator Functional Human Being Weather Entity 5 "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Eat food "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "Eat food Stay alive "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Provide environment to live in "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "Provide environment to live in Provide food sources Environment "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Provide clean water "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "Provide clean water Provide environment to live in "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Context of Provide food sources "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "Provide food sources Provide environment to live in "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for cap in model.oa.all_capabilities:\n",
+ " display(HTML(f\"Context of {cap.name} \"))\n",
+ " diag = cap.context_diagram\n",
+ " diag.display_symbols_as_boxes = True\n",
+ " diag.render(None, no_edgelabels=True)\n",
+ " display(diag)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/_sources/examples/10 Declarative Modeling.ipynb.txt b/_sources/examples/10 Declarative Modeling.ipynb.txt
new file mode 100644
index 000000000..7b07b4554
--- /dev/null
+++ b/_sources/examples/10 Declarative Modeling.ipynb.txt
@@ -0,0 +1,276 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Declarative Modeling Example\n",
+ "\n",
+ "Declarative approach to modeling means that one could define or update a model using a fragment of structured text. A number of fragments could be \"played\" against a model in a sequence to build it up.\n",
+ "\n",
+ "Enabling declarative modeling for Capella models enables a range of complex automations around modeling process that are explainable / transparent to human auditors.\n",
+ "\n",
+ "This notebook will demonstrate a basic application of this approach to modeling on a coffee machine example. Please note that we will not model any specific modeling process but rather a \"free-form\" demo."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## System Analysis of a Coffee Machine\n",
+ "\n",
+ "Lets do a quick system analysis of a coffee machine. Lets assume that our meta-solution is an automated coffee machine for a household use. We may look into variant management scenario in a separate example.\n",
+ "\n",
+ "### 0. Initialize\n",
+ "\n",
+ "But before we can model something lets first initialize the model. We will use an empty Capella 5.2 model as a starting point."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Cannot load PVMT extension: ValueError: Provided model does not have a PropertyValuePkg\n",
+ "Property values are not available in this model\n"
+ ]
+ }
+ ],
+ "source": [
+ "import capellambse\n",
+ "import io\n",
+ "from capellambse import decl\n",
+ "\n",
+ "path_to_model = \"../../../tests/data/decl/empty_project_52/empty_project_52.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "to visualize the modeling results we'll use context-diagrams extension, you may get one by uncommenting and running the command below"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "!pip install capellambse_context_diagrams"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "lets verify that the model is empty at SA layer:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "At SA layer the model has 0, out of which 0 are allocated to Root Component\n"
+ ]
+ }
+ ],
+ "source": [
+ "functions_allocated = model.sa.root_component.allocated_functions\n",
+ "functions_available = model.sa.root_function.functions\n",
+ "print(f\"At SA layer the model has {len(functions_available)}, out of which {len(functions_allocated)} are allocated to Root Component\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Also for this to work we'll need \"coordinates\" of some key elements in the model:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "root_function = model.sa.root_function\n",
+ "root_component = model.sa.root_component\n",
+ "structure = model.sa.component_package"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 1. Context\n",
+ "\n",
+ "Lets start by renaming the root component from **System** to **Coffee Machine**, creating a human actor **User** and a component exchange between those two.\n",
+ "\n",
+ "We can achieve this by applying the following YAML patch to an empty Capella model:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{Promise(identifier='usr-port-promise'): \n",
+ " .applied_property_value_groups = []\n",
+ " .applied_property_values = []\n",
+ " .constraints = []\n",
+ " .description = ''\n",
+ " .direction = \n",
+ " .exchanges = ... # backreference to ComponentExchange - omitted: can be slow to compute\n",
+ " .filtering_criteria = []\n",
+ " .name = 'usr'\n",
+ " .owner = \n",
+ " .parent = \n",
+ " .progress_status = 'NOT_SET'\n",
+ " .property_value_groups = []\n",
+ " .property_values = []\n",
+ " .requirements = []\n",
+ " .summary = None\n",
+ " .traces = []\n",
+ " .uuid = '3a2ff9e0-adcc-4d2d-ae4f-7001a0c25475'\n",
+ " .xtype = 'org.polarsys.capella.core.data.fa:ComponentPort',\n",
+ " Promise(identifier='cm-port-promise'): \n",
+ " .applied_property_value_groups = []\n",
+ " .applied_property_values = []\n",
+ " .constraints = []\n",
+ " .description = ''\n",
+ " .direction = \n",
+ " .exchanges = ... # backreference to ComponentExchange - omitted: can be slow to compute\n",
+ " .filtering_criteria = []\n",
+ " .name = 'cm'\n",
+ " .owner = \n",
+ " .parent = \n",
+ " .progress_status = 'NOT_SET'\n",
+ " .property_value_groups = []\n",
+ " .property_values = []\n",
+ " .requirements = []\n",
+ " .summary = None\n",
+ " .traces = []\n",
+ " .uuid = '99f8db47-4771-4e4e-993a-b252398d8806'\n",
+ " .xtype = 'org.polarsys.capella.core.data.fa:ComponentPort'}"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model_update = f\"\"\"\n",
+ "- parent: !uuid {root_component.uuid}\n",
+ " modify:\n",
+ " name: Coffee Machine\n",
+ "- parent: !uuid {root_component.uuid}\n",
+ " extend:\n",
+ " ports:\n",
+ " - name: usr\n",
+ " direction: INOUT\n",
+ " promise_id: usr-port-promise\n",
+ " exchanges:\n",
+ " - name: user interactions\n",
+ " source: !promise usr-port-promise\n",
+ " target: !promise cm-port-promise\n",
+ "- parent: !uuid {structure.uuid}\n",
+ " extend:\n",
+ " components:\n",
+ " - name: User\n",
+ " is_actor: true\n",
+ " is_human: true\n",
+ " ports:\n",
+ " - name: cm\n",
+ " direction: INOUT\n",
+ " promise_id: cm-port-promise\n",
+ "\"\"\"\n",
+ "# the below line applies the model_update to the model\n",
+ "decl.apply(model, io.StringIO(model_update))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "and now we can verify the changes by visualizing the context of our system under analysis:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "image/svg+xml": [
+ "SF Coffee Machine user interactions User "
+ ],
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "root_component.context_diagram"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Please note: the changes we made are not yet stored - if you like those to be saved you may use `model.save()` method. This will save the model back to where it was loaded from, for example by writing back into local files, or by creating a Git commit and pushing it back to the remote.\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "c5ea7dc634d8047a259e5b898f154d237fbe6934b444b1a949475949608d751e"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_sources/examples/11 Complexity Assessment.ipynb.txt b/_sources/examples/11 Complexity Assessment.ipynb.txt
new file mode 100644
index 000000000..420349bbe
--- /dev/null
+++ b/_sources/examples/11 Complexity Assessment.ipynb.txt
@@ -0,0 +1,120 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Complexity Assessment\n",
+ "\n",
+ "This notebook demonstrates how to use / view the model complexity badge for a Capella model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from IPython.display import SVG, display\n",
+ "import capellambse"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Cannot load PVMT extension: ValueError: Provided model does not have a PropertyValuePkg\n",
+ "Property values are not available in this model\n"
+ ]
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "180 \n",
+ "objects \n",
+ "\n",
+ "\n",
+ "31% \n",
+ "\n",
+ "16% \n",
+ "\n",
+ "27% \n",
+ "\n",
+ "27% \n",
+ " \n",
+ "18 \n",
+ "diagrams \n",
+ "\n",
+ "\n",
+ "39% \n",
+ "\n",
+ "22% \n",
+ "\n",
+ "28% \n",
+ "\n",
+ "11% \n",
+ " \n",
+ "\n",
+ "\n",
+ "Operational Analysis \n",
+ "\n",
+ "System Analysis \n",
+ "\n",
+ "Logical Architecture \n",
+ "\n",
+ "Physical Architecture \n",
+ " \n",
+ " \n",
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "path_to_model = \"../../../tests/data/melodymodel/5_2/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)\n",
+ "SVG(model.description_badge)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "f5c9192943a88c565de58e6fd7c534c9de794a35889e45ad6809ab92c821a96c"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_sources/howtos/howtos.rst.txt b/_sources/howtos/howtos.rst.txt
new file mode 100644
index 000000000..fdef7f6de
--- /dev/null
+++ b/_sources/howtos/howtos.rst.txt
@@ -0,0 +1,21 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+.. _howtos:
+
+*******
+How Tos
+*******
+
+In this section you can view dedicated tutorial-notebooks of key
+features.
+
+
+.. toctree::
+ :maxdepth: 4
+ :caption: How tos:
+ :numbered:
+ :glob:
+
+ ../examples/*
diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt
new file mode 100644
index 000000000..7103e2017
--- /dev/null
+++ b/_sources/index.rst.txt
@@ -0,0 +1,77 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+*****************************
+Welcome to the documentation!
+*****************************
+
+Python Capella MBSE Tools
+=========================
+
+.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
+ :target: https://github.com/psf/black
+ :alt: Black
+
+**Date**: |today| **Version**: |Version|
+
+Description
+-----------
+
+This library was designed to enable and support Model Based System Engineering
+using Polarsys' Capella_ with Python. Common usage for this API:
+
+* parsing .aird files
+* easy access to model elements and objects
+* property-value access and manipulation
+* diagram access and export as SVG
+
+Additionally and as a core idea it provides an interface for the underlying
+database of the Capella model.
+
+Since v0.5, it also supports a simple, but powerful :ref:`declarative modelling
+language `, which is based on the API for the semantic
+model.
+
+If you want a quickstart at how to use this package, head right into the
+:ref:`how-tos section `.
+
+.. toctree::
+ :caption: Start
+ :maxdepth: 1
+ :titlesonly:
+
+ start/installation
+ start/specifying-models
+ start/intro-to-api
+ start/declarative
+ start/audit-events
+
+.. toctree::
+ :caption: Tutorials
+ :titlesonly:
+
+ howtos/howtos
+
+.. toctree::
+ :caption: API reference
+ :maxdepth: 4
+
+ code/modules
+
+.. toctree::
+ :caption: Integration with other tools
+ :maxdepth: 2
+
+ tools/sphinx-extension.rst
+
+.. toctree::
+ :caption: Development
+ :maxdepth: 2
+
+ development/low-level-api
+ development/how-to-explore-capella-mm
+ development/developing-docs
+ development/repl
+
+.. _Capella: https://www.eclipse.org/capella/
diff --git a/_sources/start/audit-events.rst.txt b/_sources/start/audit-events.rst.txt
new file mode 100644
index 000000000..8684e25e2
--- /dev/null
+++ b/_sources/start/audit-events.rst.txt
@@ -0,0 +1,152 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+.. _audit-events:
+
+************
+Audit events
+************
+
+|project| fires :external:py:func:`sys.audit` events for certain calls in the
+high-level API. These events can be inspected by a callable registered with
+:external:py:func:`sys.addaudithook`.
+
+.. warning::
+
+ System audit hooks cannot be removed once they were registered. When storing
+ a reference to a model in an audit hook, make sure that the reference is
+ destroyed properly to avoid unnecessary memory consumption.
+
+Also refer to the :py:class:`capellambse.auditing.AttributeAuditor` for an
+example class that records read access to all attributes in a model using the
+``capellambse.getattr`` audit event.
+
+For programmatic use, a set of all events that signify changes to the model is
+available as the ``events`` class variable on the
+:py:class:`~capellambse.auditing.WriteProtector`.
+
+List of audit events fired by |project|
+=======================================
+
+The following table shows all audit events that are fired by ``capellambse``.
+
+.. note::
+
+ For some calls, multiple events may be fired. For example, a
+ ``capellambse.create`` event is always followed by another event (such as
+ ``capellambse.insert``) when adding the newly created object to the model
+ tree.
+
++--------------------------------+--------------------------------------------+
+| Event | Description |
++================================+============================================+
+| ``capellambse.getattr`` | An attribute is accessed for reading. |
+| | |
+| .. versionadded:: 0.5.11 | **Arguments:** |
+| | |
+| | 1. ``obj``: The object that was accessed. |
+| | 2. ``attr``: The attribute on that object. |
+| | 3. ``value``: The value that is going to |
+| | be returned. Use this to avoid |
+| | recursive loops when inspecting the |
+| | object. |
+| | |
+| | .. note:: |
+| | |
+| | This event will also be fired for |
+| | internal read accesses, for example |
+| | when searching the model for references |
+| | to another object. Currently there is |
+| | no reliable way to distinguish between |
+| | explicit (user) access and these |
+| | internal calls. |
++--------------------------------+--------------------------------------------+
+| ``capellambse.read_attribute`` | Deprecated alias of |
+| | ``capellambse.getattr``. |
+| .. versionadded:: pre-0.5 | |
+| | |
+| .. deprecated:: 0.5.11 | |
+| Use the ``getattr`` event | |
+| instead. | |
++--------------------------------+--------------------------------------------+
+| ``capellambse.setattr`` | An attribute is about to be changed. |
+| | |
+| .. versionadded:: 0.5.11 | **Arguments:** |
+| | |
+| | 1. ``obj``: The object being changed. |
+| | 2. ``attr``: The name of the attribute. |
+| | 3. ``value``: The new value. |
++--------------------------------+--------------------------------------------+
+| ``capellambse.delete`` | An object or a list of objects is about to |
+| | be deleted from the model. |
+| .. versionadded:: 0.5.11 | |
+| | This is also fired when purging left-over |
+| | references while deleting another object. |
+| | |
+| | **Arguments:** |
+| | |
+| | 1. ``parent``: The current parent object. |
+| | 2. ``attr``: The attribute that contains |
+| | the object to be deleted. |
+| | 3. ``index``: If a single object from a |
+| | list is being deleted, contains the |
+| | index of that object into the list. If |
+| | the entire attribute is deleted (in the |
+| | case of lists: the list is emptied), |
+| | contains ``None``. |
++--------------------------------+--------------------------------------------+
+| ``capellambse.insert`` | An item is about to be inserted into a |
+| | coupled ``ElementList``. |
+| .. versionadded:: 0.5.11 | |
+| | **Arguments:** |
+| | |
+| | 1. ``parent``: The object being changed. |
+| | 2. ``attr``: The attribute that contains |
+| | this list. |
+| | 3. ``index``: The index into the list to |
+| | insert into. May be ``len(the_list)`` |
+| | (or greater) to signify appending to |
+| | the end. |
+| | 4. ``value``: The value being inserted. |
++--------------------------------+--------------------------------------------+
+| ``capellambse.create`` | A new object was just created, but is not |
+| | yet part of the model. |
+| .. versionadded:: 0.5.11 | |
+| | **Arguments:** |
+| | |
+| | 1. ``parent``: The new parent object. |
+| | 2. ``attr``: The attribute that contains |
+| | this list. |
+| | 3. ``index``: The index into the list to |
+| | insert into. May be ``len(the_list)`` |
+| | (or greater) to signify appending to |
+| | the end. |
+| | 4. ``value``: The newly created object. |
++--------------------------------+--------------------------------------------+
+
+Implementation notes
+====================
+
+Audit events are generally fired from these locations:
+
+1. Read access events (i.e. ``capellambse.getattr``) are fired by each Accessor
+ subclass, just before returning the final value from ``__get__()``.
+
+2. Events that signify modifications to a list are fired by the overridden
+ methods in ``CoupledElementListMixin`` (include ``create``), as well as by
+ ``__setattr__()`` of ``GenericElement``, before passing the values on to the
+ actual accessor implementation.
+
+3. The ``capellambse.delete`` event for deleting an entire attribute (i.e. the
+ case where the ``index`` argument is ``None``) is fired by the relevant
+ Accessor's ``__delete__()`` method.
+
+ Note that for lists, Accessors may instead fire individual ``delete`` events
+ for each list item.
+
+In order to prevent audit events from being fired for elements that are still
+under construction, ``GenericElement`` keeps track of the construction state in
+the ``_constructed`` attribute. It becomes True when construction is finished
+and audit events may be fired. Accessors must not fire any audit events if the
+object they're acting on has not been fully constructed.
diff --git a/_sources/start/declarative.rst.txt b/_sources/start/declarative.rst.txt
new file mode 100644
index 000000000..c428248e6
--- /dev/null
+++ b/_sources/start/declarative.rst.txt
@@ -0,0 +1,349 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+.. _declarative-modelling:
+
+*********************
+Declarative modelling
+*********************
+
+.. versionadded:: 0.5.0
+ Introduced the declarative modelling module.
+
+|project| supports declarative modelling with the :py:mod:`capellambse.decl`
+module. This requires the optional dependency ``capellambse[decl]`` to be
+installed.
+
+The YAML-based declarative modelling engine combines a few simple concepts into
+a powerful, but easy to use file format. These files can then be applied to any
+model supported by |project|.
+
+Example
+=======
+
+Here is an example YAML file that declares a simple coffee machine with a
+couple of functions, and functional exchanges between them:
+
+.. literalinclude:: ../../../tests/data/decl/coffee-machine.yml
+ :language: yaml
+ :lines: 4-
+ :lineno-start: 1
+ :linenos:
+
+CLI usage
+---------
+
+If the additional optional dependency ``capellambse[decl,cli]`` is installed,
+this file can be applied from the command line. Assuming it is saved as
+``coffee-machine.yml``, it can then be applied to a locally stored Capella
+model like this:
+
+.. code-block:: sh
+
+ python -m capellambse.decl --model path/to/model.aird coffee-machine.yml
+
+Refer to the :py:func:`capellambse.cli_helpers.loadcli` documentation to find
+out the supported argument format for ``--model``.
+
+API usage
+---------
+
+Declarative YAML can also be applied programmatically, by calling the
+:py:func:`capellambse.decl.apply` function. It takes a (loaded) |project|
+model, and either a path to a file or a file-like object. To pass in a string
+containing YAML, wrap it in :external:class:`io.StringIO`:
+
+.. code-block:: python
+ :emphasize-lines: 5
+
+ import io, capellambse.decl
+ my_model = capellambse.MelodyModel(...)
+ my_yaml = "..."
+
+ capellambse.decl.apply(my_model, io.StringIO(my_yaml))
+
+ my_model.save()
+
+Format description
+==================
+
+The expected YAML follows a simple format, where a parent object (i.e. an
+object that already exists in the model) is selected, and one or more of three
+different operations is applied to it:
+
+- ``extend``-ing the object on list attributes,
+- ``set``-ting properties on the object itself,
+- ``sync``-ing objects into the model, or
+- ``delete``-ing one or more children.
+
+Selecting a parent
+------------------
+
+There are a few ways to select a parent object from the model.
+
+The most straight-forward way is to use the universally unique ID (UUID), using
+the ``!uuid`` YAML tag. The following query selects the root logical function
+in our test model:
+
+.. code-block:: yaml
+
+ - parent: !uuid f28ec0f8-f3b3-43a0-8af7-79f194b29a2d
+
+A more versatile way involves the ``!find`` YAML tag, which allows specifying a
+set of attributes in order to filter down to a single model element. This tag
+simply takes a mapping of all the attributes to select for. This usually also
+involves the element's type (or class), which is selectable with the ``_type``
+attribute:
+
+.. code-block:: yaml
+
+ - parent: !find
+ _type: LogicalFunction
+ # ^-- note the leading underscore, to disambiguate from the "type"
+ # property that exists on some model elements
+ name: Root Logical Function
+ set: [...]
+
+The ``!find`` tag also supports dot-notation for filtering on nested
+attributes.
+
+.. code-block:: yaml
+
+ - parent: !find
+ _type: FunctionOutputPort
+ name: FOP 1
+ owner.name: manage the school
+ set: [...]
+
+Extending objects
+-----------------
+
+The following subsections show how to create completely new objects, or
+reference and move already existing ones, using examples of declarative YAML
+files on
+:py:class:`~capellambse.model.common.accessors.ElementListCouplingMixin`-ish
+attributes. The extension of one-to-one attributes works in the same way,
+adhering to the YAML syntax.
+
+Creating new objects
+^^^^^^^^^^^^^^^^^^^^
+
+:py:class:`~capellambse.model.layers.la.LogicalFunction` objects have several
+different attributes which can be modified from a declarative YAML file. For
+example, it is possible to create new
+sub-:py:attr:`~capellambse.model.layers.la.LogicalFunction.functions`. This
+snippet creates a function with the name "brew coffee" directly below the root
+function:
+
+.. code-block:: yaml
+ :emphasize-lines: 2
+
+ - parent: !uuid f28ec0f8-f3b3-43a0-8af7-79f194b29a2d
+ extend:
+ functions:
+ - name: brew coffee
+
+Functions can be nested arbitrarily deeply, and can also receive any other
+supported attributes at the same time. The "brew coffee" function for example
+could further receive nested child functions, each providing an output port:
+
+.. code-block:: yaml
+ :emphasize-lines: 4-5
+
+ - parent: !uuid f28ec0f8-f3b3-43a0-8af7-79f194b29a2d
+ extend:
+ functions:
+ - name: brew coffee
+ functions:
+ - name: grind beans
+ outputs:
+ - name: Ground Beans port
+ - name: heat water
+ outputs:
+ - name: Hot Water port
+
+While objects that already exist in the base model can be referenced with
+``!uuid``, this is not possible for objects declared by the YAML file, as they
+will have a random UUID assigned to ensure uniqueness. For this reason, a
+promise mechanic exists, which allows to "tag" any declared object with a
+``promise_id``, and later reference that object with the ``!promise`` YAML tag.
+These promise IDs are user defined strings. The only requirement is that two
+objects cannot receive the same ID, however they can be referenced any number
+of times. This example snippet demonstrates how to declare two logical
+functions, which communicate through a functional exchange:
+
+.. code-block:: yaml
+ :emphasize-lines: 7,11,14-15
+
+ - parent: !uuid f28ec0f8-f3b3-43a0-8af7-79f194b29a2d
+ extend:
+ functions:
+ - name: brew coffee
+ inputs:
+ - name: Steam port
+ promise_id: steam-input
+ - name: produce steam
+ outputs:
+ - name: Steam port
+ promise_id: steam-output
+ exchanges:
+ - name: Steam
+ source: !promise steam-output
+ target: !promise steam-input
+
+The ``!promise`` tag (and the ``!uuid`` tag as well) can be used anywhere where
+a model object is expected.
+
+Creating new references
+^^^^^^^^^^^^^^^^^^^^^^^
+
+It is important to understand when new model objects are created and when only
+references are added. The following example would create a reference in the
+``.allocated_functions`` attribute of the
+:py:class:`~capellambse.model.layers.la.LogicalComponent` which is also the
+logical ``root_component`` (parent) to the logical ``root_function``:
+
+.. code-block:: yaml
+ :emphasize-lines: 2
+
+ - parent: !uuid 0d2edb8f-fa34-4e73-89ec-fb9a63001440
+ extend:
+ allocated_functions:
+ - !uuid f28ec0f8-f3b3-43a0-8af7-79f194b29a2d
+
+This is caused by the type of relationship (non-
+:py:class:`~capellambse.model.common.accessors.DirectProxyAccessor`) between
+the parent and its ``allocated_functions``.
+
+It is also possible to create references to promised objects, but extra caution
+for declaring ``promise_id``\ s for resolving these promises successfully:
+
+.. code-block:: yaml
+ :emphasize-lines: 5,9
+
+ - parent: !uuid f28ec0f8-f3b3-43a0-8af7-79f194b29a2d
+ extend:
+ functions:
+ - name: The promised one
+ promise_id: promised-fnc
+ - parent: !uuid 0d2edb8f-fa34-4e73-89ec-fb9a63001440
+ extend:
+ functions:
+ - !promise promised-fnc
+
+The ``promise_id`` declaration can also happen after referencing it.
+
+Moving objects
+^^^^^^^^^^^^^^
+
+The following example would move a logical function from underneath a
+:py:class:`~capellambse.model.layers.la.LogicalFunctionPkg` (accessible via
+``functions``) into ``functions`` of the logical ``root_function`` (parent)
+since the ``functions`` attribute has a parent/children relationship (i.e. the
+:py:class:`~capellambse.model.common.accessors.DirectProxyAccessor` is used).
+
+.. code-block:: yaml
+
+ - parent: !uuid f28ec0f8-f3b3-43a0-8af7-79f194b29a2d
+ extend:
+ functions:
+ - !uuid 8833d2dc-b862-4a50-b26c-6f7e0f17faef
+
+Setting properties
+------------------
+
+After selecting a parent, it is also possible to directly change its properties
+without introducing new objects into the model. This happens by specifying the
+attributes in the ``set:`` key.
+
+The following example would change the ``name`` of the root
+:py:class:`~capellambse.model.layers.la.LogicalComponent` to "Coffee Machine"
+(notice how we use a different UUID than before):
+
+.. code-block:: yaml
+ :emphasize-lines: 2
+
+ - parent: !uuid 0d2edb8f-fa34-4e73-89ec-fb9a63001440
+ set:
+ name: Coffee Machine
+
+This is not limited to string attributes; it is just as well possible to change
+e.g. numeric properties. This example changes the ``min_card`` property of an
+:py:class:`~capellambse.model.crosslayer.information.ExchangeItemElement` to
+``0`` and the ``max_card`` to infinity, effectively removing both limitations:
+
+.. code-block:: yaml
+ :emphasize-lines: 3-
+
+ - parent: !uuid 81b87fcc-03cf-434b-ad5b-ef18266c5a3e
+ set:
+ min_card: 0
+ max_card: .inf
+
+Synchronizing objects
+---------------------
+
+The ``sync:`` key is a combination of the above ``extend:`` and ``set:`` keys.
+Using it, it is possible to modify objects that already exist, or create new
+objects if they don't exist yet.
+
+Unlike the other keys however, ``sync:`` takes two sets of attributs: one that
+is used to find a matching object (using the ``find:`` key), and one that is
+only used to set values once the object of interest was found (using the
+``set:`` key).
+
+This operation also supports Promise IDs, which are resolved either using the
+found existing object or the newly created one.
+
+The following snippet ensures that the root LogicalFunction contains a
+subfunction "brew coffee" with the given description. A function named "brew
+coffee" will be used if it already exists, but if not, a new one will be
+created. In either case, the used function will resolve the "brew-coffee"
+promise, which can be used to reference it elsewhere:
+
+.. code-block:: yaml
+
+ - parent: !uuid f28ec0f8-f3b3-43a0-8af7-79f194b29a2d # the root function
+ sync:
+ functions:
+ - find:
+ name: brew coffee
+ set:
+ description: This function brews coffee.
+ promise_id: brew-coffee
+ - parent: !uuid 0d2edb8f-fa34-4e73-89ec-fb9a63001440 # the root component
+ extend:
+ allocated_functions:
+ - !promise brew-coffee
+
+Deleting objects
+----------------
+
+Finally, with declarative modelling files, it is possible to delete objects
+from the model. Depending on where the delete operation occurs, either the
+target object is deleted entirely, or only the link to it is destroyed.
+
+Currently, objects to be deleted can only be selected by their UUID.
+
+For example, this snippet deletes the logical function named "produce Great
+Wizards" from the model:
+
+.. code-block:: yaml
+ :emphasize-lines: 3
+
+ - parent: !uuid f28ec0f8-f3b3-43a0-8af7-79f194b29a2d
+ delete:
+ functions:
+ - !uuid 0e71a0d3-0a18-4671-bba0-71b5f88f95dd
+
+In contrast, this snippet only removes its allocation to the "Hogwarts" root
+component, but the function still exists afterwards:
+
+.. code-block:: yaml
+ :emphasize-lines: 3
+
+ - parent: !uuid 0d2edb8f-fa34-4e73-89ec-fb9a63001440
+ delete:
+ allocated_functions:
+ - !uuid 0e71a0d3-0a18-4671-bba0-71b5f88f95dd
diff --git a/_sources/start/installation.rst.txt b/_sources/start/installation.rst.txt
new file mode 100644
index 000000000..b1da8a644
--- /dev/null
+++ b/_sources/start/installation.rst.txt
@@ -0,0 +1,65 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+************
+Installation
+************
+
+.. image:: https://img.shields.io/pypi/pyversions/capellambse
+ :target: https://pypi.org/project/capellambse/
+ :alt: PyPI - Python Version
+
+This guide helps you to get |project| installed. There are a few ways to get it
+done:
+
+Install from PyPI
+=================
+
+Installing |project| from Python Package Index via pip__ is the quickest way to
+get started.
+
+__ http://www.pip-installer.org/
+
+.. code:: bash
+
+ pip install capellambse
+
+Windows
+=======
+
+If you intend to use |project|'s PNG export functionality, you need a working
+installation of cairosvg__. Unfortunately, the Windows wheels on PyPI do not
+ship with all necessary libraries. However, they can be manually installed with
+the `GTK for Windows Runtime Environment Installer`__.
+
+__ https://pypi.org/project/CairoSVG/
+__ https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases
+
+This should give you a fully functioning |project|.
+
+Install as a package from Github
+================================
+
+If you want to have a comfortable playground with examples / Jupyter notebooks
+/ export to excel demo and test models you may clone the repository directly
+from Github, create a virtual environment and install all the extras:
+
+.. code-block:: bash
+
+ git clone https://github.com/DSD-DBS/py-capellambse.git
+ cd py-capellambse
+ python3 -m venv .venv
+ source .venv/bin/activate
+ pip install .
+ pip install jupyter
+ cd examples
+ jupyter-notebook
+
+Install for development
+=======================
+
+In case you'd like to contribute to the development or improve documentation,
+sample models or examples collection please follow the `contribution guide`__.
+
+__ https://github.com/DSD-DBS/py-capellambse/blob/master/CONTRIBUTING.md
diff --git a/_sources/start/intro-to-api.rst.txt b/_sources/start/intro-to-api.rst.txt
new file mode 100644
index 000000000..743825664
--- /dev/null
+++ b/_sources/start/intro-to-api.rst.txt
@@ -0,0 +1,63 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+**********************************
+Introduction to py-capellambse API
+**********************************
+
+|project| provides access to model elements using a meta-model similar to the
+one of Capella. However in this meta-model we make a few simplifications. A
+collection of automated tests and design reviews help us to ensure that those
+simplifications don't break compatibility with original Capella models (however
+coverage isn't complete yet).
+
+As you may know the meta-model behind Capella is layered. There are many
+packages involved and there is a long inheritance chain behind almost every
+model element. We are simplifying that by "flattening" the lower layers.
+
+You may see an example of how that works in the figure below:
+
+.. image:: ../_static/img/crosslayer_intro.jpg
+
+In the example above we see that `LogicalFunction` is a subtype of
+`AbstractFunction`, just like `SystemFunction` or `OperationalActivity`.
+Because of that, all of those subtypes can be `.available_in_states` or have a
+layer-specific structural `owner`, like `LogicalComponent` for
+`LogicalFunction`. Any layer-specific class that inherits from `Component` may
+also have `state_machines`.
+
+The API reference part of this documentation provides you with the complete (as
+it is generated from the code base) list of available methods and attributes.
+
+Layer-specific packages
+=======================
+
+The following packages enable working with model layers:
+
+* :mod:`capellambse.model.layers.oa` - covers Operational Analysis layer.
+* :mod:`capellambse.model.layers.ctx` - covers System Analysis layer.
+* :mod:`capellambse.model.layers.la` - covers Logical Architecture layer.
+* :mod:`capellambse.model.layers.pa` - covers Physical Architecture layer.
+
+Cross-layer packages
+====================
+
+The following packages enable all (almost) of the layer packages:
+
+* :mod:`capellambse.model.crosslayer.fa` - covers Functional Analysis concerns,
+ defines things like AbstractFunction or FunctionalExchange
+* :mod:`capellambse.model.crosslayer.cs` - covers Composite Structure concerns,
+ defines things like Component
+* :mod:`capellambse.model.crosslayer.capellacommon` - covers common concerns,
+ defines things like StateMachine, State
+* :mod:`capellambse.model.crosslayer.information` - covers Information
+ concerns, defines things like Class, DataPkg, ExchangeItem
+
+Extension packages
+==================
+
+* :mod:`capellambse.extensions.reqif` - provides means for working with ReqIF
+ Requirements within Capella model.
+* :mod:`capellambse.extensions.pvmt` - provides means for working with object
+ attributes created with PVMT package.
diff --git a/_sources/start/specifying-models.rst.txt b/_sources/start/specifying-models.rst.txt
new file mode 100644
index 000000000..a9e8762cd
--- /dev/null
+++ b/_sources/start/specifying-models.rst.txt
@@ -0,0 +1,163 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+.. specifying-models:
+
+*****************
+Specifying models
+*****************
+
+.. currentmodule:: capellambse.cli_helpers
+
+|project| and tools using it generally support multiple ways of specifying a
+model to load and use. Which way to use depends on the specific situation. This
+page lists all the ways that are commonly supported.
+
+Simple paths
+============
+
+A model can be specified by the path to its main ``*.aird`` file.
+
+.. code:: text
+
+ /home/username/models/coffee-machine/coffee-machine.aird
+ C:\Capella\workspace\coffee-machine\coffee-machine.aird
+ ./model/model.aird
+ model.aird
+
+This is equivalent to specifying the *path* and *entrypoint* arguments to the
+:class:`~capellambse.model.MelodyModel` constructor, e.g.:
+
+.. code:: python
+
+ model = capellambse.MelodyModel(
+ path="/home/username/models/coffee-machine",
+ entrypoint="coffee-machine.aird",
+ )
+
+Just like how the *entrypoint* argument is optional if there is only one
+``*.aird`` file in the given *path*, the file name here may be omitted in this
+case as well:
+
+.. code:: text
+
+ /home/username/models/coffee-machine/
+ C:\Capella\workspace\coffee-machine
+ ./model
+ .
+
+Make sure to escape any special characters such as whitespace or backslashes
+when specifying paths on the command line.
+
+Remote URLs
+===========
+
+Models can also be loaded from various remote locations by specifying a URL in
+the form of ``protocol://host.name/path/to/model.aird``. Out of the box,
+|project| supports the following protocols:
+
+- :class:`file:///local/folder
+ `
+- :class:`git://host.name/repo.git
+ ` and variants, like:
+ ``git+https://host.name/repo``, ``git@host.name:repo``
+- :class:`http:// and https:// `,
+ example: ``https://host.name/path/%s?param=arg``
+- :class:`zip://, zip+https:// etc.
+ `, examples:
+ ``zip:///local/file.zip``, ``zip+https://host.name/remote/file.zip``,
+ ``zip+https://host.name/remote/%s?param=arg!file.zip``
+
+Click on a protocol to get to the detailed documentation including supported
+additional arguments, which can be passed in using JSON (see below).
+
+JSON
+====
+
+For more complex cases, like remote models that require credentials, it is
+possible to pass a JSON-encoded dictionary. This dictionary can contain any key
+that the :class:`~capellambse.model.MelodyModel` constructor and the underlying
+:class:`~capellambse.filehandler.FileHandler` understands.
+
+Note that, when passing such JSON as command line argument, it is necessary to
+escape the whole JSON string to prevent the Shell from interpreting it,
+removing quotes, replacing variables, etc. In bash-like shells, this is usually
+accomplished by wrapping it in single quotes, like this:
+
+.. code:: bash
+
+ python -m capellambse.repl '{"path": "git@example.com:demo-model.git", "revision": "dev", ...}'
+
+.. known-models:
+
+Known models
+============
+
+A model can be given a short name by placing a JSON file in the user's
+'known_models' folder. This is the exact same JSON as described above, just put
+into a file instead of passed as string.
+
+Run the following command to find out where to put the files:
+
+.. code:: bash
+
+ python -m capellambse.cli_helpers
+
+This will show the folder for custom 'known_models' files, and list the names
+of all files found in either the custom or built-in folder. These names can
+then be passed to any CLI command in place of the full model definition.
+
+For example, to start a capellambse REPL using the built-in "coffee-machine"
+model definition, you can run:
+
+.. code:: bash
+
+ python -m capellambse.repl coffee-machine
+
+The most common keys to use include ``path`` and ``entrypoint``, as well as
+credential-related keys like ``username``, ``password`` or ``identity_file``.
+Refer to the documentation of :class:`~capellambse.model.MelodyModel`, as well
+as the respective FileHandler class you want to use for more details:
+
+- For local file paths:
+ :class:`~capellambse.filehandler.local.LocalFileHandler`
+- For Git repositories: :class:`~capellambse.filehandler.git.GitFileHandler`
+- For simple HTTP/HTTPS servers, optionally using HTTP Basic Authentication:
+ :class:`~capellambse.filehandler.http.HTTPFileHandler`
+- For the Gitlab Artifacts service:
+ :class:`~capellambse.filehandler.gitlab_artifacts.GitlabArtifactsFiles`
+
+CLI support
+===========
+
+In order to make it easy to support model loading from the CLI, |project|
+exposes a few functions and classes in the :mod:`capellambse.cli_helpers`
+module.
+
+Standalone functions
+--------------------
+
+These functions help with loading a model from arbitrary user-supplied strings,
+such as command line arguments.
+
+.. autofunction:: loadinfo
+ :noindex:
+
+.. autofunction:: loadcli
+ :noindex:
+
+.. autofunction:: enumerate_known_models
+ :noindex:
+
+Click parameter types
+---------------------
+
+There are also Click parameter types available that encapsulate the
+``loadinfo`` and ``loadcli`` functions, respectively:
+
+.. autoclass:: ModelInfoCLI
+ :noindex:
+
+.. autoclass:: ModelCLI
+ :noindex:
diff --git a/_sources/tools/sphinx-extension.rst.txt b/_sources/tools/sphinx-extension.rst.txt
new file mode 100644
index 000000000..46a68c875
--- /dev/null
+++ b/_sources/tools/sphinx-extension.rst.txt
@@ -0,0 +1,8 @@
+..
+ SPDX-FileCopyrightText: Copyright DB InfraGO AG
+ SPDX-License-Identifier: Apache-2.0
+
+The |project| Sphinx extension
+==============================
+
+.. automodule:: capellambse.sphinx
diff --git a/_static/basic.css b/_static/basic.css
new file mode 100644
index 000000000..30fee9d0f
--- /dev/null
+++ b/_static/basic.css
@@ -0,0 +1,925 @@
+/*
+ * basic.css
+ * ~~~~~~~~~
+ *
+ * Sphinx stylesheet -- basic theme.
+ *
+ * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+ clear: both;
+}
+
+div.section::after {
+ display: block;
+ content: '';
+ clear: left;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+ width: 100%;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+ word-wrap: break-word;
+ overflow-wrap : break-word;
+}
+
+div.sphinxsidebar ul {
+ list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+div.sphinxsidebar #searchbox form.search {
+ overflow: hidden;
+}
+
+div.sphinxsidebar #searchbox input[type="text"] {
+ float: left;
+ width: 80%;
+ padding: 0.25em;
+ box-sizing: border-box;
+}
+
+div.sphinxsidebar #searchbox input[type="submit"] {
+ float: left;
+ width: 20%;
+ border-left: none;
+ padding: 0.25em;
+ box-sizing: border-box;
+}
+
+
+img {
+ border: 0;
+ max-width: 100%;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li p.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ width: 90%;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable {
+ width: 100%;
+}
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable ul {
+ margin-top: 0;
+ margin-bottom: 0;
+ list-style-type: none;
+}
+
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+div.modindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+div.genindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+/* -- domain module index --------------------------------------------------- */
+
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+div.body {
+ min-width: 360px;
+ max-width: 800px;
+}
+
+div.body p, div.body dd, div.body li, div.body blockquote {
+ -moz-hyphens: auto;
+ -ms-hyphens: auto;
+ -webkit-hyphens: auto;
+ hyphens: auto;
+}
+
+a.headerlink {
+ visibility: hidden;
+}
+
+a:visited {
+ color: #551A8B;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink,
+caption:hover > a.headerlink,
+p.caption:hover > a.headerlink,
+div.code-block-caption:hover > a.headerlink {
+ visibility: visible;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+img.align-left, figure.align-left, .figure.align-left, object.align-left {
+ clear: left;
+ float: left;
+ margin-right: 1em;
+}
+
+img.align-right, figure.align-right, .figure.align-right, object.align-right {
+ clear: right;
+ float: right;
+ margin-left: 1em;
+}
+
+img.align-center, figure.align-center, .figure.align-center, object.align-center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+img.align-default, figure.align-default, .figure.align-default {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.align-left {
+ text-align: left;
+}
+
+.align-center {
+ text-align: center;
+}
+
+.align-default {
+ text-align: center;
+}
+
+.align-right {
+ text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar,
+aside.sidebar {
+ margin: 0 0 0.5em 1em;
+ border: 1px solid #ddb;
+ padding: 7px;
+ background-color: #ffe;
+ width: 40%;
+ float: right;
+ clear: right;
+ overflow-x: auto;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+}
+
+nav.contents,
+aside.topic,
+div.admonition, div.topic, blockquote {
+ clear: left;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+nav.contents,
+aside.topic,
+div.topic {
+ border: 1px solid #ccc;
+ padding: 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+/* -- content of sidebars/topics/admonitions -------------------------------- */
+
+div.sidebar > :last-child,
+aside.sidebar > :last-child,
+nav.contents > :last-child,
+aside.topic > :last-child,
+div.topic > :last-child,
+div.admonition > :last-child {
+ margin-bottom: 0;
+}
+
+div.sidebar::after,
+aside.sidebar::after,
+nav.contents::after,
+aside.topic::after,
+div.topic::after,
+div.admonition::after,
+blockquote::after {
+ display: block;
+ content: '';
+ clear: both;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ border: 0;
+ border-collapse: collapse;
+}
+
+table.align-center {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table.align-default {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table caption span.caption-number {
+ font-style: italic;
+}
+
+table caption span.caption-text {
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 5px;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px;
+}
+
+table.citation td {
+ border-bottom: none;
+}
+
+th > :first-child,
+td > :first-child {
+ margin-top: 0px;
+}
+
+th > :last-child,
+td > :last-child {
+ margin-bottom: 0px;
+}
+
+/* -- figures --------------------------------------------------------------- */
+
+div.figure, figure {
+ margin: 0.5em;
+ padding: 0.5em;
+}
+
+div.figure p.caption, figcaption {
+ padding: 0.3em;
+}
+
+div.figure p.caption span.caption-number,
+figcaption span.caption-number {
+ font-style: italic;
+}
+
+div.figure p.caption span.caption-text,
+figcaption span.caption-text {
+}
+
+/* -- field list styles ----------------------------------------------------- */
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+.field-name {
+ -moz-hyphens: manual;
+ -ms-hyphens: manual;
+ -webkit-hyphens: manual;
+ hyphens: manual;
+}
+
+/* -- hlist styles ---------------------------------------------------------- */
+
+table.hlist {
+ margin: 1em 0;
+}
+
+table.hlist td {
+ vertical-align: top;
+}
+
+/* -- object description styles --------------------------------------------- */
+
+.sig {
+ font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
+}
+
+.sig-name, code.descname {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+.sig-name {
+ font-size: 1.1em;
+}
+
+code.descname {
+ font-size: 1.2em;
+}
+
+.sig-prename, code.descclassname {
+ background-color: transparent;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.sig-paren {
+ font-size: larger;
+}
+
+.sig-param.n {
+ font-style: italic;
+}
+
+/* C++ specific styling */
+
+.sig-inline.c-texpr,
+.sig-inline.cpp-texpr {
+ font-family: unset;
+}
+
+.sig.c .k, .sig.c .kt,
+.sig.cpp .k, .sig.cpp .kt {
+ color: #0033B3;
+}
+
+.sig.c .m,
+.sig.cpp .m {
+ color: #1750EB;
+}
+
+.sig.c .s, .sig.c .sc,
+.sig.cpp .s, .sig.cpp .sc {
+ color: #067D17;
+}
+
+
+/* -- other body styles ----------------------------------------------------- */
+
+ol.arabic {
+ list-style: decimal;
+}
+
+ol.loweralpha {
+ list-style: lower-alpha;
+}
+
+ol.upperalpha {
+ list-style: upper-alpha;
+}
+
+ol.lowerroman {
+ list-style: lower-roman;
+}
+
+ol.upperroman {
+ list-style: upper-roman;
+}
+
+:not(li) > ol > li:first-child > :first-child,
+:not(li) > ul > li:first-child > :first-child {
+ margin-top: 0px;
+}
+
+:not(li) > ol > li:last-child > :last-child,
+:not(li) > ul > li:last-child > :last-child {
+ margin-bottom: 0px;
+}
+
+ol.simple ol p,
+ol.simple ul p,
+ul.simple ol p,
+ul.simple ul p {
+ margin-top: 0;
+}
+
+ol.simple > li:not(:first-child) > p,
+ul.simple > li:not(:first-child) > p {
+ margin-top: 0;
+}
+
+ol.simple p,
+ul.simple p {
+ margin-bottom: 0;
+}
+
+aside.footnote > span,
+div.citation > span {
+ float: left;
+}
+aside.footnote > span:last-of-type,
+div.citation > span:last-of-type {
+ padding-right: 0.5em;
+}
+aside.footnote > p {
+ margin-left: 2em;
+}
+div.citation > p {
+ margin-left: 4em;
+}
+aside.footnote > p:last-of-type,
+div.citation > p:last-of-type {
+ margin-bottom: 0em;
+}
+aside.footnote > p:last-of-type:after,
+div.citation > p:last-of-type:after {
+ content: "";
+ clear: both;
+}
+
+dl.field-list {
+ display: grid;
+ grid-template-columns: fit-content(30%) auto;
+}
+
+dl.field-list > dt {
+ font-weight: bold;
+ word-break: break-word;
+ padding-left: 0.5em;
+ padding-right: 5px;
+}
+
+dl.field-list > dd {
+ padding-left: 0.5em;
+ margin-top: 0em;
+ margin-left: 0em;
+ margin-bottom: 0em;
+}
+
+dl {
+ margin-bottom: 15px;
+}
+
+dd > :first-child {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+.sig dd {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+.sig dl {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+dl > dd:last-child,
+dl > dd:last-child > :last-child {
+ margin-bottom: 0;
+}
+
+dt:target, span.highlighted {
+ background-color: #fbe54e;
+}
+
+rect.highlighted {
+ fill: #fbe54e;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+.footnote:target {
+ background-color: #ffa;
+}
+
+.line-block {
+ display: block;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.line-block .line-block {
+ margin-top: 0;
+ margin-bottom: 0;
+ margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+ font-family: sans-serif;
+}
+
+.accelerator {
+ text-decoration: underline;
+}
+
+.classifier {
+ font-style: oblique;
+}
+
+.classifier:before {
+ font-style: normal;
+ margin: 0 0.5em;
+ content: ":";
+ display: inline-block;
+}
+
+abbr, acronym {
+ border-bottom: dotted 1px;
+ cursor: help;
+}
+
+.translated {
+ background-color: rgba(207, 255, 207, 0.2)
+}
+
+.untranslated {
+ background-color: rgba(255, 207, 207, 0.2)
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+ overflow: auto;
+ overflow-y: hidden; /* fixes display issues on Chrome browsers */
+}
+
+pre, div[class*="highlight-"] {
+ clear: both;
+}
+
+span.pre {
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ -webkit-hyphens: none;
+ hyphens: none;
+ white-space: nowrap;
+}
+
+div[class*="highlight-"] {
+ margin: 1em 0;
+}
+
+td.linenos pre {
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ display: block;
+}
+
+table.highlighttable tbody {
+ display: block;
+}
+
+table.highlighttable tr {
+ display: flex;
+}
+
+table.highlighttable td {
+ margin: 0;
+ padding: 0;
+}
+
+table.highlighttable td.linenos {
+ padding-right: 0.5em;
+}
+
+table.highlighttable td.code {
+ flex: 1;
+ overflow: hidden;
+}
+
+.highlight .hll {
+ display: block;
+}
+
+div.highlight pre,
+table.highlighttable pre {
+ margin: 0;
+}
+
+div.code-block-caption + div {
+ margin-top: 0;
+}
+
+div.code-block-caption {
+ margin-top: 1em;
+ padding: 2px 5px;
+ font-size: small;
+}
+
+div.code-block-caption code {
+ background-color: transparent;
+}
+
+table.highlighttable td.linenos,
+span.linenos,
+div.highlight span.gp { /* gp: Generic.Prompt */
+ user-select: none;
+ -webkit-user-select: text; /* Safari fallback only */
+ -webkit-user-select: none; /* Chrome/Safari */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* IE10+ */
+}
+
+div.code-block-caption span.caption-number {
+ padding: 0.1em 0.3em;
+ font-style: italic;
+}
+
+div.code-block-caption span.caption-text {
+}
+
+div.literal-block-wrapper {
+ margin: 1em 0;
+}
+
+code.xref, a code {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
+ background-color: transparent;
+}
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+ margin: -1px -10px;
+ padding: 0 10px;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+ vertical-align: middle;
+}
+
+div.body div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+span.eqno a.headerlink {
+ position: absolute;
+ z-index: 1;
+}
+
+div.math:hover a.headerlink {
+ visibility: visible;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0 !important;
+ width: 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ #top-link {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/_static/debug.css b/_static/debug.css
new file mode 100644
index 000000000..74d4aec33
--- /dev/null
+++ b/_static/debug.css
@@ -0,0 +1,69 @@
+/*
+ This CSS file should be overridden by the theme authors. It's
+ meant for debugging and developing the skeleton that this theme provides.
+*/
+body {
+ font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
+ "Apple Color Emoji", "Segoe UI Emoji";
+ background: lavender;
+}
+.sb-announcement {
+ background: rgb(131, 131, 131);
+}
+.sb-announcement__inner {
+ background: black;
+ color: white;
+}
+.sb-header {
+ background: lightskyblue;
+}
+.sb-header__inner {
+ background: royalblue;
+ color: white;
+}
+.sb-header-secondary {
+ background: lightcyan;
+}
+.sb-header-secondary__inner {
+ background: cornflowerblue;
+ color: white;
+}
+.sb-sidebar-primary {
+ background: lightgreen;
+}
+.sb-main {
+ background: blanchedalmond;
+}
+.sb-main__inner {
+ background: antiquewhite;
+}
+.sb-header-article {
+ background: lightsteelblue;
+}
+.sb-article-container {
+ background: snow;
+}
+.sb-article-main {
+ background: white;
+}
+.sb-footer-article {
+ background: lightpink;
+}
+.sb-sidebar-secondary {
+ background: lightgoldenrodyellow;
+}
+.sb-footer-content {
+ background: plum;
+}
+.sb-footer-content__inner {
+ background: palevioletred;
+}
+.sb-footer {
+ background: pink;
+}
+.sb-footer__inner {
+ background: salmon;
+}
+.sb-article {
+ background: white;
+}
diff --git a/_static/doctools.js b/_static/doctools.js
new file mode 100644
index 000000000..d06a71d75
--- /dev/null
+++ b/_static/doctools.js
@@ -0,0 +1,156 @@
+/*
+ * doctools.js
+ * ~~~~~~~~~~~
+ *
+ * Base JavaScript utilities for all Sphinx HTML documentation.
+ *
+ * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+"use strict";
+
+const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([
+ "TEXTAREA",
+ "INPUT",
+ "SELECT",
+ "BUTTON",
+]);
+
+const _ready = (callback) => {
+ if (document.readyState !== "loading") {
+ callback();
+ } else {
+ document.addEventListener("DOMContentLoaded", callback);
+ }
+};
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+const Documentation = {
+ init: () => {
+ Documentation.initDomainIndexTable();
+ Documentation.initOnKeyListeners();
+ },
+
+ /**
+ * i18n support
+ */
+ TRANSLATIONS: {},
+ PLURAL_EXPR: (n) => (n === 1 ? 0 : 1),
+ LOCALE: "unknown",
+
+ // gettext and ngettext don't access this so that the functions
+ // can safely bound to a different name (_ = Documentation.gettext)
+ gettext: (string) => {
+ const translated = Documentation.TRANSLATIONS[string];
+ switch (typeof translated) {
+ case "undefined":
+ return string; // no translation
+ case "string":
+ return translated; // translation exists
+ default:
+ return translated[0]; // (singular, plural) translation tuple exists
+ }
+ },
+
+ ngettext: (singular, plural, n) => {
+ const translated = Documentation.TRANSLATIONS[singular];
+ if (typeof translated !== "undefined")
+ return translated[Documentation.PLURAL_EXPR(n)];
+ return n === 1 ? singular : plural;
+ },
+
+ addTranslations: (catalog) => {
+ Object.assign(Documentation.TRANSLATIONS, catalog.messages);
+ Documentation.PLURAL_EXPR = new Function(
+ "n",
+ `return (${catalog.plural_expr})`
+ );
+ Documentation.LOCALE = catalog.locale;
+ },
+
+ /**
+ * helper function to focus on search bar
+ */
+ focusSearchBar: () => {
+ document.querySelectorAll("input[name=q]")[0]?.focus();
+ },
+
+ /**
+ * Initialise the domain index toggle buttons
+ */
+ initDomainIndexTable: () => {
+ const toggler = (el) => {
+ const idNumber = el.id.substr(7);
+ const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`);
+ if (el.src.substr(-9) === "minus.png") {
+ el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`;
+ toggledRows.forEach((el) => (el.style.display = "none"));
+ } else {
+ el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`;
+ toggledRows.forEach((el) => (el.style.display = ""));
+ }
+ };
+
+ const togglerElements = document.querySelectorAll("img.toggler");
+ togglerElements.forEach((el) =>
+ el.addEventListener("click", (event) => toggler(event.currentTarget))
+ );
+ togglerElements.forEach((el) => (el.style.display = ""));
+ if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler);
+ },
+
+ initOnKeyListeners: () => {
+ // only install a listener if it is really needed
+ if (
+ !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
+ !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS
+ )
+ return;
+
+ document.addEventListener("keydown", (event) => {
+ // bail for input elements
+ if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
+ // bail with special keys
+ if (event.altKey || event.ctrlKey || event.metaKey) return;
+
+ if (!event.shiftKey) {
+ switch (event.key) {
+ case "ArrowLeft":
+ if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
+
+ const prevLink = document.querySelector('link[rel="prev"]');
+ if (prevLink && prevLink.href) {
+ window.location.href = prevLink.href;
+ event.preventDefault();
+ }
+ break;
+ case "ArrowRight":
+ if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
+
+ const nextLink = document.querySelector('link[rel="next"]');
+ if (nextLink && nextLink.href) {
+ window.location.href = nextLink.href;
+ event.preventDefault();
+ }
+ break;
+ }
+ }
+
+ // some keyboard layouts may need Shift to get /
+ switch (event.key) {
+ case "/":
+ if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
+ Documentation.focusSearchBar();
+ event.preventDefault();
+ }
+ });
+ },
+};
+
+// quick alias for translations
+const _ = Documentation.gettext;
+
+_ready(Documentation.init);
diff --git a/_static/documentation_options.js b/_static/documentation_options.js
new file mode 100644
index 000000000..7e4c114f2
--- /dev/null
+++ b/_static/documentation_options.js
@@ -0,0 +1,13 @@
+const DOCUMENTATION_OPTIONS = {
+ VERSION: '',
+ LANGUAGE: 'en',
+ COLLAPSE_INDEX: false,
+ BUILDER: 'html',
+ FILE_SUFFIX: '.html',
+ LINK_SUFFIX: '.html',
+ HAS_SOURCE: true,
+ SOURCELINK_SUFFIX: '.txt',
+ NAVIGATION_WITH_KEYS: false,
+ SHOW_SEARCH_SUMMARY: true,
+ ENABLE_SEARCH_SHORTCUTS: true,
+};
\ No newline at end of file
diff --git a/_static/file.png b/_static/file.png
new file mode 100644
index 000000000..a858a410e
Binary files /dev/null and b/_static/file.png differ
diff --git a/_static/img/2021-05-09_10-32.jpg b/_static/img/2021-05-09_10-32.jpg
new file mode 100644
index 000000000..d16a02951
Binary files /dev/null and b/_static/img/2021-05-09_10-32.jpg differ
diff --git a/_static/img/2021-05-09_10-32.jpg.license b/_static/img/2021-05-09_10-32.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_10-32.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_10-36.jpg b/_static/img/2021-05-09_10-36.jpg
new file mode 100644
index 000000000..db2876cb3
Binary files /dev/null and b/_static/img/2021-05-09_10-36.jpg differ
diff --git a/_static/img/2021-05-09_10-36.jpg.license b/_static/img/2021-05-09_10-36.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_10-36.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_10-50.jpg b/_static/img/2021-05-09_10-50.jpg
new file mode 100644
index 000000000..cd12ca5d9
Binary files /dev/null and b/_static/img/2021-05-09_10-50.jpg differ
diff --git a/_static/img/2021-05-09_10-50.jpg.license b/_static/img/2021-05-09_10-50.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_10-50.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_17-36.jpg b/_static/img/2021-05-09_17-36.jpg
new file mode 100644
index 000000000..b5581088b
Binary files /dev/null and b/_static/img/2021-05-09_17-36.jpg differ
diff --git a/_static/img/2021-05-09_17-36.jpg.license b/_static/img/2021-05-09_17-36.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_17-36.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_17-38.jpg b/_static/img/2021-05-09_17-38.jpg
new file mode 100644
index 000000000..60c056e85
Binary files /dev/null and b/_static/img/2021-05-09_17-38.jpg differ
diff --git a/_static/img/2021-05-09_17-38.jpg.license b/_static/img/2021-05-09_17-38.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_17-38.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_17-44.jpg b/_static/img/2021-05-09_17-44.jpg
new file mode 100644
index 000000000..83b414d0f
Binary files /dev/null and b/_static/img/2021-05-09_17-44.jpg differ
diff --git a/_static/img/2021-05-09_17-44.jpg.license b/_static/img/2021-05-09_17-44.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_17-44.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_17-57.jpg b/_static/img/2021-05-09_17-57.jpg
new file mode 100644
index 000000000..b9dd0947e
Binary files /dev/null and b/_static/img/2021-05-09_17-57.jpg differ
diff --git a/_static/img/2021-05-09_17-57.jpg.license b/_static/img/2021-05-09_17-57.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_17-57.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_19-50.jpg b/_static/img/2021-05-09_19-50.jpg
new file mode 100644
index 000000000..7decd28c0
Binary files /dev/null and b/_static/img/2021-05-09_19-50.jpg differ
diff --git a/_static/img/2021-05-09_19-50.jpg.license b/_static/img/2021-05-09_19-50.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_19-50.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_21-16.jpg b/_static/img/2021-05-09_21-16.jpg
new file mode 100644
index 000000000..165f0ba53
Binary files /dev/null and b/_static/img/2021-05-09_21-16.jpg differ
diff --git a/_static/img/2021-05-09_21-16.jpg.license b/_static/img/2021-05-09_21-16.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_21-16.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_21-21.jpg b/_static/img/2021-05-09_21-21.jpg
new file mode 100644
index 000000000..1b27de5f0
Binary files /dev/null and b/_static/img/2021-05-09_21-21.jpg differ
diff --git a/_static/img/2021-05-09_21-21.jpg.license b/_static/img/2021-05-09_21-21.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_21-21.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_21-46.jpg b/_static/img/2021-05-09_21-46.jpg
new file mode 100644
index 000000000..903bd8e92
Binary files /dev/null and b/_static/img/2021-05-09_21-46.jpg differ
diff --git a/_static/img/2021-05-09_21-46.jpg.license b/_static/img/2021-05-09_21-46.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_21-46.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_22-09.jpg b/_static/img/2021-05-09_22-09.jpg
new file mode 100644
index 000000000..5b3a1fcd2
Binary files /dev/null and b/_static/img/2021-05-09_22-09.jpg differ
diff --git a/_static/img/2021-05-09_22-09.jpg.license b/_static/img/2021-05-09_22-09.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_22-09.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-09_22-39.jpg b/_static/img/2021-05-09_22-39.jpg
new file mode 100644
index 000000000..d02b6668f
Binary files /dev/null and b/_static/img/2021-05-09_22-39.jpg differ
diff --git a/_static/img/2021-05-09_22-39.jpg.license b/_static/img/2021-05-09_22-39.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-09_22-39.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-10_22-35.jpg b/_static/img/2021-05-10_22-35.jpg
new file mode 100644
index 000000000..9c3650585
Binary files /dev/null and b/_static/img/2021-05-10_22-35.jpg differ
diff --git a/_static/img/2021-05-10_22-35.jpg.license b/_static/img/2021-05-10_22-35.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-10_22-35.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-10_22-59.jpg b/_static/img/2021-05-10_22-59.jpg
new file mode 100644
index 000000000..ca184bc6c
Binary files /dev/null and b/_static/img/2021-05-10_22-59.jpg differ
diff --git a/_static/img/2021-05-10_22-59.jpg.license b/_static/img/2021-05-10_22-59.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-10_22-59.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-12_18-18.jpg b/_static/img/2021-05-12_18-18.jpg
new file mode 100644
index 000000000..5ee9dac5a
Binary files /dev/null and b/_static/img/2021-05-12_18-18.jpg differ
diff --git a/_static/img/2021-05-12_18-18.jpg.license b/_static/img/2021-05-12_18-18.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-12_18-18.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-12_18-51.jpg b/_static/img/2021-05-12_18-51.jpg
new file mode 100644
index 000000000..afb248858
Binary files /dev/null and b/_static/img/2021-05-12_18-51.jpg differ
diff --git a/_static/img/2021-05-12_18-51.jpg.license b/_static/img/2021-05-12_18-51.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-12_18-51.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-12_19-12.jpg b/_static/img/2021-05-12_19-12.jpg
new file mode 100644
index 000000000..cda80cf9d
Binary files /dev/null and b/_static/img/2021-05-12_19-12.jpg differ
diff --git a/_static/img/2021-05-12_19-12.jpg.license b/_static/img/2021-05-12_19-12.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-12_19-12.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-12_20-06.jpg b/_static/img/2021-05-12_20-06.jpg
new file mode 100644
index 000000000..b34855edf
Binary files /dev/null and b/_static/img/2021-05-12_20-06.jpg differ
diff --git a/_static/img/2021-05-12_20-06.jpg.license b/_static/img/2021-05-12_20-06.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-12_20-06.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-12_20-10.jpg b/_static/img/2021-05-12_20-10.jpg
new file mode 100644
index 000000000..04d6402f1
Binary files /dev/null and b/_static/img/2021-05-12_20-10.jpg differ
diff --git a/_static/img/2021-05-12_20-10.jpg.license b/_static/img/2021-05-12_20-10.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-12_20-10.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-12_21-03.jpg b/_static/img/2021-05-12_21-03.jpg
new file mode 100644
index 000000000..384e2ba0d
Binary files /dev/null and b/_static/img/2021-05-12_21-03.jpg differ
diff --git a/_static/img/2021-05-12_21-03.jpg.license b/_static/img/2021-05-12_21-03.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-12_21-03.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-13_20-46.jpg b/_static/img/2021-05-13_20-46.jpg
new file mode 100644
index 000000000..d3448b877
Binary files /dev/null and b/_static/img/2021-05-13_20-46.jpg differ
diff --git a/_static/img/2021-05-13_20-46.jpg.license b/_static/img/2021-05-13_20-46.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-13_20-46.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/2021-05-17_11-50.jpg b/_static/img/2021-05-17_11-50.jpg
new file mode 100644
index 000000000..3fb35b9c0
Binary files /dev/null and b/_static/img/2021-05-17_11-50.jpg differ
diff --git a/_static/img/2021-05-17_11-50.jpg.license b/_static/img/2021-05-17_11-50.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/2021-05-17_11-50.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/core-pkg-deps-raw.svg b/_static/img/core-pkg-deps-raw.svg
new file mode 100644
index 000000000..04321b962
--- /dev/null
+++ b/_static/img/core-pkg-deps-raw.svg
@@ -0,0 +1,1146 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/common/activity/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/common/behavior/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/common/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/core/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/cs/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/ctx/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/kitalpha/emde/1.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/epbs/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/fa/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/information/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/interaction/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/la/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/common/core/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/oa/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/pa/5.0.0
+
+
+
+
+
+
+
+
+
+
+ http://www.polarsys.org/capella/core/requirement/5.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_static/img/core-pkg-deps-raw.svg.license b/_static/img/core-pkg-deps-raw.svg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/core-pkg-deps-raw.svg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/crosslayer_intro.jpg b/_static/img/crosslayer_intro.jpg
new file mode 100644
index 000000000..41349a91a
Binary files /dev/null and b/_static/img/crosslayer_intro.jpg differ
diff --git a/_static/img/crosslayer_intro.jpg.license b/_static/img/crosslayer_intro.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/crosslayer_intro.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/dep-graph-oa.jpg b/_static/img/dep-graph-oa.jpg
new file mode 100644
index 000000000..1e771de2f
Binary files /dev/null and b/_static/img/dep-graph-oa.jpg differ
diff --git a/_static/img/dep-graph-oa.jpg.license b/_static/img/dep-graph-oa.jpg.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/dep-graph-oa.jpg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/github-logo.svg b/_static/img/github-logo.svg
new file mode 100644
index 000000000..06e6c2240
--- /dev/null
+++ b/_static/img/github-logo.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/_static/img/harrys_wand.png b/_static/img/harrys_wand.png
new file mode 100644
index 000000000..effece64b
Binary files /dev/null and b/_static/img/harrys_wand.png differ
diff --git a/_static/img/harrys_wand.png.license b/_static/img/harrys_wand.png.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/harrys_wand.png.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/img/waypoints.png b/_static/img/waypoints.png
new file mode 100644
index 000000000..fd021c986
Binary files /dev/null and b/_static/img/waypoints.png differ
diff --git a/_static/img/waypoints.png.license b/_static/img/waypoints.png.license
new file mode 100644
index 000000000..62a1749a9
--- /dev/null
+++ b/_static/img/waypoints.png.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: Copyright DB InfraGO AG
+SPDX-License-Identifier: Apache-2.0
diff --git a/_static/language_data.js b/_static/language_data.js
new file mode 100644
index 000000000..250f5665f
--- /dev/null
+++ b/_static/language_data.js
@@ -0,0 +1,199 @@
+/*
+ * language_data.js
+ * ~~~~~~~~~~~~~~~~
+ *
+ * This script contains the language-specific data used by searchtools.js,
+ * namely the list of stopwords, stemmer, scorer and splitter.
+ *
+ * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"];
+
+
+/* Non-minified version is copied as a separate JS file, is available */
+
+/**
+ * Porter Stemmer
+ */
+var Stemmer = function() {
+
+ var step2list = {
+ ational: 'ate',
+ tional: 'tion',
+ enci: 'ence',
+ anci: 'ance',
+ izer: 'ize',
+ bli: 'ble',
+ alli: 'al',
+ entli: 'ent',
+ eli: 'e',
+ ousli: 'ous',
+ ization: 'ize',
+ ation: 'ate',
+ ator: 'ate',
+ alism: 'al',
+ iveness: 'ive',
+ fulness: 'ful',
+ ousness: 'ous',
+ aliti: 'al',
+ iviti: 'ive',
+ biliti: 'ble',
+ logi: 'log'
+ };
+
+ var step3list = {
+ icate: 'ic',
+ ative: '',
+ alize: 'al',
+ iciti: 'ic',
+ ical: 'ic',
+ ful: '',
+ ness: ''
+ };
+
+ var c = "[^aeiou]"; // consonant
+ var v = "[aeiouy]"; // vowel
+ var C = c + "[^aeiouy]*"; // consonant sequence
+ var V = v + "[aeiou]*"; // vowel sequence
+
+ var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
+ var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
+ var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
+ var s_v = "^(" + C + ")?" + v; // vowel in stem
+
+ this.stemWord = function (w) {
+ var stem;
+ var suffix;
+ var firstch;
+ var origword = w;
+
+ if (w.length < 3)
+ return w;
+
+ var re;
+ var re2;
+ var re3;
+ var re4;
+
+ firstch = w.substr(0,1);
+ if (firstch == "y")
+ w = firstch.toUpperCase() + w.substr(1);
+
+ // Step 1a
+ re = /^(.+?)(ss|i)es$/;
+ re2 = /^(.+?)([^s])s$/;
+
+ if (re.test(w))
+ w = w.replace(re,"$1$2");
+ else if (re2.test(w))
+ w = w.replace(re2,"$1$2");
+
+ // Step 1b
+ re = /^(.+?)eed$/;
+ re2 = /^(.+?)(ed|ing)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ re = new RegExp(mgr0);
+ if (re.test(fp[1])) {
+ re = /.$/;
+ w = w.replace(re,"");
+ }
+ }
+ else if (re2.test(w)) {
+ var fp = re2.exec(w);
+ stem = fp[1];
+ re2 = new RegExp(s_v);
+ if (re2.test(stem)) {
+ w = stem;
+ re2 = /(at|bl|iz)$/;
+ re3 = new RegExp("([^aeiouylsz])\\1$");
+ re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+ if (re2.test(w))
+ w = w + "e";
+ else if (re3.test(w)) {
+ re = /.$/;
+ w = w.replace(re,"");
+ }
+ else if (re4.test(w))
+ w = w + "e";
+ }
+ }
+
+ // Step 1c
+ re = /^(.+?)y$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ re = new RegExp(s_v);
+ if (re.test(stem))
+ w = stem + "i";
+ }
+
+ // Step 2
+ re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ suffix = fp[2];
+ re = new RegExp(mgr0);
+ if (re.test(stem))
+ w = stem + step2list[suffix];
+ }
+
+ // Step 3
+ re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ suffix = fp[2];
+ re = new RegExp(mgr0);
+ if (re.test(stem))
+ w = stem + step3list[suffix];
+ }
+
+ // Step 4
+ re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
+ re2 = /^(.+?)(s|t)(ion)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ re = new RegExp(mgr1);
+ if (re.test(stem))
+ w = stem;
+ }
+ else if (re2.test(w)) {
+ var fp = re2.exec(w);
+ stem = fp[1] + fp[2];
+ re2 = new RegExp(mgr1);
+ if (re2.test(stem))
+ w = stem;
+ }
+
+ // Step 5
+ re = /^(.+?)e$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ re = new RegExp(mgr1);
+ re2 = new RegExp(meq1);
+ re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+ if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
+ w = stem;
+ }
+ re = /ll$/;
+ re2 = new RegExp(mgr1);
+ if (re.test(w) && re2.test(w)) {
+ re = /.$/;
+ w = w.replace(re,"");
+ }
+
+ // and turn initial Y back to y
+ if (firstch == "y")
+ w = firstch.toLowerCase() + w.substr(1);
+ return w;
+ }
+}
+
diff --git a/_static/minus.png b/_static/minus.png
new file mode 100644
index 000000000..d96755fda
Binary files /dev/null and b/_static/minus.png differ
diff --git a/_static/nbsphinx-broken-thumbnail.svg b/_static/nbsphinx-broken-thumbnail.svg
new file mode 100644
index 000000000..4919ca882
--- /dev/null
+++ b/_static/nbsphinx-broken-thumbnail.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/_static/nbsphinx-code-cells.css b/_static/nbsphinx-code-cells.css
new file mode 100644
index 000000000..a3fb27c30
--- /dev/null
+++ b/_static/nbsphinx-code-cells.css
@@ -0,0 +1,259 @@
+/* remove conflicting styling from Sphinx themes */
+div.nbinput.container div.prompt *,
+div.nboutput.container div.prompt *,
+div.nbinput.container div.input_area pre,
+div.nboutput.container div.output_area pre,
+div.nbinput.container div.input_area .highlight,
+div.nboutput.container div.output_area .highlight {
+ border: none;
+ padding: 0;
+ margin: 0;
+ box-shadow: none;
+}
+
+div.nbinput.container > div[class*=highlight],
+div.nboutput.container > div[class*=highlight] {
+ margin: 0;
+}
+
+div.nbinput.container div.prompt *,
+div.nboutput.container div.prompt * {
+ background: none;
+}
+
+div.nboutput.container div.output_area .highlight,
+div.nboutput.container div.output_area pre {
+ background: unset;
+}
+
+div.nboutput.container div.output_area div.highlight {
+ color: unset; /* override Pygments text color */
+}
+
+/* avoid gaps between output lines */
+div.nboutput.container div[class*=highlight] pre {
+ line-height: normal;
+}
+
+/* input/output containers */
+div.nbinput.container,
+div.nboutput.container {
+ display: -webkit-flex;
+ display: flex;
+ align-items: flex-start;
+ margin: 0;
+ width: 100%;
+}
+@media (max-width: 540px) {
+ div.nbinput.container,
+ div.nboutput.container {
+ flex-direction: column;
+ }
+}
+
+/* input container */
+div.nbinput.container {
+ padding-top: 5px;
+}
+
+/* last container */
+div.nblast.container {
+ padding-bottom: 5px;
+}
+
+/* input prompt */
+div.nbinput.container div.prompt pre,
+/* for sphinx_immaterial theme: */
+div.nbinput.container div.prompt pre > code {
+ color: #307FC1;
+}
+
+/* output prompt */
+div.nboutput.container div.prompt pre,
+/* for sphinx_immaterial theme: */
+div.nboutput.container div.prompt pre > code {
+ color: #BF5B3D;
+}
+
+/* all prompts */
+div.nbinput.container div.prompt,
+div.nboutput.container div.prompt {
+ width: 4.5ex;
+ padding-top: 5px;
+ position: relative;
+ user-select: none;
+}
+
+div.nbinput.container div.prompt > div,
+div.nboutput.container div.prompt > div {
+ position: absolute;
+ right: 0;
+ margin-right: 0.3ex;
+}
+
+@media (max-width: 540px) {
+ div.nbinput.container div.prompt,
+ div.nboutput.container div.prompt {
+ width: unset;
+ text-align: left;
+ padding: 0.4em;
+ }
+ div.nboutput.container div.prompt.empty {
+ padding: 0;
+ }
+
+ div.nbinput.container div.prompt > div,
+ div.nboutput.container div.prompt > div {
+ position: unset;
+ }
+}
+
+/* disable scrollbars and line breaks on prompts */
+div.nbinput.container div.prompt pre,
+div.nboutput.container div.prompt pre {
+ overflow: hidden;
+ white-space: pre;
+}
+
+/* input/output area */
+div.nbinput.container div.input_area,
+div.nboutput.container div.output_area {
+ -webkit-flex: 1;
+ flex: 1;
+ overflow: auto;
+}
+@media (max-width: 540px) {
+ div.nbinput.container div.input_area,
+ div.nboutput.container div.output_area {
+ width: 100%;
+ }
+}
+
+/* input area */
+div.nbinput.container div.input_area {
+ border: 1px solid #e0e0e0;
+ border-radius: 2px;
+ /*background: #f5f5f5;*/
+}
+
+/* override MathJax center alignment in output cells */
+div.nboutput.container div[class*=MathJax] {
+ text-align: left !important;
+}
+
+/* override sphinx.ext.imgmath center alignment in output cells */
+div.nboutput.container div.math p {
+ text-align: left;
+}
+
+/* standard error */
+div.nboutput.container div.output_area.stderr {
+ background: #fdd;
+}
+
+/* ANSI colors */
+.ansi-black-fg { color: #3E424D; }
+.ansi-black-bg { background-color: #3E424D; }
+.ansi-black-intense-fg { color: #282C36; }
+.ansi-black-intense-bg { background-color: #282C36; }
+.ansi-red-fg { color: #E75C58; }
+.ansi-red-bg { background-color: #E75C58; }
+.ansi-red-intense-fg { color: #B22B31; }
+.ansi-red-intense-bg { background-color: #B22B31; }
+.ansi-green-fg { color: #00A250; }
+.ansi-green-bg { background-color: #00A250; }
+.ansi-green-intense-fg { color: #007427; }
+.ansi-green-intense-bg { background-color: #007427; }
+.ansi-yellow-fg { color: #DDB62B; }
+.ansi-yellow-bg { background-color: #DDB62B; }
+.ansi-yellow-intense-fg { color: #B27D12; }
+.ansi-yellow-intense-bg { background-color: #B27D12; }
+.ansi-blue-fg { color: #208FFB; }
+.ansi-blue-bg { background-color: #208FFB; }
+.ansi-blue-intense-fg { color: #0065CA; }
+.ansi-blue-intense-bg { background-color: #0065CA; }
+.ansi-magenta-fg { color: #D160C4; }
+.ansi-magenta-bg { background-color: #D160C4; }
+.ansi-magenta-intense-fg { color: #A03196; }
+.ansi-magenta-intense-bg { background-color: #A03196; }
+.ansi-cyan-fg { color: #60C6C8; }
+.ansi-cyan-bg { background-color: #60C6C8; }
+.ansi-cyan-intense-fg { color: #258F8F; }
+.ansi-cyan-intense-bg { background-color: #258F8F; }
+.ansi-white-fg { color: #C5C1B4; }
+.ansi-white-bg { background-color: #C5C1B4; }
+.ansi-white-intense-fg { color: #A1A6B2; }
+.ansi-white-intense-bg { background-color: #A1A6B2; }
+
+.ansi-default-inverse-fg { color: #FFFFFF; }
+.ansi-default-inverse-bg { background-color: #000000; }
+
+.ansi-bold { font-weight: bold; }
+.ansi-underline { text-decoration: underline; }
+
+
+div.nbinput.container div.input_area div[class*=highlight] > pre,
+div.nboutput.container div.output_area div[class*=highlight] > pre,
+div.nboutput.container div.output_area div[class*=highlight].math,
+div.nboutput.container div.output_area.rendered_html,
+div.nboutput.container div.output_area > div.output_javascript,
+div.nboutput.container div.output_area:not(.rendered_html) > img{
+ padding: 5px;
+ margin: 0;
+}
+
+/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */
+div.nbinput.container div.input_area > div[class^='highlight'],
+div.nboutput.container div.output_area > div[class^='highlight']{
+ overflow-y: hidden;
+}
+
+/* hide copy button on prompts for 'sphinx_copybutton' extension ... */
+.prompt .copybtn,
+/* ... and 'sphinx_immaterial' theme */
+.prompt .md-clipboard.md-icon {
+ display: none;
+}
+
+/* Some additional styling taken form the Jupyter notebook CSS */
+.jp-RenderedHTMLCommon table,
+div.rendered_html table {
+ border: none;
+ border-collapse: collapse;
+ border-spacing: 0;
+ color: black;
+ font-size: 12px;
+ table-layout: fixed;
+}
+.jp-RenderedHTMLCommon thead,
+div.rendered_html thead {
+ border-bottom: 1px solid black;
+ vertical-align: bottom;
+}
+.jp-RenderedHTMLCommon tr,
+.jp-RenderedHTMLCommon th,
+.jp-RenderedHTMLCommon td,
+div.rendered_html tr,
+div.rendered_html th,
+div.rendered_html td {
+ text-align: right;
+ vertical-align: middle;
+ padding: 0.5em 0.5em;
+ line-height: normal;
+ white-space: normal;
+ max-width: none;
+ border: none;
+}
+.jp-RenderedHTMLCommon th,
+div.rendered_html th {
+ font-weight: bold;
+}
+.jp-RenderedHTMLCommon tbody tr:nth-child(odd),
+div.rendered_html tbody tr:nth-child(odd) {
+ background: #f5f5f5;
+}
+.jp-RenderedHTMLCommon tbody tr:hover,
+div.rendered_html tbody tr:hover {
+ background: rgba(66, 165, 245, 0.2);
+}
+
diff --git a/_static/nbsphinx-gallery.css b/_static/nbsphinx-gallery.css
new file mode 100644
index 000000000..365c27a96
--- /dev/null
+++ b/_static/nbsphinx-gallery.css
@@ -0,0 +1,31 @@
+.nbsphinx-gallery {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
+ gap: 5px;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.nbsphinx-gallery > a {
+ padding: 5px;
+ border: 1px dotted currentColor;
+ border-radius: 2px;
+ text-align: center;
+}
+
+.nbsphinx-gallery > a:hover {
+ border-style: solid;
+}
+
+.nbsphinx-gallery img {
+ max-width: 100%;
+ max-height: 100%;
+}
+
+.nbsphinx-gallery > a > div:first-child {
+ display: flex;
+ align-items: start;
+ justify-content: center;
+ height: 120px;
+ margin-bottom: 5px;
+}
diff --git a/_static/nbsphinx-no-thumbnail.svg b/_static/nbsphinx-no-thumbnail.svg
new file mode 100644
index 000000000..9dca7588f
--- /dev/null
+++ b/_static/nbsphinx-no-thumbnail.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/_static/plus.png b/_static/plus.png
new file mode 100644
index 000000000..7107cec93
Binary files /dev/null and b/_static/plus.png differ
diff --git a/_static/pygments.css b/_static/pygments.css
new file mode 100644
index 000000000..5c8cad8b4
--- /dev/null
+++ b/_static/pygments.css
@@ -0,0 +1,258 @@
+.highlight pre { line-height: 125%; }
+.highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+.highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+.highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+.highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+.highlight .hll { background-color: #ffffcc }
+.highlight { background: #f8f8f8; }
+.highlight .c { color: #8f5902; font-style: italic } /* Comment */
+.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */
+.highlight .g { color: #000000 } /* Generic */
+.highlight .k { color: #204a87; font-weight: bold } /* Keyword */
+.highlight .l { color: #000000 } /* Literal */
+.highlight .n { color: #000000 } /* Name */
+.highlight .o { color: #ce5c00; font-weight: bold } /* Operator */
+.highlight .x { color: #000000 } /* Other */
+.highlight .p { color: #000000; font-weight: bold } /* Punctuation */
+.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */
+.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */
+.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */
+.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #a40000 } /* Generic.Deleted */
+.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
+.highlight .ges { color: #000000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
+.highlight .gr { color: #ef2929 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #000000; font-style: italic } /* Generic.Output */
+.highlight .gp { color: #8f5902 } /* Generic.Prompt */
+.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
+.highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */
+.highlight .ld { color: #000000 } /* Literal.Date */
+.highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */
+.highlight .s { color: #4e9a06 } /* Literal.String */
+.highlight .na { color: #c4a000 } /* Name.Attribute */
+.highlight .nb { color: #204a87 } /* Name.Builtin */
+.highlight .nc { color: #000000 } /* Name.Class */
+.highlight .no { color: #000000 } /* Name.Constant */
+.highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #ce5c00 } /* Name.Entity */
+.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #000000 } /* Name.Function */
+.highlight .nl { color: #f57900 } /* Name.Label */
+.highlight .nn { color: #000000 } /* Name.Namespace */
+.highlight .nx { color: #000000 } /* Name.Other */
+.highlight .py { color: #000000 } /* Name.Property */
+.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #000000 } /* Name.Variable */
+.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */
+.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */
+.highlight .w { color: #f8f8f8 } /* Text.Whitespace */
+.highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */
+.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */
+.highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */
+.highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */
+.highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */
+.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */
+.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */
+.highlight .sc { color: #4e9a06 } /* Literal.String.Char */
+.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */
+.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */
+.highlight .se { color: #4e9a06 } /* Literal.String.Escape */
+.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */
+.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */
+.highlight .sx { color: #4e9a06 } /* Literal.String.Other */
+.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */
+.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */
+.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */
+.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */
+.highlight .fm { color: #000000 } /* Name.Function.Magic */
+.highlight .vc { color: #000000 } /* Name.Variable.Class */
+.highlight .vg { color: #000000 } /* Name.Variable.Global */
+.highlight .vi { color: #000000 } /* Name.Variable.Instance */
+.highlight .vm { color: #000000 } /* Name.Variable.Magic */
+.highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */
+@media not print {
+body[data-theme="dark"] .highlight pre { line-height: 125%; }
+body[data-theme="dark"] .highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+body[data-theme="dark"] .highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+body[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+body[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+body[data-theme="dark"] .highlight .hll { background-color: #49483e }
+body[data-theme="dark"] .highlight { background: #272822; color: #f8f8f2 }
+body[data-theme="dark"] .highlight .c { color: #959077 } /* Comment */
+body[data-theme="dark"] .highlight .err { color: #ed007e; background-color: #1e0010 } /* Error */
+body[data-theme="dark"] .highlight .esc { color: #f8f8f2 } /* Escape */
+body[data-theme="dark"] .highlight .g { color: #f8f8f2 } /* Generic */
+body[data-theme="dark"] .highlight .k { color: #66d9ef } /* Keyword */
+body[data-theme="dark"] .highlight .l { color: #ae81ff } /* Literal */
+body[data-theme="dark"] .highlight .n { color: #f8f8f2 } /* Name */
+body[data-theme="dark"] .highlight .o { color: #ff4689 } /* Operator */
+body[data-theme="dark"] .highlight .x { color: #f8f8f2 } /* Other */
+body[data-theme="dark"] .highlight .p { color: #f8f8f2 } /* Punctuation */
+body[data-theme="dark"] .highlight .ch { color: #959077 } /* Comment.Hashbang */
+body[data-theme="dark"] .highlight .cm { color: #959077 } /* Comment.Multiline */
+body[data-theme="dark"] .highlight .cp { color: #959077 } /* Comment.Preproc */
+body[data-theme="dark"] .highlight .cpf { color: #959077 } /* Comment.PreprocFile */
+body[data-theme="dark"] .highlight .c1 { color: #959077 } /* Comment.Single */
+body[data-theme="dark"] .highlight .cs { color: #959077 } /* Comment.Special */
+body[data-theme="dark"] .highlight .gd { color: #ff4689 } /* Generic.Deleted */
+body[data-theme="dark"] .highlight .ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */
+body[data-theme="dark"] .highlight .ges { color: #f8f8f2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
+body[data-theme="dark"] .highlight .gr { color: #f8f8f2 } /* Generic.Error */
+body[data-theme="dark"] .highlight .gh { color: #f8f8f2 } /* Generic.Heading */
+body[data-theme="dark"] .highlight .gi { color: #a6e22e } /* Generic.Inserted */
+body[data-theme="dark"] .highlight .go { color: #66d9ef } /* Generic.Output */
+body[data-theme="dark"] .highlight .gp { color: #ff4689; font-weight: bold } /* Generic.Prompt */
+body[data-theme="dark"] .highlight .gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */
+body[data-theme="dark"] .highlight .gu { color: #959077 } /* Generic.Subheading */
+body[data-theme="dark"] .highlight .gt { color: #f8f8f2 } /* Generic.Traceback */
+body[data-theme="dark"] .highlight .kc { color: #66d9ef } /* Keyword.Constant */
+body[data-theme="dark"] .highlight .kd { color: #66d9ef } /* Keyword.Declaration */
+body[data-theme="dark"] .highlight .kn { color: #ff4689 } /* Keyword.Namespace */
+body[data-theme="dark"] .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
+body[data-theme="dark"] .highlight .kr { color: #66d9ef } /* Keyword.Reserved */
+body[data-theme="dark"] .highlight .kt { color: #66d9ef } /* Keyword.Type */
+body[data-theme="dark"] .highlight .ld { color: #e6db74 } /* Literal.Date */
+body[data-theme="dark"] .highlight .m { color: #ae81ff } /* Literal.Number */
+body[data-theme="dark"] .highlight .s { color: #e6db74 } /* Literal.String */
+body[data-theme="dark"] .highlight .na { color: #a6e22e } /* Name.Attribute */
+body[data-theme="dark"] .highlight .nb { color: #f8f8f2 } /* Name.Builtin */
+body[data-theme="dark"] .highlight .nc { color: #a6e22e } /* Name.Class */
+body[data-theme="dark"] .highlight .no { color: #66d9ef } /* Name.Constant */
+body[data-theme="dark"] .highlight .nd { color: #a6e22e } /* Name.Decorator */
+body[data-theme="dark"] .highlight .ni { color: #f8f8f2 } /* Name.Entity */
+body[data-theme="dark"] .highlight .ne { color: #a6e22e } /* Name.Exception */
+body[data-theme="dark"] .highlight .nf { color: #a6e22e } /* Name.Function */
+body[data-theme="dark"] .highlight .nl { color: #f8f8f2 } /* Name.Label */
+body[data-theme="dark"] .highlight .nn { color: #f8f8f2 } /* Name.Namespace */
+body[data-theme="dark"] .highlight .nx { color: #a6e22e } /* Name.Other */
+body[data-theme="dark"] .highlight .py { color: #f8f8f2 } /* Name.Property */
+body[data-theme="dark"] .highlight .nt { color: #ff4689 } /* Name.Tag */
+body[data-theme="dark"] .highlight .nv { color: #f8f8f2 } /* Name.Variable */
+body[data-theme="dark"] .highlight .ow { color: #ff4689 } /* Operator.Word */
+body[data-theme="dark"] .highlight .pm { color: #f8f8f2 } /* Punctuation.Marker */
+body[data-theme="dark"] .highlight .w { color: #f8f8f2 } /* Text.Whitespace */
+body[data-theme="dark"] .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
+body[data-theme="dark"] .highlight .mf { color: #ae81ff } /* Literal.Number.Float */
+body[data-theme="dark"] .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
+body[data-theme="dark"] .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
+body[data-theme="dark"] .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
+body[data-theme="dark"] .highlight .sa { color: #e6db74 } /* Literal.String.Affix */
+body[data-theme="dark"] .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
+body[data-theme="dark"] .highlight .sc { color: #e6db74 } /* Literal.String.Char */
+body[data-theme="dark"] .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
+body[data-theme="dark"] .highlight .sd { color: #e6db74 } /* Literal.String.Doc */
+body[data-theme="dark"] .highlight .s2 { color: #e6db74 } /* Literal.String.Double */
+body[data-theme="dark"] .highlight .se { color: #ae81ff } /* Literal.String.Escape */
+body[data-theme="dark"] .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
+body[data-theme="dark"] .highlight .si { color: #e6db74 } /* Literal.String.Interpol */
+body[data-theme="dark"] .highlight .sx { color: #e6db74 } /* Literal.String.Other */
+body[data-theme="dark"] .highlight .sr { color: #e6db74 } /* Literal.String.Regex */
+body[data-theme="dark"] .highlight .s1 { color: #e6db74 } /* Literal.String.Single */
+body[data-theme="dark"] .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
+body[data-theme="dark"] .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
+body[data-theme="dark"] .highlight .fm { color: #a6e22e } /* Name.Function.Magic */
+body[data-theme="dark"] .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
+body[data-theme="dark"] .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
+body[data-theme="dark"] .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
+body[data-theme="dark"] .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
+body[data-theme="dark"] .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
+@media (prefers-color-scheme: dark) {
+body:not([data-theme="light"]) .highlight pre { line-height: 125%; }
+body:not([data-theme="light"]) .highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+body:not([data-theme="light"]) .highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+body:not([data-theme="light"]) .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+body:not([data-theme="light"]) .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+body:not([data-theme="light"]) .highlight .hll { background-color: #49483e }
+body:not([data-theme="light"]) .highlight { background: #272822; color: #f8f8f2 }
+body:not([data-theme="light"]) .highlight .c { color: #959077 } /* Comment */
+body:not([data-theme="light"]) .highlight .err { color: #ed007e; background-color: #1e0010 } /* Error */
+body:not([data-theme="light"]) .highlight .esc { color: #f8f8f2 } /* Escape */
+body:not([data-theme="light"]) .highlight .g { color: #f8f8f2 } /* Generic */
+body:not([data-theme="light"]) .highlight .k { color: #66d9ef } /* Keyword */
+body:not([data-theme="light"]) .highlight .l { color: #ae81ff } /* Literal */
+body:not([data-theme="light"]) .highlight .n { color: #f8f8f2 } /* Name */
+body:not([data-theme="light"]) .highlight .o { color: #ff4689 } /* Operator */
+body:not([data-theme="light"]) .highlight .x { color: #f8f8f2 } /* Other */
+body:not([data-theme="light"]) .highlight .p { color: #f8f8f2 } /* Punctuation */
+body:not([data-theme="light"]) .highlight .ch { color: #959077 } /* Comment.Hashbang */
+body:not([data-theme="light"]) .highlight .cm { color: #959077 } /* Comment.Multiline */
+body:not([data-theme="light"]) .highlight .cp { color: #959077 } /* Comment.Preproc */
+body:not([data-theme="light"]) .highlight .cpf { color: #959077 } /* Comment.PreprocFile */
+body:not([data-theme="light"]) .highlight .c1 { color: #959077 } /* Comment.Single */
+body:not([data-theme="light"]) .highlight .cs { color: #959077 } /* Comment.Special */
+body:not([data-theme="light"]) .highlight .gd { color: #ff4689 } /* Generic.Deleted */
+body:not([data-theme="light"]) .highlight .ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */
+body:not([data-theme="light"]) .highlight .ges { color: #f8f8f2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
+body:not([data-theme="light"]) .highlight .gr { color: #f8f8f2 } /* Generic.Error */
+body:not([data-theme="light"]) .highlight .gh { color: #f8f8f2 } /* Generic.Heading */
+body:not([data-theme="light"]) .highlight .gi { color: #a6e22e } /* Generic.Inserted */
+body:not([data-theme="light"]) .highlight .go { color: #66d9ef } /* Generic.Output */
+body:not([data-theme="light"]) .highlight .gp { color: #ff4689; font-weight: bold } /* Generic.Prompt */
+body:not([data-theme="light"]) .highlight .gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */
+body:not([data-theme="light"]) .highlight .gu { color: #959077 } /* Generic.Subheading */
+body:not([data-theme="light"]) .highlight .gt { color: #f8f8f2 } /* Generic.Traceback */
+body:not([data-theme="light"]) .highlight .kc { color: #66d9ef } /* Keyword.Constant */
+body:not([data-theme="light"]) .highlight .kd { color: #66d9ef } /* Keyword.Declaration */
+body:not([data-theme="light"]) .highlight .kn { color: #ff4689 } /* Keyword.Namespace */
+body:not([data-theme="light"]) .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
+body:not([data-theme="light"]) .highlight .kr { color: #66d9ef } /* Keyword.Reserved */
+body:not([data-theme="light"]) .highlight .kt { color: #66d9ef } /* Keyword.Type */
+body:not([data-theme="light"]) .highlight .ld { color: #e6db74 } /* Literal.Date */
+body:not([data-theme="light"]) .highlight .m { color: #ae81ff } /* Literal.Number */
+body:not([data-theme="light"]) .highlight .s { color: #e6db74 } /* Literal.String */
+body:not([data-theme="light"]) .highlight .na { color: #a6e22e } /* Name.Attribute */
+body:not([data-theme="light"]) .highlight .nb { color: #f8f8f2 } /* Name.Builtin */
+body:not([data-theme="light"]) .highlight .nc { color: #a6e22e } /* Name.Class */
+body:not([data-theme="light"]) .highlight .no { color: #66d9ef } /* Name.Constant */
+body:not([data-theme="light"]) .highlight .nd { color: #a6e22e } /* Name.Decorator */
+body:not([data-theme="light"]) .highlight .ni { color: #f8f8f2 } /* Name.Entity */
+body:not([data-theme="light"]) .highlight .ne { color: #a6e22e } /* Name.Exception */
+body:not([data-theme="light"]) .highlight .nf { color: #a6e22e } /* Name.Function */
+body:not([data-theme="light"]) .highlight .nl { color: #f8f8f2 } /* Name.Label */
+body:not([data-theme="light"]) .highlight .nn { color: #f8f8f2 } /* Name.Namespace */
+body:not([data-theme="light"]) .highlight .nx { color: #a6e22e } /* Name.Other */
+body:not([data-theme="light"]) .highlight .py { color: #f8f8f2 } /* Name.Property */
+body:not([data-theme="light"]) .highlight .nt { color: #ff4689 } /* Name.Tag */
+body:not([data-theme="light"]) .highlight .nv { color: #f8f8f2 } /* Name.Variable */
+body:not([data-theme="light"]) .highlight .ow { color: #ff4689 } /* Operator.Word */
+body:not([data-theme="light"]) .highlight .pm { color: #f8f8f2 } /* Punctuation.Marker */
+body:not([data-theme="light"]) .highlight .w { color: #f8f8f2 } /* Text.Whitespace */
+body:not([data-theme="light"]) .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
+body:not([data-theme="light"]) .highlight .mf { color: #ae81ff } /* Literal.Number.Float */
+body:not([data-theme="light"]) .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
+body:not([data-theme="light"]) .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
+body:not([data-theme="light"]) .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
+body:not([data-theme="light"]) .highlight .sa { color: #e6db74 } /* Literal.String.Affix */
+body:not([data-theme="light"]) .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
+body:not([data-theme="light"]) .highlight .sc { color: #e6db74 } /* Literal.String.Char */
+body:not([data-theme="light"]) .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
+body:not([data-theme="light"]) .highlight .sd { color: #e6db74 } /* Literal.String.Doc */
+body:not([data-theme="light"]) .highlight .s2 { color: #e6db74 } /* Literal.String.Double */
+body:not([data-theme="light"]) .highlight .se { color: #ae81ff } /* Literal.String.Escape */
+body:not([data-theme="light"]) .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
+body:not([data-theme="light"]) .highlight .si { color: #e6db74 } /* Literal.String.Interpol */
+body:not([data-theme="light"]) .highlight .sx { color: #e6db74 } /* Literal.String.Other */
+body:not([data-theme="light"]) .highlight .sr { color: #e6db74 } /* Literal.String.Regex */
+body:not([data-theme="light"]) .highlight .s1 { color: #e6db74 } /* Literal.String.Single */
+body:not([data-theme="light"]) .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
+body:not([data-theme="light"]) .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
+body:not([data-theme="light"]) .highlight .fm { color: #a6e22e } /* Name.Function.Magic */
+body:not([data-theme="light"]) .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
+body:not([data-theme="light"]) .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
+body:not([data-theme="light"]) .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
+body:not([data-theme="light"]) .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
+body:not([data-theme="light"]) .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
+}
+}
\ No newline at end of file
diff --git a/_static/scripts/furo-extensions.js b/_static/scripts/furo-extensions.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/_static/scripts/furo.js b/_static/scripts/furo.js
new file mode 100644
index 000000000..32e7c05be
--- /dev/null
+++ b/_static/scripts/furo.js
@@ -0,0 +1,3 @@
+/*! For license information please see furo.js.LICENSE.txt */
+(()=>{var t={212:function(t,e,n){var o,r;r=void 0!==n.g?n.g:"undefined"!=typeof window?window:this,o=function(){return function(t){"use strict";var e={navClass:"active",contentClass:"active",nested:!1,nestedClass:"active",offset:0,reflow:!1,events:!0},n=function(t,e,n){if(n.settings.events){var o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n});e.dispatchEvent(o)}},o=function(t){var e=0;if(t.offsetParent)for(;t;)e+=t.offsetTop,t=t.offsetParent;return e>=0?e:0},r=function(t){t&&t.sort((function(t,e){return o(t.content)=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight,document.body.offsetHeight,document.documentElement.offsetHeight,document.body.clientHeight,document.documentElement.clientHeight)},l=function(t,e){var n=t[t.length-1];if(function(t,e){return!(!s()||!c(t.content,e,!0))}(n,e))return n;for(var o=t.length-1;o>=0;o--)if(c(t[o].content,e))return t[o]},a=function(t,e){if(e.nested&&t.parentNode){var n=t.parentNode.closest("li");n&&(n.classList.remove(e.nestedClass),a(n,e))}},i=function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.remove(e.navClass),t.content.classList.remove(e.contentClass),a(o,e),n("gumshoeDeactivate",o,{link:t.nav,content:t.content,settings:e}))}},u=function(t,e){if(e.nested){var n=t.parentNode.closest("li");n&&(n.classList.add(e.nestedClass),u(n,e))}};return function(o,c){var s,a,d,f,m,v={setup:function(){s=document.querySelectorAll(o),a=[],Array.prototype.forEach.call(s,(function(t){var e=document.getElementById(decodeURIComponent(t.hash.substr(1)));e&&a.push({nav:t,content:e})})),r(a)},detect:function(){var t=l(a,m);t?d&&t.content===d.content||(i(d,m),function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.add(e.navClass),t.content.classList.add(e.contentClass),u(o,e),n("gumshoeActivate",o,{link:t.nav,content:t.content,settings:e}))}}(t,m),d=t):d&&(i(d,m),d=null)}},h=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame(v.detect)},g=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame((function(){r(a),v.detect()}))};return v.destroy=function(){d&&i(d,m),t.removeEventListener("scroll",h,!1),m.reflow&&t.removeEventListener("resize",g,!1),a=null,s=null,d=null,f=null,m=null},m=function(){var t={};return Array.prototype.forEach.call(arguments,(function(e){for(var n in e){if(!e.hasOwnProperty(n))return;t[n]=e[n]}})),t}(e,c||{}),v.setup(),v.detect(),t.addEventListener("scroll",h,!1),m.reflow&&t.addEventListener("resize",g,!1),v}}(r)}.apply(e,[]),void 0===o||(t.exports=o)}},e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o].call(c.exports,c,c.exports,n),c.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=n(212),e=n.n(t),o=null,r=null,c=window.pageYOffset||document.documentElement.scrollTop;const s=64;function l(){const t=localStorage.getItem("theme")||"auto";var e;"light"!==(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"auto"===t?"light":"light"==t?"dark":"auto":"auto"===t?"dark":"dark"==t?"light":"auto")&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto"),document.body.dataset.theme=e,localStorage.setItem("theme",e),console.log(`Changed to ${e} mode.`)}function a(){!function(){const t=document.getElementsByClassName("theme-toggle");Array.from(t).forEach((t=>{t.addEventListener("click",l)}))}(),function(){let t=0,e=!1;window.addEventListener("scroll",(function(n){t=window.scrollY,e||(window.requestAnimationFrame((function(){var n;n=t,0==Math.floor(r.getBoundingClientRect().top)?r.classList.add("scrolled"):r.classList.remove("scrolled"),function(t){tc&&document.documentElement.classList.remove("show-back-to-top"),c=t}(n),function(t){null!==o&&(0==t?o.scrollTo(0,0):Math.ceil(t)>=Math.floor(document.documentElement.scrollHeight-window.innerHeight)?o.scrollTo(0,o.scrollHeight):document.querySelector(".scroll-current"))}(n),e=!1})),e=!0)})),window.scroll()}(),null!==o&&new(e())(".toc-tree a",{reflow:!0,recursive:!0,navClass:"scroll-current",offset:()=>{let t=parseFloat(getComputedStyle(document.documentElement).fontSize);return r.getBoundingClientRect().height+.5*t+1}})}document.addEventListener("DOMContentLoaded",(function(){document.body.parentNode.classList.remove("no-js"),r=document.querySelector("header"),o=document.querySelector(".toc-scroll"),a()}))})()})();
+//# sourceMappingURL=furo.js.map
\ No newline at end of file
diff --git a/_static/scripts/furo.js.LICENSE.txt b/_static/scripts/furo.js.LICENSE.txt
new file mode 100644
index 000000000..1632189c7
--- /dev/null
+++ b/_static/scripts/furo.js.LICENSE.txt
@@ -0,0 +1,7 @@
+/*!
+ * gumshoejs v5.1.2 (patched by @pradyunsg)
+ * A simple, framework-agnostic scrollspy script.
+ * (c) 2019 Chris Ferdinandi
+ * MIT License
+ * http://github.com/cferdinandi/gumshoe
+ */
diff --git a/_static/scripts/furo.js.map b/_static/scripts/furo.js.map
new file mode 100644
index 000000000..470530223
--- /dev/null
+++ b/_static/scripts/furo.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"scripts/furo.js","mappings":"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","sources":["webpack:///./src/furo/assets/scripts/gumshoe-patched.js","webpack:///webpack/bootstrap","webpack:///webpack/runtime/compat get default export","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/global","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///./src/furo/assets/scripts/furo.js"],"sourcesContent":["/*!\n * gumshoejs v5.1.2 (patched by @pradyunsg)\n * A simple, framework-agnostic scrollspy script.\n * (c) 2019 Chris Ferdinandi\n * MIT License\n * http://github.com/cferdinandi/gumshoe\n */\n\n(function (root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define([], function () {\n return factory(root);\n });\n } else if (typeof exports === \"object\") {\n module.exports = factory(root);\n } else {\n root.Gumshoe = factory(root);\n }\n})(\n typeof global !== \"undefined\"\n ? global\n : typeof window !== \"undefined\"\n ? window\n : this,\n function (window) {\n \"use strict\";\n\n //\n // Defaults\n //\n\n var defaults = {\n // Active classes\n navClass: \"active\",\n contentClass: \"active\",\n\n // Nested navigation\n nested: false,\n nestedClass: \"active\",\n\n // Offset & reflow\n offset: 0,\n reflow: false,\n\n // Event support\n events: true,\n };\n\n //\n // Methods\n //\n\n /**\n * Merge two or more objects together.\n * @param {Object} objects The objects to merge together\n * @returns {Object} Merged values of defaults and options\n */\n var extend = function () {\n var merged = {};\n Array.prototype.forEach.call(arguments, function (obj) {\n for (var key in obj) {\n if (!obj.hasOwnProperty(key)) return;\n merged[key] = obj[key];\n }\n });\n return merged;\n };\n\n /**\n * Emit a custom event\n * @param {String} type The event type\n * @param {Node} elem The element to attach the event to\n * @param {Object} detail Any details to pass along with the event\n */\n var emitEvent = function (type, elem, detail) {\n // Make sure events are enabled\n if (!detail.settings.events) return;\n\n // Create a new event\n var event = new CustomEvent(type, {\n bubbles: true,\n cancelable: true,\n detail: detail,\n });\n\n // Dispatch the event\n elem.dispatchEvent(event);\n };\n\n /**\n * Get an element's distance from the top of the Document.\n * @param {Node} elem The element\n * @return {Number} Distance from the top in pixels\n */\n var getOffsetTop = function (elem) {\n var location = 0;\n if (elem.offsetParent) {\n while (elem) {\n location += elem.offsetTop;\n elem = elem.offsetParent;\n }\n }\n return location >= 0 ? location : 0;\n };\n\n /**\n * Sort content from first to last in the DOM\n * @param {Array} contents The content areas\n */\n var sortContents = function (contents) {\n if (contents) {\n contents.sort(function (item1, item2) {\n var offset1 = getOffsetTop(item1.content);\n var offset2 = getOffsetTop(item2.content);\n if (offset1 < offset2) return -1;\n return 1;\n });\n }\n };\n\n /**\n * Get the offset to use for calculating position\n * @param {Object} settings The settings for this instantiation\n * @return {Float} The number of pixels to offset the calculations\n */\n var getOffset = function (settings) {\n // if the offset is a function run it\n if (typeof settings.offset === \"function\") {\n return parseFloat(settings.offset());\n }\n\n // Otherwise, return it as-is\n return parseFloat(settings.offset);\n };\n\n /**\n * Get the document element's height\n * @private\n * @returns {Number}\n */\n var getDocumentHeight = function () {\n return Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n document.body.offsetHeight,\n document.documentElement.offsetHeight,\n document.body.clientHeight,\n document.documentElement.clientHeight,\n );\n };\n\n /**\n * Determine if an element is in view\n * @param {Node} elem The element\n * @param {Object} settings The settings for this instantiation\n * @param {Boolean} bottom If true, check if element is above bottom of viewport instead\n * @return {Boolean} Returns true if element is in the viewport\n */\n var isInView = function (elem, settings, bottom) {\n var bounds = elem.getBoundingClientRect();\n var offset = getOffset(settings);\n if (bottom) {\n return (\n parseInt(bounds.bottom, 10) <\n (window.innerHeight || document.documentElement.clientHeight)\n );\n }\n return parseInt(bounds.top, 10) <= offset;\n };\n\n /**\n * Check if at the bottom of the viewport\n * @return {Boolean} If true, page is at the bottom of the viewport\n */\n var isAtBottom = function () {\n if (\n Math.ceil(window.innerHeight + window.pageYOffset) >=\n getDocumentHeight()\n )\n return true;\n return false;\n };\n\n /**\n * Check if the last item should be used (even if not at the top of the page)\n * @param {Object} item The last item\n * @param {Object} settings The settings for this instantiation\n * @return {Boolean} If true, use the last item\n */\n var useLastItem = function (item, settings) {\n if (isAtBottom() && isInView(item.content, settings, true)) return true;\n return false;\n };\n\n /**\n * Get the active content\n * @param {Array} contents The content areas\n * @param {Object} settings The settings for this instantiation\n * @return {Object} The content area and matching navigation link\n */\n var getActive = function (contents, settings) {\n var last = contents[contents.length - 1];\n if (useLastItem(last, settings)) return last;\n for (var i = contents.length - 1; i >= 0; i--) {\n if (isInView(contents[i].content, settings)) return contents[i];\n }\n };\n\n /**\n * Deactivate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var deactivateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested || !nav.parentNode) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Remove the active class\n li.classList.remove(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n deactivateNested(li, settings);\n };\n\n /**\n * Deactivate a nav and content area\n * @param {Object} items The nav item and content to deactivate\n * @param {Object} settings The settings for this instantiation\n */\n var deactivate = function (items, settings) {\n // Make sure there are items to deactivate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Remove the active class from the nav and content\n li.classList.remove(settings.navClass);\n items.content.classList.remove(settings.contentClass);\n\n // Deactivate any parent navs in a nested navigation\n deactivateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeDeactivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Activate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var activateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Add the active class\n li.classList.add(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n activateNested(li, settings);\n };\n\n /**\n * Activate a nav and content area\n * @param {Object} items The nav item and content to activate\n * @param {Object} settings The settings for this instantiation\n */\n var activate = function (items, settings) {\n // Make sure there are items to activate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Add the active class to the nav and content\n li.classList.add(settings.navClass);\n items.content.classList.add(settings.contentClass);\n\n // Activate any parent navs in a nested navigation\n activateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeActivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Create the Constructor object\n * @param {String} selector The selector to use for navigation items\n * @param {Object} options User options and settings\n */\n var Constructor = function (selector, options) {\n //\n // Variables\n //\n\n var publicAPIs = {};\n var navItems, contents, current, timeout, settings;\n\n //\n // Methods\n //\n\n /**\n * Set variables from DOM elements\n */\n publicAPIs.setup = function () {\n // Get all nav items\n navItems = document.querySelectorAll(selector);\n\n // Create contents array\n contents = [];\n\n // Loop through each item, get it's matching content, and push to the array\n Array.prototype.forEach.call(navItems, function (item) {\n // Get the content for the nav item\n var content = document.getElementById(\n decodeURIComponent(item.hash.substr(1)),\n );\n if (!content) return;\n\n // Push to the contents array\n contents.push({\n nav: item,\n content: content,\n });\n });\n\n // Sort contents by the order they appear in the DOM\n sortContents(contents);\n };\n\n /**\n * Detect which content is currently active\n */\n publicAPIs.detect = function () {\n // Get the active content\n var active = getActive(contents, settings);\n\n // if there's no active content, deactivate and bail\n if (!active) {\n if (current) {\n deactivate(current, settings);\n current = null;\n }\n return;\n }\n\n // If the active content is the one currently active, do nothing\n if (current && active.content === current.content) return;\n\n // Deactivate the current content and activate the new content\n deactivate(current, settings);\n activate(active, settings);\n\n // Update the currently active content\n current = active;\n };\n\n /**\n * Detect the active content on scroll\n * Debounced for performance\n */\n var scrollHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(publicAPIs.detect);\n };\n\n /**\n * Update content sorting on resize\n * Debounced for performance\n */\n var resizeHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(function () {\n sortContents(contents);\n publicAPIs.detect();\n });\n };\n\n /**\n * Destroy the current instantiation\n */\n publicAPIs.destroy = function () {\n // Undo DOM changes\n if (current) {\n deactivate(current, settings);\n }\n\n // Remove event listeners\n window.removeEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.removeEventListener(\"resize\", resizeHandler, false);\n }\n\n // Reset variables\n contents = null;\n navItems = null;\n current = null;\n timeout = null;\n settings = null;\n };\n\n /**\n * Initialize the current instantiation\n */\n var init = function () {\n // Merge user options into defaults\n settings = extend(defaults, options || {});\n\n // Setup variables based on the current DOM\n publicAPIs.setup();\n\n // Find the currently active content\n publicAPIs.detect();\n\n // Setup event listeners\n window.addEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.addEventListener(\"resize\", resizeHandler, false);\n }\n };\n\n //\n // Initialize and return the public APIs\n //\n\n init();\n return publicAPIs;\n };\n\n //\n // Return the Constructor\n //\n\n return Constructor;\n },\n);\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import Gumshoe from \"./gumshoe-patched.js\";\n\n////////////////////////////////////////////////////////////////////////////////\n// Scroll Handling\n////////////////////////////////////////////////////////////////////////////////\nvar tocScroll = null;\nvar header = null;\nvar lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;\nconst GO_TO_TOP_OFFSET = 64;\n\nfunction scrollHandlerForHeader() {\n if (Math.floor(header.getBoundingClientRect().top) == 0) {\n header.classList.add(\"scrolled\");\n } else {\n header.classList.remove(\"scrolled\");\n }\n}\n\nfunction scrollHandlerForBackToTop(positionY) {\n if (positionY < GO_TO_TOP_OFFSET) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n } else {\n if (positionY < lastScrollTop) {\n document.documentElement.classList.add(\"show-back-to-top\");\n } else if (positionY > lastScrollTop) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n }\n }\n lastScrollTop = positionY;\n}\n\nfunction scrollHandlerForTOC(positionY) {\n if (tocScroll === null) {\n return;\n }\n\n // top of page.\n if (positionY == 0) {\n tocScroll.scrollTo(0, 0);\n } else if (\n // bottom of page.\n Math.ceil(positionY) >=\n Math.floor(document.documentElement.scrollHeight - window.innerHeight)\n ) {\n tocScroll.scrollTo(0, tocScroll.scrollHeight);\n } else {\n // somewhere in the middle.\n const current = document.querySelector(\".scroll-current\");\n if (current == null) {\n return;\n }\n\n // https://github.com/pypa/pip/issues/9159 This breaks scroll behaviours.\n // // scroll the currently \"active\" heading in toc, into view.\n // const rect = current.getBoundingClientRect();\n // if (0 > rect.top) {\n // current.scrollIntoView(true); // the argument is \"alignTop\"\n // } else if (rect.bottom > window.innerHeight) {\n // current.scrollIntoView(false);\n // }\n }\n}\n\nfunction scrollHandler(positionY) {\n scrollHandlerForHeader();\n scrollHandlerForBackToTop(positionY);\n scrollHandlerForTOC(positionY);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Theme Toggle\n////////////////////////////////////////////////////////////////////////////////\nfunction setTheme(mode) {\n if (mode !== \"light\" && mode !== \"dark\" && mode !== \"auto\") {\n console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);\n mode = \"auto\";\n }\n\n document.body.dataset.theme = mode;\n localStorage.setItem(\"theme\", mode);\n console.log(`Changed to ${mode} mode.`);\n}\n\nfunction cycleThemeOnce() {\n const currentTheme = localStorage.getItem(\"theme\") || \"auto\";\n const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\n if (prefersDark) {\n // Auto (dark) -> Light -> Dark\n if (currentTheme === \"auto\") {\n setTheme(\"light\");\n } else if (currentTheme == \"light\") {\n setTheme(\"dark\");\n } else {\n setTheme(\"auto\");\n }\n } else {\n // Auto (light) -> Dark -> Light\n if (currentTheme === \"auto\") {\n setTheme(\"dark\");\n } else if (currentTheme == \"dark\") {\n setTheme(\"light\");\n } else {\n setTheme(\"auto\");\n }\n }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Setup\n////////////////////////////////////////////////////////////////////////////////\nfunction setupScrollHandler() {\n // Taken from https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event\n let last_known_scroll_position = 0;\n let ticking = false;\n\n window.addEventListener(\"scroll\", function (e) {\n last_known_scroll_position = window.scrollY;\n\n if (!ticking) {\n window.requestAnimationFrame(function () {\n scrollHandler(last_known_scroll_position);\n ticking = false;\n });\n\n ticking = true;\n }\n });\n window.scroll();\n}\n\nfunction setupScrollSpy() {\n if (tocScroll === null) {\n return;\n }\n\n // Scrollspy -- highlight table on contents, based on scroll\n new Gumshoe(\".toc-tree a\", {\n reflow: true,\n recursive: true,\n navClass: \"scroll-current\",\n offset: () => {\n let rem = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return header.getBoundingClientRect().height + 0.5 * rem + 1;\n },\n });\n}\n\nfunction setupTheme() {\n // Attach event handlers for toggling themes\n const buttons = document.getElementsByClassName(\"theme-toggle\");\n Array.from(buttons).forEach((btn) => {\n btn.addEventListener(\"click\", cycleThemeOnce);\n });\n}\n\nfunction setup() {\n setupTheme();\n setupScrollHandler();\n setupScrollSpy();\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Main entrypoint\n////////////////////////////////////////////////////////////////////////////////\nfunction main() {\n document.body.parentNode.classList.remove(\"no-js\");\n\n header = document.querySelector(\"header\");\n tocScroll = document.querySelector(\".toc-scroll\");\n\n setup();\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", main);\n"],"names":["root","g","window","this","defaults","navClass","contentClass","nested","nestedClass","offset","reflow","events","emitEvent","type","elem","detail","settings","event","CustomEvent","bubbles","cancelable","dispatchEvent","getOffsetTop","location","offsetParent","offsetTop","sortContents","contents","sort","item1","item2","content","isInView","bottom","bounds","getBoundingClientRect","parseFloat","getOffset","parseInt","innerHeight","document","documentElement","clientHeight","top","isAtBottom","Math","ceil","pageYOffset","max","body","scrollHeight","offsetHeight","getActive","last","length","item","useLastItem","i","deactivateNested","nav","parentNode","li","closest","classList","remove","deactivate","items","link","activateNested","add","selector","options","navItems","current","timeout","publicAPIs","querySelectorAll","Array","prototype","forEach","call","getElementById","decodeURIComponent","hash","substr","push","active","activate","scrollHandler","cancelAnimationFrame","requestAnimationFrame","detect","resizeHandler","destroy","removeEventListener","merged","arguments","obj","key","hasOwnProperty","extend","setup","addEventListener","factory","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","n","getter","__esModule","d","a","definition","o","Object","defineProperty","enumerable","get","globalThis","Function","e","prop","tocScroll","header","lastScrollTop","scrollTop","GO_TO_TOP_OFFSET","cycleThemeOnce","currentTheme","localStorage","getItem","mode","matchMedia","matches","console","error","dataset","theme","setItem","log","buttons","getElementsByClassName","from","btn","setupTheme","last_known_scroll_position","ticking","scrollY","positionY","floor","scrollHandlerForBackToTop","scrollTo","querySelector","scrollHandlerForTOC","scroll","setupScrollHandler","recursive","rem","getComputedStyle","fontSize","height"],"sourceRoot":""}
\ No newline at end of file
diff --git a/_static/searchtools.js b/_static/searchtools.js
new file mode 100644
index 000000000..7918c3fab
--- /dev/null
+++ b/_static/searchtools.js
@@ -0,0 +1,574 @@
+/*
+ * searchtools.js
+ * ~~~~~~~~~~~~~~~~
+ *
+ * Sphinx JavaScript utilities for the full-text search.
+ *
+ * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+"use strict";
+
+/**
+ * Simple result scoring code.
+ */
+if (typeof Scorer === "undefined") {
+ var Scorer = {
+ // Implement the following function to further tweak the score for each result
+ // The function takes a result array [docname, title, anchor, descr, score, filename]
+ // and returns the new score.
+ /*
+ score: result => {
+ const [docname, title, anchor, descr, score, filename] = result
+ return score
+ },
+ */
+
+ // query matches the full name of an object
+ objNameMatch: 11,
+ // or matches in the last dotted part of the object name
+ objPartialMatch: 6,
+ // Additive scores depending on the priority of the object
+ objPrio: {
+ 0: 15, // used to be importantResults
+ 1: 5, // used to be objectResults
+ 2: -5, // used to be unimportantResults
+ },
+ // Used when the priority is not in the mapping.
+ objPrioDefault: 0,
+
+ // query found in title
+ title: 15,
+ partialTitle: 7,
+ // query found in terms
+ term: 5,
+ partialTerm: 2,
+ };
+}
+
+const _removeChildren = (element) => {
+ while (element && element.lastChild) element.removeChild(element.lastChild);
+};
+
+/**
+ * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
+ */
+const _escapeRegExp = (string) =>
+ string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
+
+const _displayItem = (item, searchTerms, highlightTerms) => {
+ const docBuilder = DOCUMENTATION_OPTIONS.BUILDER;
+ const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX;
+ const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX;
+ const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY;
+ const contentRoot = document.documentElement.dataset.content_root;
+
+ const [docName, title, anchor, descr, score, _filename] = item;
+
+ let listItem = document.createElement("li");
+ let requestUrl;
+ let linkUrl;
+ if (docBuilder === "dirhtml") {
+ // dirhtml builder
+ let dirname = docName + "/";
+ if (dirname.match(/\/index\/$/))
+ dirname = dirname.substring(0, dirname.length - 6);
+ else if (dirname === "index/") dirname = "";
+ requestUrl = contentRoot + dirname;
+ linkUrl = requestUrl;
+ } else {
+ // normal html builders
+ requestUrl = contentRoot + docName + docFileSuffix;
+ linkUrl = docName + docLinkSuffix;
+ }
+ let linkEl = listItem.appendChild(document.createElement("a"));
+ linkEl.href = linkUrl + anchor;
+ linkEl.dataset.score = score;
+ linkEl.innerHTML = title;
+ if (descr) {
+ listItem.appendChild(document.createElement("span")).innerHTML =
+ " (" + descr + ")";
+ // highlight search terms in the description
+ if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js
+ highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted"));
+ }
+ else if (showSearchSummary)
+ fetch(requestUrl)
+ .then((responseData) => responseData.text())
+ .then((data) => {
+ if (data)
+ listItem.appendChild(
+ Search.makeSearchSummary(data, searchTerms)
+ );
+ // highlight search terms in the summary
+ if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js
+ highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted"));
+ });
+ Search.output.appendChild(listItem);
+};
+const _finishSearch = (resultCount) => {
+ Search.stopPulse();
+ Search.title.innerText = _("Search Results");
+ if (!resultCount)
+ Search.status.innerText = Documentation.gettext(
+ "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories."
+ );
+ else
+ Search.status.innerText = _(
+ `Search finished, found ${resultCount} page(s) matching the search query.`
+ );
+};
+const _displayNextItem = (
+ results,
+ resultCount,
+ searchTerms,
+ highlightTerms,
+) => {
+ // results left, load the summary and display it
+ // this is intended to be dynamic (don't sub resultsCount)
+ if (results.length) {
+ _displayItem(results.pop(), searchTerms, highlightTerms);
+ setTimeout(
+ () => _displayNextItem(results, resultCount, searchTerms, highlightTerms),
+ 5
+ );
+ }
+ // search finished, update title and status message
+ else _finishSearch(resultCount);
+};
+
+/**
+ * Default splitQuery function. Can be overridden in ``sphinx.search`` with a
+ * custom function per language.
+ *
+ * The regular expression works by splitting the string on consecutive characters
+ * that are not Unicode letters, numbers, underscores, or emoji characters.
+ * This is the same as ``\W+`` in Python, preserving the surrogate pair area.
+ */
+if (typeof splitQuery === "undefined") {
+ var splitQuery = (query) => query
+ .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu)
+ .filter(term => term) // remove remaining empty strings
+}
+
+/**
+ * Search Module
+ */
+const Search = {
+ _index: null,
+ _queued_query: null,
+ _pulse_status: -1,
+
+ htmlToText: (htmlString) => {
+ const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html');
+ htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() });
+ const docContent = htmlElement.querySelector('[role="main"]');
+ if (docContent !== undefined) return docContent.textContent;
+ console.warn(
+ "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template."
+ );
+ return "";
+ },
+
+ init: () => {
+ const query = new URLSearchParams(window.location.search).get("q");
+ document
+ .querySelectorAll('input[name="q"]')
+ .forEach((el) => (el.value = query));
+ if (query) Search.performSearch(query);
+ },
+
+ loadIndex: (url) =>
+ (document.body.appendChild(document.createElement("script")).src = url),
+
+ setIndex: (index) => {
+ Search._index = index;
+ if (Search._queued_query !== null) {
+ const query = Search._queued_query;
+ Search._queued_query = null;
+ Search.query(query);
+ }
+ },
+
+ hasIndex: () => Search._index !== null,
+
+ deferQuery: (query) => (Search._queued_query = query),
+
+ stopPulse: () => (Search._pulse_status = -1),
+
+ startPulse: () => {
+ if (Search._pulse_status >= 0) return;
+
+ const pulse = () => {
+ Search._pulse_status = (Search._pulse_status + 1) % 4;
+ Search.dots.innerText = ".".repeat(Search._pulse_status);
+ if (Search._pulse_status >= 0) window.setTimeout(pulse, 500);
+ };
+ pulse();
+ },
+
+ /**
+ * perform a search for something (or wait until index is loaded)
+ */
+ performSearch: (query) => {
+ // create the required interface elements
+ const searchText = document.createElement("h2");
+ searchText.textContent = _("Searching");
+ const searchSummary = document.createElement("p");
+ searchSummary.classList.add("search-summary");
+ searchSummary.innerText = "";
+ const searchList = document.createElement("ul");
+ searchList.classList.add("search");
+
+ const out = document.getElementById("search-results");
+ Search.title = out.appendChild(searchText);
+ Search.dots = Search.title.appendChild(document.createElement("span"));
+ Search.status = out.appendChild(searchSummary);
+ Search.output = out.appendChild(searchList);
+
+ const searchProgress = document.getElementById("search-progress");
+ // Some themes don't use the search progress node
+ if (searchProgress) {
+ searchProgress.innerText = _("Preparing search...");
+ }
+ Search.startPulse();
+
+ // index already loaded, the browser was quick!
+ if (Search.hasIndex()) Search.query(query);
+ else Search.deferQuery(query);
+ },
+
+ /**
+ * execute search (requires search index to be loaded)
+ */
+ query: (query) => {
+ const filenames = Search._index.filenames;
+ const docNames = Search._index.docnames;
+ const titles = Search._index.titles;
+ const allTitles = Search._index.alltitles;
+ const indexEntries = Search._index.indexentries;
+
+ // stem the search terms and add them to the correct list
+ const stemmer = new Stemmer();
+ const searchTerms = new Set();
+ const excludedTerms = new Set();
+ const highlightTerms = new Set();
+ const objectTerms = new Set(splitQuery(query.toLowerCase().trim()));
+ splitQuery(query.trim()).forEach((queryTerm) => {
+ const queryTermLower = queryTerm.toLowerCase();
+
+ // maybe skip this "word"
+ // stopwords array is from language_data.js
+ if (
+ stopwords.indexOf(queryTermLower) !== -1 ||
+ queryTerm.match(/^\d+$/)
+ )
+ return;
+
+ // stem the word
+ let word = stemmer.stemWord(queryTermLower);
+ // select the correct list
+ if (word[0] === "-") excludedTerms.add(word.substr(1));
+ else {
+ searchTerms.add(word);
+ highlightTerms.add(queryTermLower);
+ }
+ });
+
+ if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js
+ localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" "))
+ }
+
+ // console.debug("SEARCH: searching for:");
+ // console.info("required: ", [...searchTerms]);
+ // console.info("excluded: ", [...excludedTerms]);
+
+ // array of [docname, title, anchor, descr, score, filename]
+ let results = [];
+ _removeChildren(document.getElementById("search-progress"));
+
+ const queryLower = query.toLowerCase();
+ for (const [title, foundTitles] of Object.entries(allTitles)) {
+ if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) {
+ for (const [file, id] of foundTitles) {
+ let score = Math.round(100 * queryLower.length / title.length)
+ results.push([
+ docNames[file],
+ titles[file] !== title ? `${titles[file]} > ${title}` : title,
+ id !== null ? "#" + id : "",
+ null,
+ score,
+ filenames[file],
+ ]);
+ }
+ }
+ }
+
+ // search for explicit entries in index directives
+ for (const [entry, foundEntries] of Object.entries(indexEntries)) {
+ if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) {
+ for (const [file, id] of foundEntries) {
+ let score = Math.round(100 * queryLower.length / entry.length)
+ results.push([
+ docNames[file],
+ titles[file],
+ id ? "#" + id : "",
+ null,
+ score,
+ filenames[file],
+ ]);
+ }
+ }
+ }
+
+ // lookup as object
+ objectTerms.forEach((term) =>
+ results.push(...Search.performObjectSearch(term, objectTerms))
+ );
+
+ // lookup as search terms in fulltext
+ results.push(...Search.performTermsSearch(searchTerms, excludedTerms));
+
+ // let the scorer override scores with a custom scoring function
+ if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item)));
+
+ // now sort the results by score (in opposite order of appearance, since the
+ // display function below uses pop() to retrieve items) and then
+ // alphabetically
+ results.sort((a, b) => {
+ const leftScore = a[4];
+ const rightScore = b[4];
+ if (leftScore === rightScore) {
+ // same score: sort alphabetically
+ const leftTitle = a[1].toLowerCase();
+ const rightTitle = b[1].toLowerCase();
+ if (leftTitle === rightTitle) return 0;
+ return leftTitle > rightTitle ? -1 : 1; // inverted is intentional
+ }
+ return leftScore > rightScore ? 1 : -1;
+ });
+
+ // remove duplicate search results
+ // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept
+ let seen = new Set();
+ results = results.reverse().reduce((acc, result) => {
+ let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(',');
+ if (!seen.has(resultStr)) {
+ acc.push(result);
+ seen.add(resultStr);
+ }
+ return acc;
+ }, []);
+
+ results = results.reverse();
+
+ // for debugging
+ //Search.lastresults = results.slice(); // a copy
+ // console.info("search results:", Search.lastresults);
+
+ // print the results
+ _displayNextItem(results, results.length, searchTerms, highlightTerms);
+ },
+
+ /**
+ * search for object names
+ */
+ performObjectSearch: (object, objectTerms) => {
+ const filenames = Search._index.filenames;
+ const docNames = Search._index.docnames;
+ const objects = Search._index.objects;
+ const objNames = Search._index.objnames;
+ const titles = Search._index.titles;
+
+ const results = [];
+
+ const objectSearchCallback = (prefix, match) => {
+ const name = match[4]
+ const fullname = (prefix ? prefix + "." : "") + name;
+ const fullnameLower = fullname.toLowerCase();
+ if (fullnameLower.indexOf(object) < 0) return;
+
+ let score = 0;
+ const parts = fullnameLower.split(".");
+
+ // check for different match types: exact matches of full name or
+ // "last name" (i.e. last dotted part)
+ if (fullnameLower === object || parts.slice(-1)[0] === object)
+ score += Scorer.objNameMatch;
+ else if (parts.slice(-1)[0].indexOf(object) > -1)
+ score += Scorer.objPartialMatch; // matches in last name
+
+ const objName = objNames[match[1]][2];
+ const title = titles[match[0]];
+
+ // If more than one term searched for, we require other words to be
+ // found in the name/title/description
+ const otherTerms = new Set(objectTerms);
+ otherTerms.delete(object);
+ if (otherTerms.size > 0) {
+ const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase();
+ if (
+ [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0)
+ )
+ return;
+ }
+
+ let anchor = match[3];
+ if (anchor === "") anchor = fullname;
+ else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname;
+
+ const descr = objName + _(", in ") + title;
+
+ // add custom score for some objects according to scorer
+ if (Scorer.objPrio.hasOwnProperty(match[2]))
+ score += Scorer.objPrio[match[2]];
+ else score += Scorer.objPrioDefault;
+
+ results.push([
+ docNames[match[0]],
+ fullname,
+ "#" + anchor,
+ descr,
+ score,
+ filenames[match[0]],
+ ]);
+ };
+ Object.keys(objects).forEach((prefix) =>
+ objects[prefix].forEach((array) =>
+ objectSearchCallback(prefix, array)
+ )
+ );
+ return results;
+ },
+
+ /**
+ * search for full-text terms in the index
+ */
+ performTermsSearch: (searchTerms, excludedTerms) => {
+ // prepare search
+ const terms = Search._index.terms;
+ const titleTerms = Search._index.titleterms;
+ const filenames = Search._index.filenames;
+ const docNames = Search._index.docnames;
+ const titles = Search._index.titles;
+
+ const scoreMap = new Map();
+ const fileMap = new Map();
+
+ // perform the search on the required terms
+ searchTerms.forEach((word) => {
+ const files = [];
+ const arr = [
+ { files: terms[word], score: Scorer.term },
+ { files: titleTerms[word], score: Scorer.title },
+ ];
+ // add support for partial matches
+ if (word.length > 2) {
+ const escapedWord = _escapeRegExp(word);
+ Object.keys(terms).forEach((term) => {
+ if (term.match(escapedWord) && !terms[word])
+ arr.push({ files: terms[term], score: Scorer.partialTerm });
+ });
+ Object.keys(titleTerms).forEach((term) => {
+ if (term.match(escapedWord) && !titleTerms[word])
+ arr.push({ files: titleTerms[word], score: Scorer.partialTitle });
+ });
+ }
+
+ // no match but word was a required one
+ if (arr.every((record) => record.files === undefined)) return;
+
+ // found search word in contents
+ arr.forEach((record) => {
+ if (record.files === undefined) return;
+
+ let recordFiles = record.files;
+ if (recordFiles.length === undefined) recordFiles = [recordFiles];
+ files.push(...recordFiles);
+
+ // set score for the word in each file
+ recordFiles.forEach((file) => {
+ if (!scoreMap.has(file)) scoreMap.set(file, {});
+ scoreMap.get(file)[word] = record.score;
+ });
+ });
+
+ // create the mapping
+ files.forEach((file) => {
+ if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1)
+ fileMap.get(file).push(word);
+ else fileMap.set(file, [word]);
+ });
+ });
+
+ // now check if the files don't contain excluded terms
+ const results = [];
+ for (const [file, wordList] of fileMap) {
+ // check if all requirements are matched
+
+ // as search terms with length < 3 are discarded
+ const filteredTermCount = [...searchTerms].filter(
+ (term) => term.length > 2
+ ).length;
+ if (
+ wordList.length !== searchTerms.size &&
+ wordList.length !== filteredTermCount
+ )
+ continue;
+
+ // ensure that none of the excluded terms is in the search result
+ if (
+ [...excludedTerms].some(
+ (term) =>
+ terms[term] === file ||
+ titleTerms[term] === file ||
+ (terms[term] || []).includes(file) ||
+ (titleTerms[term] || []).includes(file)
+ )
+ )
+ break;
+
+ // select one (max) score for the file.
+ const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w]));
+ // add result to the result list
+ results.push([
+ docNames[file],
+ titles[file],
+ "",
+ null,
+ score,
+ filenames[file],
+ ]);
+ }
+ return results;
+ },
+
+ /**
+ * helper function to return a node containing the
+ * search summary for a given text. keywords is a list
+ * of stemmed words.
+ */
+ makeSearchSummary: (htmlText, keywords) => {
+ const text = Search.htmlToText(htmlText);
+ if (text === "") return null;
+
+ const textLower = text.toLowerCase();
+ const actualStartPosition = [...keywords]
+ .map((k) => textLower.indexOf(k.toLowerCase()))
+ .filter((i) => i > -1)
+ .slice(-1)[0];
+ const startWithContext = Math.max(actualStartPosition - 120, 0);
+
+ const top = startWithContext === 0 ? "" : "...";
+ const tail = startWithContext + 240 < text.length ? "..." : "";
+
+ let summary = document.createElement("p");
+ summary.classList.add("context");
+ summary.textContent = top + text.substr(startWithContext, 240).trim() + tail;
+
+ return summary;
+ },
+};
+
+_ready(Search.init);
diff --git a/_static/skeleton.css b/_static/skeleton.css
new file mode 100644
index 000000000..467c878c6
--- /dev/null
+++ b/_static/skeleton.css
@@ -0,0 +1,296 @@
+/* Some sane resets. */
+html {
+ height: 100%;
+}
+
+body {
+ margin: 0;
+ min-height: 100%;
+}
+
+/* All the flexbox magic! */
+body,
+.sb-announcement,
+.sb-content,
+.sb-main,
+.sb-container,
+.sb-container__inner,
+.sb-article-container,
+.sb-footer-content,
+.sb-header,
+.sb-header-secondary,
+.sb-footer {
+ display: flex;
+}
+
+/* These order things vertically */
+body,
+.sb-main,
+.sb-article-container {
+ flex-direction: column;
+}
+
+/* Put elements in the center */
+.sb-header,
+.sb-header-secondary,
+.sb-container,
+.sb-content,
+.sb-footer,
+.sb-footer-content {
+ justify-content: center;
+}
+/* Put elements at the ends */
+.sb-article-container {
+ justify-content: space-between;
+}
+
+/* These elements grow. */
+.sb-main,
+.sb-content,
+.sb-container,
+article {
+ flex-grow: 1;
+}
+
+/* Because padding making this wider is not fun */
+article {
+ box-sizing: border-box;
+}
+
+/* The announcements element should never be wider than the page. */
+.sb-announcement {
+ max-width: 100%;
+}
+
+.sb-sidebar-primary,
+.sb-sidebar-secondary {
+ flex-shrink: 0;
+ width: 17rem;
+}
+
+.sb-announcement__inner {
+ justify-content: center;
+
+ box-sizing: border-box;
+ height: 3rem;
+
+ overflow-x: auto;
+ white-space: nowrap;
+}
+
+/* Sidebars, with checkbox-based toggle */
+.sb-sidebar-primary,
+.sb-sidebar-secondary {
+ position: fixed;
+ height: 100%;
+ top: 0;
+}
+
+.sb-sidebar-primary {
+ left: -17rem;
+ transition: left 250ms ease-in-out;
+}
+.sb-sidebar-secondary {
+ right: -17rem;
+ transition: right 250ms ease-in-out;
+}
+
+.sb-sidebar-toggle {
+ display: none;
+}
+.sb-sidebar-overlay {
+ position: fixed;
+ top: 0;
+ width: 0;
+ height: 0;
+
+ transition: width 0ms ease 250ms, height 0ms ease 250ms, opacity 250ms ease;
+
+ opacity: 0;
+ background-color: rgba(0, 0, 0, 0.54);
+}
+
+#sb-sidebar-toggle--primary:checked
+ ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--primary"],
+#sb-sidebar-toggle--secondary:checked
+ ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--secondary"] {
+ width: 100%;
+ height: 100%;
+ opacity: 1;
+ transition: width 0ms ease, height 0ms ease, opacity 250ms ease;
+}
+
+#sb-sidebar-toggle--primary:checked ~ .sb-container .sb-sidebar-primary {
+ left: 0;
+}
+#sb-sidebar-toggle--secondary:checked ~ .sb-container .sb-sidebar-secondary {
+ right: 0;
+}
+
+/* Full-width mode */
+.drop-secondary-sidebar-for-full-width-content
+ .hide-when-secondary-sidebar-shown {
+ display: none !important;
+}
+.drop-secondary-sidebar-for-full-width-content .sb-sidebar-secondary {
+ display: none !important;
+}
+
+/* Mobile views */
+.sb-page-width {
+ width: 100%;
+}
+
+.sb-article-container,
+.sb-footer-content__inner,
+.drop-secondary-sidebar-for-full-width-content .sb-article,
+.drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 100vw;
+}
+
+.sb-article,
+.match-content-width {
+ padding: 0 1rem;
+ box-sizing: border-box;
+}
+
+@media (min-width: 32rem) {
+ .sb-article,
+ .match-content-width {
+ padding: 0 2rem;
+ }
+}
+
+/* Tablet views */
+@media (min-width: 42rem) {
+ .sb-article-container {
+ width: auto;
+ }
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 42rem;
+ }
+ .sb-article,
+ .match-content-width {
+ width: 42rem;
+ }
+}
+@media (min-width: 46rem) {
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 46rem;
+ }
+ .sb-article,
+ .match-content-width {
+ width: 46rem;
+ }
+}
+@media (min-width: 50rem) {
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 50rem;
+ }
+ .sb-article,
+ .match-content-width {
+ width: 50rem;
+ }
+}
+
+/* Tablet views */
+@media (min-width: 59rem) {
+ .sb-sidebar-secondary {
+ position: static;
+ }
+ .hide-when-secondary-sidebar-shown {
+ display: none !important;
+ }
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 59rem;
+ }
+ .sb-article,
+ .match-content-width {
+ width: 42rem;
+ }
+}
+@media (min-width: 63rem) {
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 63rem;
+ }
+ .sb-article,
+ .match-content-width {
+ width: 46rem;
+ }
+}
+@media (min-width: 67rem) {
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 67rem;
+ }
+ .sb-article,
+ .match-content-width {
+ width: 50rem;
+ }
+}
+
+/* Desktop views */
+@media (min-width: 76rem) {
+ .sb-sidebar-primary {
+ position: static;
+ }
+ .hide-when-primary-sidebar-shown {
+ display: none !important;
+ }
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 59rem;
+ }
+ .sb-article,
+ .match-content-width {
+ width: 42rem;
+ }
+}
+
+/* Full desktop views */
+@media (min-width: 80rem) {
+ .sb-article,
+ .match-content-width {
+ width: 46rem;
+ }
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 63rem;
+ }
+}
+
+@media (min-width: 84rem) {
+ .sb-article,
+ .match-content-width {
+ width: 50rem;
+ }
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 67rem;
+ }
+}
+
+@media (min-width: 88rem) {
+ .sb-footer-content__inner,
+ .drop-secondary-sidebar-for-full-width-content .sb-article,
+ .drop-secondary-sidebar-for-full-width-content .match-content-width {
+ width: 67rem;
+ }
+ .sb-page-width {
+ width: 88rem;
+ }
+}
diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js
new file mode 100644
index 000000000..8a96c69a1
--- /dev/null
+++ b/_static/sphinx_highlight.js
@@ -0,0 +1,154 @@
+/* Highlighting utilities for Sphinx HTML documentation. */
+"use strict";
+
+const SPHINX_HIGHLIGHT_ENABLED = true
+
+/**
+ * highlight a given string on a node by wrapping it in
+ * span elements with the given class name.
+ */
+const _highlight = (node, addItems, text, className) => {
+ if (node.nodeType === Node.TEXT_NODE) {
+ const val = node.nodeValue;
+ const parent = node.parentNode;
+ const pos = val.toLowerCase().indexOf(text);
+ if (
+ pos >= 0 &&
+ !parent.classList.contains(className) &&
+ !parent.classList.contains("nohighlight")
+ ) {
+ let span;
+
+ const closestNode = parent.closest("body, svg, foreignObject");
+ const isInSVG = closestNode && closestNode.matches("svg");
+ if (isInSVG) {
+ span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
+ } else {
+ span = document.createElement("span");
+ span.classList.add(className);
+ }
+
+ span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+ const rest = document.createTextNode(val.substr(pos + text.length));
+ parent.insertBefore(
+ span,
+ parent.insertBefore(
+ rest,
+ node.nextSibling
+ )
+ );
+ node.nodeValue = val.substr(0, pos);
+ /* There may be more occurrences of search term in this node. So call this
+ * function recursively on the remaining fragment.
+ */
+ _highlight(rest, addItems, text, className);
+
+ if (isInSVG) {
+ const rect = document.createElementNS(
+ "http://www.w3.org/2000/svg",
+ "rect"
+ );
+ const bbox = parent.getBBox();
+ rect.x.baseVal.value = bbox.x;
+ rect.y.baseVal.value = bbox.y;
+ rect.width.baseVal.value = bbox.width;
+ rect.height.baseVal.value = bbox.height;
+ rect.setAttribute("class", className);
+ addItems.push({ parent: parent, target: rect });
+ }
+ }
+ } else if (node.matches && !node.matches("button, select, textarea")) {
+ node.childNodes.forEach((el) => _highlight(el, addItems, text, className));
+ }
+};
+const _highlightText = (thisNode, text, className) => {
+ let addItems = [];
+ _highlight(thisNode, addItems, text, className);
+ addItems.forEach((obj) =>
+ obj.parent.insertAdjacentElement("beforebegin", obj.target)
+ );
+};
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+const SphinxHighlight = {
+
+ /**
+ * highlight the search words provided in localstorage in the text
+ */
+ highlightSearchWords: () => {
+ if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight
+
+ // get and clear terms from localstorage
+ const url = new URL(window.location);
+ const highlight =
+ localStorage.getItem("sphinx_highlight_terms")
+ || url.searchParams.get("highlight")
+ || "";
+ localStorage.removeItem("sphinx_highlight_terms")
+ url.searchParams.delete("highlight");
+ window.history.replaceState({}, "", url);
+
+ // get individual terms from highlight string
+ const terms = highlight.toLowerCase().split(/\s+/).filter(x => x);
+ if (terms.length === 0) return; // nothing to do
+
+ // There should never be more than one element matching "div.body"
+ const divBody = document.querySelectorAll("div.body");
+ const body = divBody.length ? divBody[0] : document.querySelector("body");
+ window.setTimeout(() => {
+ terms.forEach((term) => _highlightText(body, term, "highlighted"));
+ }, 10);
+
+ const searchBox = document.getElementById("searchbox");
+ if (searchBox === null) return;
+ searchBox.appendChild(
+ document
+ .createRange()
+ .createContextualFragment(
+ ' ' +
+ '' +
+ _("Hide Search Matches") +
+ "
"
+ )
+ );
+ },
+
+ /**
+ * helper function to hide the search marks again
+ */
+ hideSearchWords: () => {
+ document
+ .querySelectorAll("#searchbox .highlight-link")
+ .forEach((el) => el.remove());
+ document
+ .querySelectorAll("span.highlighted")
+ .forEach((el) => el.classList.remove("highlighted"));
+ localStorage.removeItem("sphinx_highlight_terms")
+ },
+
+ initEscapeListener: () => {
+ // only install a listener if it is really needed
+ if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return;
+
+ document.addEventListener("keydown", (event) => {
+ // bail for input elements
+ if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
+ // bail with special keys
+ if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return;
+ if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) {
+ SphinxHighlight.hideSearchWords();
+ event.preventDefault();
+ }
+ });
+ },
+};
+
+_ready(() => {
+ /* Do not call highlightSearchWords() when we are on the search page.
+ * It will highlight words from the *previous* search query.
+ */
+ if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords();
+ SphinxHighlight.initEscapeListener();
+});
diff --git a/_static/styles/furo-extensions.css b/_static/styles/furo-extensions.css
new file mode 100644
index 000000000..bc447f228
--- /dev/null
+++ b/_static/styles/furo-extensions.css
@@ -0,0 +1,2 @@
+#furo-sidebar-ad-placement{padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)}#furo-sidebar-ad-placement .ethical-sidebar{background:var(--color-background-secondary);border:none;box-shadow:none}#furo-sidebar-ad-placement .ethical-sidebar:hover{background:var(--color-background-hover)}#furo-sidebar-ad-placement .ethical-sidebar a{color:var(--color-foreground-primary)}#furo-sidebar-ad-placement .ethical-callout a{color:var(--color-foreground-secondary)!important}#furo-readthedocs-versions{background:transparent;display:block;position:static;width:100%}#furo-readthedocs-versions .rst-versions{background:#1a1c1e}#furo-readthedocs-versions .rst-current-version{background:var(--color-sidebar-item-background);cursor:unset}#furo-readthedocs-versions .rst-current-version:hover{background:var(--color-sidebar-item-background)}#furo-readthedocs-versions .rst-current-version .fa-book{color:var(--color-foreground-primary)}#furo-readthedocs-versions>.rst-other-versions{padding:0}#furo-readthedocs-versions>.rst-other-versions small{opacity:1}#furo-readthedocs-versions .injected .rst-versions{position:unset}#furo-readthedocs-versions:focus-within,#furo-readthedocs-versions:hover{box-shadow:0 0 0 1px var(--color-sidebar-background-border)}#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:hover .rst-current-version{background:#1a1c1e;font-size:inherit;height:auto;line-height:inherit;padding:12px;text-align:right}#furo-readthedocs-versions:focus-within .rst-current-version .fa-book,#furo-readthedocs-versions:hover .rst-current-version .fa-book{color:#fff;float:left}#furo-readthedocs-versions:focus-within .fa-caret-down,#furo-readthedocs-versions:hover .fa-caret-down{display:none}#furo-readthedocs-versions:focus-within .injected,#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:focus-within .rst-other-versions,#furo-readthedocs-versions:hover .injected,#furo-readthedocs-versions:hover .rst-current-version,#furo-readthedocs-versions:hover .rst-other-versions{display:block}#furo-readthedocs-versions:focus-within>.rst-current-version,#furo-readthedocs-versions:hover>.rst-current-version{display:none}.highlight:hover button.copybtn{color:var(--color-code-foreground)}.highlight button.copybtn{align-items:center;background-color:var(--color-code-background);border:none;color:var(--color-background-item);cursor:pointer;height:1.25em;opacity:1;right:.5rem;top:.625rem;transition:color .3s,opacity .3s;width:1.25em}.highlight button.copybtn:hover{background-color:var(--color-code-background);color:var(--color-brand-content)}.highlight button.copybtn:after{background-color:transparent;color:var(--color-code-foreground);display:none}.highlight button.copybtn.success{color:#22863a;transition:color 0ms}.highlight button.copybtn.success:after{display:block}.highlight button.copybtn svg{padding:0}body{--sd-color-primary:var(--color-brand-primary);--sd-color-primary-highlight:var(--color-brand-content);--sd-color-primary-text:var(--color-background-primary);--sd-color-shadow:rgba(0,0,0,.05);--sd-color-card-border:var(--color-card-border);--sd-color-card-border-hover:var(--color-brand-content);--sd-color-card-background:var(--color-card-background);--sd-color-card-text:var(--color-foreground-primary);--sd-color-card-header:var(--color-card-marginals-background);--sd-color-card-footer:var(--color-card-marginals-background);--sd-color-tabs-label-active:var(--color-brand-content);--sd-color-tabs-label-hover:var(--color-foreground-muted);--sd-color-tabs-label-inactive:var(--color-foreground-muted);--sd-color-tabs-underline-active:var(--color-brand-content);--sd-color-tabs-underline-hover:var(--color-foreground-border);--sd-color-tabs-underline-inactive:var(--color-background-border);--sd-color-tabs-overline:var(--color-background-border);--sd-color-tabs-underline:var(--color-background-border)}.sd-tab-content{box-shadow:0 -2px var(--sd-color-tabs-overline),0 1px var(--sd-color-tabs-underline)}.sd-card{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)}.sd-shadow-sm{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-md{box-shadow:0 .3rem .75rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-lg{box-shadow:0 .6rem 1.5rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-card-hover:hover{transform:none}.sd-cards-carousel{gap:.25rem;padding:.25rem}body{--tabs--label-text:var(--color-foreground-muted);--tabs--label-text--hover:var(--color-foreground-muted);--tabs--label-text--active:var(--color-brand-content);--tabs--label-text--active--hover:var(--color-brand-content);--tabs--label-background:transparent;--tabs--label-background--hover:transparent;--tabs--label-background--active:transparent;--tabs--label-background--active--hover:transparent;--tabs--padding-x:0.25em;--tabs--margin-x:1em;--tabs--border:var(--color-background-border);--tabs--label-border:transparent;--tabs--label-border--hover:var(--color-foreground-muted);--tabs--label-border--active:var(--color-brand-content);--tabs--label-border--active--hover:var(--color-brand-content)}[role=main] .container{max-width:none;padding-left:0;padding-right:0}.shadow.docutils{border:none;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)!important}.sphinx-bs .card{background-color:var(--color-background-secondary);color:var(--color-foreground)}
+/*# sourceMappingURL=furo-extensions.css.map*/
\ No newline at end of file
diff --git a/_static/styles/furo-extensions.css.map b/_static/styles/furo-extensions.css.map
new file mode 100644
index 000000000..9ba5637f9
--- /dev/null
+++ b/_static/styles/furo-extensions.css.map
@@ -0,0 +1 @@
+{"version":3,"file":"styles/furo-extensions.css","mappings":"AAGA,2BACE,oFACA,4CAKE,6CAHA,YACA,eAEA,CACA,kDACE,yCAEF,8CACE,sCAEJ,8CACE,kDAEJ,2BAGE,uBACA,cAHA,gBACA,UAEA,CAGA,yCACE,mBAEF,gDAEE,gDADA,YACA,CACA,sDACE,gDACF,yDACE,sCAEJ,+CACE,UACA,qDACE,UAGF,mDACE,eAEJ,yEAEE,4DAEA,mHASE,mBAPA,kBAEA,YADA,oBAGA,aADA,gBAIA,CAEA,qIAEE,WADA,UACA,CAEJ,uGACE,aAEF,iUAGE,cAEF,mHACE,aC1EJ,gCACE,mCAEF,0BAKE,mBAUA,8CACA,YAFA,mCAKA,eAZA,cALA,UASA,YADA,YAYA,iCAdA,YAcA,CAEA,gCAEE,8CADA,gCACA,CAEF,gCAGE,6BADA,mCADA,YAEA,CAEF,kCAEE,cADA,oBACA,CACA,wCACE,cAEJ,8BACE,UC5CN,KAEE,6CAA8C,CAC9C,uDAAwD,CACxD,uDAAwD,CAGxD,iCAAsC,CAGtC,+CAAgD,CAChD,uDAAwD,CACxD,uDAAwD,CACxD,oDAAqD,CACrD,6DAA8D,CAC9D,6DAA8D,CAG9D,uDAAwD,CACxD,yDAA0D,CAC1D,4DAA6D,CAC7D,2DAA4D,CAC5D,8DAA+D,CAC/D,iEAAkE,CAClE,uDAAwD,CACxD,wDAAyD,CAG3D,gBACE,qFAGF,SACE,6EAEF,cACE,uFAEF,cACE,uFAEF,cACE,uFAGF,qBACE,eAEF,mBACE,WACA,eChDF,KACE,gDAAiD,CACjD,uDAAwD,CACxD,qDAAsD,CACtD,4DAA6D,CAC7D,oCAAqC,CACrC,2CAA4C,CAC5C,4CAA6C,CAC7C,mDAAoD,CACpD,wBAAyB,CACzB,oBAAqB,CACrB,6CAA8C,CAC9C,gCAAiC,CACjC,yDAA0D,CAC1D,uDAAwD,CACxD,8DAA+D,CCbjE,uBACE,eACA,eACA,gBAGF,iBACE,YACA,+EAGF,iBACE,mDACA","sources":["webpack:///./src/furo/assets/styles/extensions/_readthedocs.sass","webpack:///./src/furo/assets/styles/extensions/_copybutton.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-design.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-inline-tabs.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-panels.sass"],"sourcesContent":["// This file contains the styles used for tweaking how ReadTheDoc's embedded\n// contents would show up inside the theme.\n\n#furo-sidebar-ad-placement\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n .ethical-sidebar\n // Remove the border and box-shadow.\n border: none\n box-shadow: none\n // Manage the background colors.\n background: var(--color-background-secondary)\n &:hover\n background: var(--color-background-hover)\n // Ensure the text is legible.\n a\n color: var(--color-foreground-primary)\n\n .ethical-callout a\n color: var(--color-foreground-secondary) !important\n\n#furo-readthedocs-versions\n position: static\n width: 100%\n background: transparent\n display: block\n\n // Make the background color fit with the theme's aesthetic.\n .rst-versions\n background: rgb(26, 28, 30)\n\n .rst-current-version\n cursor: unset\n background: var(--color-sidebar-item-background)\n &:hover\n background: var(--color-sidebar-item-background)\n .fa-book\n color: var(--color-foreground-primary)\n\n > .rst-other-versions\n padding: 0\n small\n opacity: 1\n\n .injected\n .rst-versions\n position: unset\n\n &:hover,\n &:focus-within\n box-shadow: 0 0 0 1px var(--color-sidebar-background-border)\n\n .rst-current-version\n // Undo the tweaks done in RTD's CSS\n font-size: inherit\n line-height: inherit\n height: auto\n text-align: right\n padding: 12px\n\n // Match the rest of the body\n background: #1a1c1e\n\n .fa-book\n float: left\n color: white\n\n .fa-caret-down\n display: none\n\n .rst-current-version,\n .rst-other-versions,\n .injected\n display: block\n\n > .rst-current-version\n display: none\n",".highlight\n &:hover button.copybtn\n color: var(--color-code-foreground)\n\n button.copybtn\n // Make it visible\n opacity: 1\n\n // Align things correctly\n align-items: center\n\n height: 1.25em\n width: 1.25em\n\n top: 0.625rem // $code-spacing-vertical\n right: 0.5rem\n\n // Make it look better\n color: var(--color-background-item)\n background-color: var(--color-code-background)\n border: none\n\n // Change to cursor to make it obvious that you can click on it\n cursor: pointer\n\n // Transition smoothly, for aesthetics\n transition: color 300ms, opacity 300ms\n\n &:hover\n color: var(--color-brand-content)\n background-color: var(--color-code-background)\n\n &::after\n display: none\n color: var(--color-code-foreground)\n background-color: transparent\n\n &.success\n transition: color 0ms\n color: #22863a\n &::after\n display: block\n\n svg\n padding: 0\n","body\n // Colors\n --sd-color-primary: var(--color-brand-primary)\n --sd-color-primary-highlight: var(--color-brand-content)\n --sd-color-primary-text: var(--color-background-primary)\n\n // Shadows\n --sd-color-shadow: rgba(0, 0, 0, 0.05)\n\n // Cards\n --sd-color-card-border: var(--color-card-border)\n --sd-color-card-border-hover: var(--color-brand-content)\n --sd-color-card-background: var(--color-card-background)\n --sd-color-card-text: var(--color-foreground-primary)\n --sd-color-card-header: var(--color-card-marginals-background)\n --sd-color-card-footer: var(--color-card-marginals-background)\n\n // Tabs\n --sd-color-tabs-label-active: var(--color-brand-content)\n --sd-color-tabs-label-hover: var(--color-foreground-muted)\n --sd-color-tabs-label-inactive: var(--color-foreground-muted)\n --sd-color-tabs-underline-active: var(--color-brand-content)\n --sd-color-tabs-underline-hover: var(--color-foreground-border)\n --sd-color-tabs-underline-inactive: var(--color-background-border)\n --sd-color-tabs-overline: var(--color-background-border)\n --sd-color-tabs-underline: var(--color-background-border)\n\n// Tabs\n.sd-tab-content\n box-shadow: 0 -2px var(--sd-color-tabs-overline), 0 1px var(--sd-color-tabs-underline)\n\n// Shadows\n.sd-card // Have a shadow by default\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n.sd-shadow-sm\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-md\n box-shadow: 0 0.3rem 0.75rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-lg\n box-shadow: 0 0.6rem 1.5rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Cards\n.sd-card-hover:hover // Don't change scale on hover\n transform: none\n\n.sd-cards-carousel // Have a bit of gap in the carousel by default\n gap: 0.25rem\n padding: 0.25rem\n","// This file contains styles to tweak sphinx-inline-tabs to work well with Furo.\n\nbody\n --tabs--label-text: var(--color-foreground-muted)\n --tabs--label-text--hover: var(--color-foreground-muted)\n --tabs--label-text--active: var(--color-brand-content)\n --tabs--label-text--active--hover: var(--color-brand-content)\n --tabs--label-background: transparent\n --tabs--label-background--hover: transparent\n --tabs--label-background--active: transparent\n --tabs--label-background--active--hover: transparent\n --tabs--padding-x: 0.25em\n --tabs--margin-x: 1em\n --tabs--border: var(--color-background-border)\n --tabs--label-border: transparent\n --tabs--label-border--hover: var(--color-foreground-muted)\n --tabs--label-border--active: var(--color-brand-content)\n --tabs--label-border--active--hover: var(--color-brand-content)\n","// This file contains styles to tweak sphinx-panels to work well with Furo.\n\n// sphinx-panels includes Bootstrap 4, which uses .container which can conflict\n// with docutils' `.. container::` directive.\n[role=\"main\"] .container\n max-width: initial\n padding-left: initial\n padding-right: initial\n\n// Make the panels look nicer!\n.shadow.docutils\n border: none\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Make panel colors respond to dark mode\n.sphinx-bs .card\n background-color: var(--color-background-secondary)\n color: var(--color-foreground)\n"],"names":[],"sourceRoot":""}
\ No newline at end of file
diff --git a/_static/styles/furo.css b/_static/styles/furo.css
new file mode 100644
index 000000000..3d29a218f
--- /dev/null
+++ b/_static/styles/furo.css
@@ -0,0 +1,2 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{-webkit-text-size-adjust:100%;line-height:1.15}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}@media print{.content-icon-container,.headerlink,.mobile-header,.related-pages{display:none!important}.highlight{border:.1pt solid var(--color-foreground-border)}a,blockquote,dl,ol,pre,table,ul{page-break-inside:avoid}caption,figure,h1,h2,h3,h4,h5,h6,img{page-break-after:avoid;page-break-inside:avoid}dl,ol,ul{page-break-before:avoid}}.visually-hidden{clip:rect(0,0,0,0)!important;border:0!important;height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:1px!important}:-moz-focusring{outline:auto}body{--font-stack:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;--font-stack--monospace:"SFMono-Regular",Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace;--font-size--normal:100%;--font-size--small:87.5%;--font-size--small--2:81.25%;--font-size--small--3:75%;--font-size--small--4:62.5%;--sidebar-caption-font-size:var(--font-size--small--2);--sidebar-item-font-size:var(--font-size--small);--sidebar-search-input-font-size:var(--font-size--small);--toc-font-size:var(--font-size--small--3);--toc-font-size--mobile:var(--font-size--normal);--toc-title-font-size:var(--font-size--small--4);--admonition-font-size:0.8125rem;--admonition-title-font-size:0.8125rem;--code-font-size:var(--font-size--small--2);--api-font-size:var(--font-size--small);--header-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*4);--header-padding:0.5rem;--sidebar-tree-space-above:1.5rem;--sidebar-caption-space-above:1rem;--sidebar-item-line-height:1rem;--sidebar-item-spacing-vertical:0.5rem;--sidebar-item-spacing-horizontal:1rem;--sidebar-item-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*2);--sidebar-expander-width:var(--sidebar-item-height);--sidebar-search-space-above:0.5rem;--sidebar-search-input-spacing-vertical:0.5rem;--sidebar-search-input-spacing-horizontal:0.5rem;--sidebar-search-input-height:1rem;--sidebar-search-icon-size:var(--sidebar-search-input-height);--toc-title-padding:0.25rem 0;--toc-spacing-vertical:1.5rem;--toc-spacing-horizontal:1.5rem;--toc-item-spacing-vertical:0.4rem;--toc-item-spacing-horizontal:1rem;--icon-search:url('data:image/svg+xml;charset=utf-8, ');--icon-pencil:url('data:image/svg+xml;charset=utf-8, ');--icon-abstract:url('data:image/svg+xml;charset=utf-8, ');--icon-info:url('data:image/svg+xml;charset=utf-8, ');--icon-flame:url('data:image/svg+xml;charset=utf-8, ');--icon-question:url('data:image/svg+xml;charset=utf-8, ');--icon-warning:url('data:image/svg+xml;charset=utf-8, ');--icon-failure:url('data:image/svg+xml;charset=utf-8, ');--icon-spark:url('data:image/svg+xml;charset=utf-8, ');--color-admonition-title--caution:#ff9100;--color-admonition-title-background--caution:rgba(255,145,0,.2);--color-admonition-title--warning:#ff9100;--color-admonition-title-background--warning:rgba(255,145,0,.2);--color-admonition-title--danger:#ff5252;--color-admonition-title-background--danger:rgba(255,82,82,.2);--color-admonition-title--attention:#ff5252;--color-admonition-title-background--attention:rgba(255,82,82,.2);--color-admonition-title--error:#ff5252;--color-admonition-title-background--error:rgba(255,82,82,.2);--color-admonition-title--hint:#00c852;--color-admonition-title-background--hint:rgba(0,200,82,.2);--color-admonition-title--tip:#00c852;--color-admonition-title-background--tip:rgba(0,200,82,.2);--color-admonition-title--important:#00bfa5;--color-admonition-title-background--important:rgba(0,191,165,.2);--color-admonition-title--note:#00b0ff;--color-admonition-title-background--note:rgba(0,176,255,.2);--color-admonition-title--seealso:#448aff;--color-admonition-title-background--seealso:rgba(68,138,255,.2);--color-admonition-title--admonition-todo:grey;--color-admonition-title-background--admonition-todo:hsla(0,0%,50%,.2);--color-admonition-title:#651fff;--color-admonition-title-background:rgba(101,31,255,.2);--icon-admonition-default:var(--icon-abstract);--color-topic-title:#14b8a6;--color-topic-title-background:rgba(20,184,166,.2);--icon-topic-default:var(--icon-pencil);--color-problematic:#b30000;--color-foreground-primary:#000;--color-foreground-secondary:#5a5c63;--color-foreground-muted:#646776;--color-foreground-border:#878787;--color-background-primary:#fff;--color-background-secondary:#f8f9fb;--color-background-hover:#efeff4;--color-background-hover--transparent:#efeff400;--color-background-border:#eeebee;--color-background-item:#ccc;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#2962ff;--color-brand-content:#2a5adf;--color-api-background:var(--color-background-hover--transparent);--color-api-background-hover:var(--color-background-hover);--color-api-overall:var(--color-foreground-secondary);--color-api-name:var(--color-problematic);--color-api-pre-name:var(--color-problematic);--color-api-paren:var(--color-foreground-secondary);--color-api-keyword:var(--color-foreground-primary);--color-highlight-on-target:#ffc;--color-inline-code-background:var(--color-background-secondary);--color-highlighted-background:#def;--color-highlighted-text:var(--color-foreground-primary);--color-guilabel-background:#ddeeff80;--color-guilabel-border:#bedaf580;--color-guilabel-text:var(--color-foreground-primary);--color-admonition-background:transparent;--color-table-header-background:var(--color-background-secondary);--color-table-border:var(--color-background-border);--color-card-border:var(--color-background-secondary);--color-card-background:transparent;--color-card-marginals-background:var(--color-background-secondary);--color-header-background:var(--color-background-primary);--color-header-border:var(--color-background-border);--color-header-text:var(--color-foreground-primary);--color-sidebar-background:var(--color-background-secondary);--color-sidebar-background-border:var(--color-background-border);--color-sidebar-brand-text:var(--color-foreground-primary);--color-sidebar-caption-text:var(--color-foreground-muted);--color-sidebar-link-text:var(--color-foreground-secondary);--color-sidebar-link-text--top-level:var(--color-brand-primary);--color-sidebar-item-background:var(--color-sidebar-background);--color-sidebar-item-background--current:var( --color-sidebar-item-background );--color-sidebar-item-background--hover:linear-gradient(90deg,var(--color-background-hover--transparent) 0%,var(--color-background-hover) var(--sidebar-item-spacing-horizontal),var(--color-background-hover) 100%);--color-sidebar-item-expander-background:transparent;--color-sidebar-item-expander-background--hover:var( --color-background-hover );--color-sidebar-search-text:var(--color-foreground-primary);--color-sidebar-search-background:var(--color-background-secondary);--color-sidebar-search-background--focus:var(--color-background-primary);--color-sidebar-search-border:var(--color-background-border);--color-sidebar-search-icon:var(--color-foreground-muted);--color-toc-background:var(--color-background-primary);--color-toc-title-text:var(--color-foreground-muted);--color-toc-item-text:var(--color-foreground-secondary);--color-toc-item-text--hover:var(--color-foreground-primary);--color-toc-item-text--active:var(--color-brand-primary);--color-content-foreground:var(--color-foreground-primary);--color-content-background:transparent;--color-link:var(--color-brand-content);--color-link--hover:var(--color-brand-content);--color-link-underline:var(--color-background-border);--color-link-underline--hover:var(--color-foreground-border)}.only-light{display:block!important}html body .only-dark{display:none!important}@media not print{body[data-theme=dark]{--color-problematic:#ee5151;--color-foreground-primary:#ffffffcc;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#2b8cee;--color-brand-content:#368ce2;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body[data-theme=dark] .only-light{display:none!important}body[data-theme=dark] .only-dark{display:block!important}@media(prefers-color-scheme:dark){body:not([data-theme=light]){--color-problematic:#ee5151;--color-foreground-primary:#ffffffcc;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#2b8cee;--color-brand-content:#368ce2;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body:not([data-theme=light]) .only-light{display:none!important}body:not([data-theme=light]) .only-dark{display:block!important}}}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto,body[data-theme=dark] .theme-toggle svg.theme-icon-when-dark,body[data-theme=light] .theme-toggle svg.theme-icon-when-light{display:block}body{font-family:var(--font-stack)}code,kbd,pre,samp{font-family:var(--font-stack--monospace)}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}article{line-height:1.5}h1,h2,h3,h4,h5,h6{border-radius:.5rem;font-weight:700;line-height:1.25;margin:.5rem -.5rem;padding-left:.5rem;padding-right:.5rem}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p{margin-top:0}h1{font-size:2.5em;margin-bottom:1rem}h1,h2{margin-top:1.75rem}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.25em}h5{font-size:1.125em}h6{font-size:1em}small{font-size:80%;opacity:75%}p{margin-bottom:.75rem;margin-top:.5rem}hr.docutils{background-color:var(--color-background-border);border:0;height:1px;margin:2rem 0;padding:0}.centered{text-align:center}a{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}a:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link{color:inherit}a.muted-link:hover{color:var(--color-link);text-decoration-color:var(--color-link-underline--hover)}html{overflow-x:hidden;overflow-y:scroll;scroll-behavior:smooth}.sidebar-scroll,.toc-scroll,article[role=main] *{scrollbar-color:var(--color-foreground-border) transparent;scrollbar-width:thin}.sidebar-scroll::-webkit-scrollbar,.toc-scroll::-webkit-scrollbar,article[role=main] ::-webkit-scrollbar{height:.25rem;width:.25rem}.sidebar-scroll::-webkit-scrollbar-thumb,.toc-scroll::-webkit-scrollbar-thumb,article[role=main] ::-webkit-scrollbar-thumb{background-color:var(--color-foreground-border);border-radius:.125rem}body,html{background:var(--color-background-primary);color:var(--color-foreground-primary);height:100%}article{background:var(--color-content-background);color:var(--color-content-foreground);overflow-wrap:break-word}.page{display:flex;min-height:100%}.mobile-header{background-color:var(--color-header-background);border-bottom:1px solid var(--color-header-border);color:var(--color-header-text);display:none;height:var(--header-height);width:100%;z-index:10}.mobile-header.scrolled{border-bottom:none;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2)}.mobile-header .header-center a{color:var(--color-header-text);text-decoration:none}.main{display:flex;flex:1}.sidebar-drawer{background:var(--color-sidebar-background);border-right:1px solid var(--color-sidebar-background-border);box-sizing:border-box;display:flex;justify-content:flex-end;min-width:15em;width:calc(50% - 26em)}.sidebar-container,.toc-drawer{box-sizing:border-box;width:15em}.toc-drawer{background:var(--color-toc-background);padding-right:1rem}.sidebar-sticky,.toc-sticky{display:flex;flex-direction:column;height:min(100%,100vh);height:100vh;position:sticky;top:0}.sidebar-scroll,.toc-scroll{flex-grow:1;flex-shrink:1;overflow:auto;scroll-behavior:smooth}.content{display:flex;flex-direction:column;justify-content:space-between;padding:0 3em;width:46em}.icon{display:inline-block;height:1rem;width:1rem}.icon svg{height:100%;width:100%}.announcement{align-items:center;background-color:var(--color-announcement-background);color:var(--color-announcement-text);display:flex;height:var(--header-height);overflow-x:auto}.announcement+.page{min-height:calc(100% - var(--header-height))}.announcement-content{box-sizing:border-box;min-width:100%;padding:.5rem;text-align:center;white-space:nowrap}.announcement-content a{color:var(--color-announcement-text);text-decoration-color:var(--color-announcement-text)}.announcement-content a:hover{color:var(--color-announcement-text);text-decoration-color:var(--color-link--hover)}.no-js .theme-toggle-container{display:none}.theme-toggle-container{vertical-align:middle}.theme-toggle{background:transparent;border:none;cursor:pointer;padding:0}.theme-toggle svg{color:var(--color-foreground-primary);display:none;height:1rem;vertical-align:middle;width:1rem}.theme-toggle-header{float:left;padding:1rem .5rem}.nav-overlay-icon,.toc-overlay-icon{cursor:pointer;display:none}.nav-overlay-icon .icon,.toc-overlay-icon .icon{color:var(--color-foreground-secondary);height:1rem;width:1rem}.nav-overlay-icon,.toc-header-icon{align-items:center;justify-content:center}.toc-content-icon{height:1.5rem;width:1.5rem}.content-icon-container{display:flex;float:right;gap:.5rem;margin-bottom:1rem;margin-left:1rem;margin-top:1.5rem}.content-icon-container .edit-this-page svg{color:inherit;height:1rem;width:1rem}.sidebar-toggle{display:none;position:absolute}.sidebar-toggle[name=__toc]{left:20px}.sidebar-toggle:checked{left:40px}.overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms,height 0ms,opacity .25s ease-out;width:0}.sidebar-overlay{z-index:20}.toc-overlay{z-index:40}.sidebar-drawer{transition:left .25s ease-in-out;z-index:30}.toc-drawer{transition:right .25s ease-in-out;z-index:50}#__navigation:checked~.sidebar-overlay{height:100%;opacity:1;width:100%}#__navigation:checked~.page .sidebar-drawer{left:0;top:0}#__toc:checked~.toc-overlay{height:100%;opacity:1;width:100%}#__toc:checked~.page .toc-drawer{right:0;top:0}.back-to-top{background:var(--color-background-primary);border-radius:1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 1px 0 hsla(220,9%,46%,.502);display:none;font-size:.8125rem;left:0;margin-left:50%;padding:.5rem .75rem .5rem .5rem;position:fixed;text-decoration:none;top:1rem;transform:translateX(-50%);z-index:10}.back-to-top svg{fill:currentColor;display:inline-block;height:1rem;width:1rem}.back-to-top span{margin-left:.25rem}.show-back-to-top .back-to-top{align-items:center;display:flex}@media(min-width:97em){html{font-size:110%}}@media(max-width:82em){.toc-content-icon{display:flex}.toc-drawer{border-left:1px solid var(--color-background-muted);height:100vh;position:fixed;right:-15em;top:0}.toc-tree{border-left:none;font-size:var(--toc-font-size--mobile)}.sidebar-drawer{width:calc(50% - 18.5em)}}@media(max-width:67em){.nav-overlay-icon{display:flex}.sidebar-drawer{height:100vh;left:-15em;position:fixed;top:0;width:15em}.toc-header-icon{display:flex}.theme-toggle-content,.toc-content-icon{display:none}.theme-toggle-header{display:block}.mobile-header{align-items:center;display:flex;justify-content:space-between;position:sticky;top:0}.mobile-header .header-left,.mobile-header .header-right{display:flex;height:var(--header-height);padding:0 var(--header-padding)}.mobile-header .header-left label,.mobile-header .header-right label{height:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.nav-overlay-icon .icon,.theme-toggle svg{height:1.25rem;width:1.25rem}:target{scroll-margin-top:var(--header-height)}.back-to-top{top:calc(var(--header-height) + .5rem)}.page{flex-direction:column;justify-content:center}.content{margin-left:auto;margin-right:auto}}@media(max-width:52em){.content{overflow-x:auto;width:100%}}@media(max-width:46em){.content{padding:0 1em}article aside.sidebar{float:none;margin:1rem 0;width:100%}}.admonition,.topic{background:var(--color-admonition-background);border-radius:.2rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1);font-size:var(--admonition-font-size);margin:1rem auto;overflow:hidden;padding:0 .5rem .5rem;page-break-inside:avoid}.admonition>:nth-child(2),.topic>:nth-child(2){margin-top:0}.admonition>:last-child,.topic>:last-child{margin-bottom:0}.admonition p.admonition-title,p.topic-title{font-size:var(--admonition-title-font-size);font-weight:500;line-height:1.3;margin:0 -.5rem .5rem;padding:.4rem .5rem .4rem 2rem;position:relative}.admonition p.admonition-title:before,p.topic-title:before{content:"";height:1rem;left:.5rem;position:absolute;width:1rem}p.admonition-title{background-color:var(--color-admonition-title-background)}p.admonition-title:before{background-color:var(--color-admonition-title);-webkit-mask-image:var(--icon-admonition-default);mask-image:var(--icon-admonition-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}p.topic-title{background-color:var(--color-topic-title-background)}p.topic-title:before{background-color:var(--color-topic-title);-webkit-mask-image:var(--icon-topic-default);mask-image:var(--icon-topic-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.admonition{border-left:.2rem solid var(--color-admonition-title)}.admonition.caution{border-left-color:var(--color-admonition-title--caution)}.admonition.caution>.admonition-title{background-color:var(--color-admonition-title-background--caution)}.admonition.caution>.admonition-title:before{background-color:var(--color-admonition-title--caution);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.warning{border-left-color:var(--color-admonition-title--warning)}.admonition.warning>.admonition-title{background-color:var(--color-admonition-title-background--warning)}.admonition.warning>.admonition-title:before{background-color:var(--color-admonition-title--warning);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.danger{border-left-color:var(--color-admonition-title--danger)}.admonition.danger>.admonition-title{background-color:var(--color-admonition-title-background--danger)}.admonition.danger>.admonition-title:before{background-color:var(--color-admonition-title--danger);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.attention{border-left-color:var(--color-admonition-title--attention)}.admonition.attention>.admonition-title{background-color:var(--color-admonition-title-background--attention)}.admonition.attention>.admonition-title:before{background-color:var(--color-admonition-title--attention);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.error{border-left-color:var(--color-admonition-title--error)}.admonition.error>.admonition-title{background-color:var(--color-admonition-title-background--error)}.admonition.error>.admonition-title:before{background-color:var(--color-admonition-title--error);-webkit-mask-image:var(--icon-failure);mask-image:var(--icon-failure)}.admonition.hint{border-left-color:var(--color-admonition-title--hint)}.admonition.hint>.admonition-title{background-color:var(--color-admonition-title-background--hint)}.admonition.hint>.admonition-title:before{background-color:var(--color-admonition-title--hint);-webkit-mask-image:var(--icon-question);mask-image:var(--icon-question)}.admonition.tip{border-left-color:var(--color-admonition-title--tip)}.admonition.tip>.admonition-title{background-color:var(--color-admonition-title-background--tip)}.admonition.tip>.admonition-title:before{background-color:var(--color-admonition-title--tip);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.important{border-left-color:var(--color-admonition-title--important)}.admonition.important>.admonition-title{background-color:var(--color-admonition-title-background--important)}.admonition.important>.admonition-title:before{background-color:var(--color-admonition-title--important);-webkit-mask-image:var(--icon-flame);mask-image:var(--icon-flame)}.admonition.note{border-left-color:var(--color-admonition-title--note)}.admonition.note>.admonition-title{background-color:var(--color-admonition-title-background--note)}.admonition.note>.admonition-title:before{background-color:var(--color-admonition-title--note);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition.seealso{border-left-color:var(--color-admonition-title--seealso)}.admonition.seealso>.admonition-title{background-color:var(--color-admonition-title-background--seealso)}.admonition.seealso>.admonition-title:before{background-color:var(--color-admonition-title--seealso);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.admonition-todo{border-left-color:var(--color-admonition-title--admonition-todo)}.admonition.admonition-todo>.admonition-title{background-color:var(--color-admonition-title-background--admonition-todo)}.admonition.admonition-todo>.admonition-title:before{background-color:var(--color-admonition-title--admonition-todo);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition-todo>.admonition-title{text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd{margin-left:2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:first-child{margin-top:.125rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list,dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:last-child{margin-bottom:.75rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list>dt{font-size:var(--font-size--small);text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd:empty{margin-bottom:.5rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul{margin-left:-1.2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p:nth-child(2){margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p+p:last-child:empty{margin-bottom:0;margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{color:var(--color-api-overall)}.sig:not(.sig-inline){background:var(--color-api-background);border-radius:.25rem;font-family:var(--font-stack--monospace);font-size:var(--api-font-size);font-weight:700;margin-left:-.25rem;margin-right:-.25rem;padding:.25rem .5rem .25rem 3em;text-indent:-2.5em;transition:background .1s ease-out}.sig:not(.sig-inline):hover{background:var(--color-api-background-hover)}.sig:not(.sig-inline) a.reference .viewcode-link{font-weight:400;width:3.5rem}em.property{font-style:normal}em.property:first-child{color:var(--color-api-keyword)}.sig-name{color:var(--color-api-name)}.sig-prename{color:var(--color-api-pre-name);font-weight:400}.sig-paren{color:var(--color-api-paren)}.sig-param{font-style:normal}.versionmodified{font-style:italic}div.deprecated p,div.versionadded p,div.versionchanged p{margin-bottom:.125rem;margin-top:.125rem}.viewcode-back,.viewcode-link{float:right;text-align:right}.line-block{margin-bottom:.75rem;margin-top:.5rem}.line-block .line-block{margin-bottom:0;margin-top:0;padding-left:1rem}.code-block-caption,article p.caption,table>caption{font-size:var(--font-size--small);text-align:center}.toctree-wrapper.compound .caption,.toctree-wrapper.compound :not(.caption)>.caption-text{font-size:var(--font-size--small);margin-bottom:0;text-align:initial;text-transform:uppercase}.toctree-wrapper.compound>ul{margin-bottom:0;margin-top:0}.sig-inline,code.literal{background:var(--color-inline-code-background);border-radius:.2em;font-size:var(--font-size--small--2);padding:.1em .2em}pre.literal-block .sig-inline,pre.literal-block code.literal{font-size:inherit;padding:0}p .sig-inline,p code.literal{border:1px solid var(--color-background-border)}.sig-inline{font-family:var(--font-stack--monospace)}div[class*=" highlight-"],div[class^=highlight-]{display:flex;margin:1em 0}div[class*=" highlight-"] .table-wrapper,div[class^=highlight-] .table-wrapper,pre{margin:0;padding:0}pre{overflow:auto}article[role=main] .highlight pre{line-height:1.5}.highlight pre,pre.literal-block{font-size:var(--code-font-size);padding:.625rem .875rem}pre.literal-block{background-color:var(--color-code-background);border-radius:.2rem;color:var(--color-code-foreground);margin-bottom:1rem;margin-top:1rem}.highlight{border-radius:.2rem;width:100%}.highlight .gp,.highlight span.linenos{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlight .hll{display:block;margin-left:-.875rem;margin-right:-.875rem;padding-left:.875rem;padding-right:.875rem}.code-block-caption{background-color:var(--color-code-background);border-bottom:1px solid;border-radius:.25rem;border-bottom-left-radius:0;border-bottom-right-radius:0;border-color:var(--color-background-border);color:var(--color-code-foreground);display:flex;font-weight:300;padding:.625rem .875rem}.code-block-caption+div[class]{margin-top:0}.code-block-caption+div[class] pre{border-top-left-radius:0;border-top-right-radius:0}.highlighttable{display:block;width:100%}.highlighttable tbody{display:block}.highlighttable tr{display:flex}.highlighttable td.linenos{background-color:var(--color-code-background);border-bottom-left-radius:.2rem;border-top-left-radius:.2rem;color:var(--color-code-foreground);padding:.625rem 0 .625rem .875rem}.highlighttable .linenodiv{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;font-size:var(--code-font-size);padding-right:.875rem}.highlighttable td.code{display:block;flex:1;overflow:hidden;padding:0}.highlighttable td.code .highlight{border-bottom-left-radius:0;border-top-left-radius:0}.highlight span.linenos{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;display:inline-block;margin-right:.875rem;padding-left:0;padding-right:.875rem}.footnote-reference{font-size:var(--font-size--small--4);vertical-align:super}dl.footnote.brackets{color:var(--color-foreground-secondary);display:grid;font-size:var(--font-size--small);grid-template-columns:max-content auto}dl.footnote.brackets dt{margin:0}dl.footnote.brackets dt>.fn-backref{margin-left:.25rem}dl.footnote.brackets dt:after{content:":"}dl.footnote.brackets dt .brackets:before{content:"["}dl.footnote.brackets dt .brackets:after{content:"]"}dl.footnote.brackets dd{margin:0;padding:0 1rem}aside.footnote{color:var(--color-foreground-secondary);font-size:var(--font-size--small)}aside.footnote>span,div.citation>span{float:left;font-weight:500;padding-right:.25rem}aside.footnote>p,div.citation>p{margin-left:2rem}img{box-sizing:border-box;height:auto;max-width:100%}article .figure,article figure{border-radius:.2rem;margin:0}article .figure :last-child,article figure :last-child{margin-bottom:0}article .align-left{clear:left;float:left;margin:0 1rem 1rem}article .align-right{clear:right;float:right;margin:0 1rem 1rem}article .align-center,article .align-default{display:block;margin-left:auto;margin-right:auto;text-align:center}article table.align-default{display:table;text-align:initial}.domainindex-jumpbox,.genindex-jumpbox{border-bottom:1px solid var(--color-background-border);border-top:1px solid var(--color-background-border);padding:.25rem}.domainindex-section h2,.genindex-section h2{margin-bottom:.5rem;margin-top:.75rem}.domainindex-section ul,.genindex-section ul{margin-bottom:0;margin-top:0}ol,ul{margin-bottom:1rem;margin-top:1rem;padding-left:1.2rem}ol li>p:first-child,ul li>p:first-child{margin-bottom:.25rem;margin-top:.25rem}ol li>p:last-child,ul li>p:last-child{margin-top:.25rem}ol li>ol,ol li>ul,ul li>ol,ul li>ul{margin-bottom:.5rem;margin-top:.5rem}ol.arabic{list-style:decimal}ol.loweralpha{list-style:lower-alpha}ol.upperalpha{list-style:upper-alpha}ol.lowerroman{list-style:lower-roman}ol.upperroman{list-style:upper-roman}.simple li>ol,.simple li>ul,.toctree-wrapper li>ol,.toctree-wrapper li>ul{margin-bottom:0;margin-top:0}.field-list dt,.option-list dt,dl.footnote dt,dl.glossary dt,dl.simple dt,dl:not([class]) dt{font-weight:500;margin-top:.25rem}.field-list dt+dt,.option-list dt+dt,dl.footnote dt+dt,dl.glossary dt+dt,dl.simple dt+dt,dl:not([class]) dt+dt{margin-top:0}.field-list dt .classifier:before,.option-list dt .classifier:before,dl.footnote dt .classifier:before,dl.glossary dt .classifier:before,dl.simple dt .classifier:before,dl:not([class]) dt .classifier:before{content:":";margin-left:.2rem;margin-right:.2rem}.field-list dd ul,.field-list dd>p:first-child,.option-list dd ul,.option-list dd>p:first-child,dl.footnote dd ul,dl.footnote dd>p:first-child,dl.glossary dd ul,dl.glossary dd>p:first-child,dl.simple dd ul,dl.simple dd>p:first-child,dl:not([class]) dd ul,dl:not([class]) dd>p:first-child{margin-top:.125rem}.field-list dd ul,.option-list dd ul,dl.footnote dd ul,dl.glossary dd ul,dl.simple dd ul,dl:not([class]) dd ul{margin-bottom:.125rem}.math-wrapper{overflow-x:auto;width:100%}div.math{position:relative;text-align:center}div.math .headerlink,div.math:focus .headerlink{display:none}div.math:hover .headerlink{display:inline-block}div.math span.eqno{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);z-index:1}abbr[title]{cursor:help}.problematic{color:var(--color-problematic)}kbd:not(.compound){background-color:var(--color-background-secondary);border:1px solid var(--color-foreground-border);border-radius:.2rem;box-shadow:0 .0625rem 0 rgba(0,0,0,.2),inset 0 0 0 .125rem var(--color-background-primary);color:var(--color-foreground-primary);display:inline-block;font-size:var(--font-size--small--3);margin:0 .2rem;padding:0 .2rem;vertical-align:text-bottom}blockquote{background:var(--color-background-secondary);border-left:4px solid var(--color-background-border);margin-left:0;margin-right:0;padding:.5rem 1rem}blockquote .attribution{font-weight:600;text-align:right}blockquote.highlights,blockquote.pull-quote{font-size:1.25em}blockquote.epigraph,blockquote.pull-quote{border-left-width:0;border-radius:.5rem}blockquote.highlights{background:transparent;border-left-width:0}p .reference img{vertical-align:middle}p.rubric{font-size:1.125em;font-weight:700;line-height:1.25}dd p.rubric{font-size:var(--font-size--small);font-weight:inherit;line-height:inherit;text-transform:uppercase}article .sidebar{background-color:var(--color-background-secondary);border:1px solid var(--color-background-border);border-radius:.2rem;clear:right;float:right;margin-left:1rem;margin-right:0;width:30%}article .sidebar>*{padding-left:1rem;padding-right:1rem}article .sidebar>ol,article .sidebar>ul{padding-left:2.2rem}article .sidebar .sidebar-title{border-bottom:1px solid var(--color-background-border);font-weight:500;margin:0;padding:.5rem 1rem}.table-wrapper{margin-bottom:.5rem;margin-top:1rem;overflow-x:auto;padding:.2rem .2rem .75rem;width:100%}table.docutils{border-collapse:collapse;border-radius:.2rem;border-spacing:0;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)}table.docutils th{background:var(--color-table-header-background)}table.docutils td,table.docutils th{border-bottom:1px solid var(--color-table-border);border-left:1px solid var(--color-table-border);border-right:1px solid var(--color-table-border);padding:0 .25rem}table.docutils td p,table.docutils th p{margin:.25rem}table.docutils td:first-child,table.docutils th:first-child{border-left:none}table.docutils td:last-child,table.docutils th:last-child{border-right:none}table.docutils td.text-left,table.docutils th.text-left{text-align:left}table.docutils td.text-right,table.docutils th.text-right{text-align:right}table.docutils td.text-center,table.docutils th.text-center{text-align:center}:target{scroll-margin-top:.5rem}@media(max-width:67em){:target{scroll-margin-top:calc(.5rem + var(--header-height))}section>span:target{scroll-margin-top:calc(.8rem + var(--header-height))}}.headerlink{font-weight:100;-webkit-user-select:none;-moz-user-select:none;user-select:none}.code-block-caption>.headerlink,dl dt>.headerlink,figcaption p>.headerlink,h1>.headerlink,h2>.headerlink,h3>.headerlink,h4>.headerlink,h5>.headerlink,h6>.headerlink,p.caption>.headerlink,table>caption>.headerlink{margin-left:.5rem;visibility:hidden}.code-block-caption:hover>.headerlink,dl dt:hover>.headerlink,figcaption p:hover>.headerlink,h1:hover>.headerlink,h2:hover>.headerlink,h3:hover>.headerlink,h4:hover>.headerlink,h5:hover>.headerlink,h6:hover>.headerlink,p.caption:hover>.headerlink,table>caption:hover>.headerlink{visibility:visible}.code-block-caption>.toc-backref,dl dt>.toc-backref,figcaption p>.toc-backref,h1>.toc-backref,h2>.toc-backref,h3>.toc-backref,h4>.toc-backref,h5>.toc-backref,h6>.toc-backref,p.caption>.toc-backref,table>caption>.toc-backref{color:inherit;text-decoration-line:none}figure:hover>figcaption>p>.headerlink,table:hover>caption>.headerlink{visibility:visible}:target>h1:first-of-type,:target>h2:first-of-type,:target>h3:first-of-type,:target>h4:first-of-type,:target>h5:first-of-type,:target>h6:first-of-type,span:target~h1:first-of-type,span:target~h2:first-of-type,span:target~h3:first-of-type,span:target~h4:first-of-type,span:target~h5:first-of-type,span:target~h6:first-of-type{background-color:var(--color-highlight-on-target)}:target>h1:first-of-type code.literal,:target>h2:first-of-type code.literal,:target>h3:first-of-type code.literal,:target>h4:first-of-type code.literal,:target>h5:first-of-type code.literal,:target>h6:first-of-type code.literal,span:target~h1:first-of-type code.literal,span:target~h2:first-of-type code.literal,span:target~h3:first-of-type code.literal,span:target~h4:first-of-type code.literal,span:target~h5:first-of-type code.literal,span:target~h6:first-of-type code.literal{background-color:transparent}.literal-block-wrapper:target .code-block-caption,.this-will-duplicate-information-and-it-is-still-useful-here li :target,figure:target,table:target>caption{background-color:var(--color-highlight-on-target)}dt:target{background-color:var(--color-highlight-on-target)!important}.footnote-reference:target,.footnote>dt:target+dd{background-color:var(--color-highlight-on-target)}.guilabel{background-color:var(--color-guilabel-background);border:1px solid var(--color-guilabel-border);border-radius:.5em;color:var(--color-guilabel-text);font-size:.9em;padding:0 .3em}footer{display:flex;flex-direction:column;font-size:var(--font-size--small);margin-top:2rem}.bottom-of-page{align-items:center;border-top:1px solid var(--color-background-border);color:var(--color-foreground-secondary);display:flex;justify-content:space-between;line-height:1.5;margin-top:1rem;padding-bottom:1rem;padding-top:1rem}@media(max-width:46em){.bottom-of-page{flex-direction:column-reverse;gap:.25rem;text-align:center}}.bottom-of-page .left-details{font-size:var(--font-size--small)}.bottom-of-page .right-details{display:flex;flex-direction:column;gap:.25rem;text-align:right}.bottom-of-page .icons{display:flex;font-size:1rem;gap:.25rem;justify-content:flex-end}.bottom-of-page .icons a{text-decoration:none}.bottom-of-page .icons img,.bottom-of-page .icons svg{font-size:1.125rem;height:1em;width:1em}.related-pages a{align-items:center;display:flex;text-decoration:none}.related-pages a:hover .page-info .title{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}.related-pages a svg.furo-related-icon,.related-pages a svg.furo-related-icon>use{color:var(--color-foreground-border);flex-shrink:0;height:.75rem;margin:0 .5rem;width:.75rem}.related-pages a.next-page{clear:right;float:right;max-width:50%;text-align:right}.related-pages a.prev-page{clear:left;float:left;max-width:50%}.related-pages a.prev-page svg{transform:rotate(180deg)}.page-info{display:flex;flex-direction:column;overflow-wrap:anywhere}.next-page .page-info{align-items:flex-end}.page-info .context{align-items:center;color:var(--color-foreground-muted);display:flex;font-size:var(--font-size--small);padding-bottom:.1rem;text-decoration:none}ul.search{list-style:none;padding-left:0}ul.search li{border-bottom:1px solid var(--color-background-border);padding:1rem 0}[role=main] .highlighted{background-color:var(--color-highlighted-background);color:var(--color-highlighted-text)}.sidebar-brand{display:flex;flex-direction:column;flex-shrink:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none}.sidebar-brand-text{color:var(--color-sidebar-brand-text);font-size:1.5rem;overflow-wrap:break-word}.sidebar-brand-text,.sidebar-logo-container{margin:var(--sidebar-item-spacing-vertical) 0}.sidebar-logo{display:block;margin:0 auto;max-width:100%}.sidebar-search-container{align-items:center;background:var(--color-sidebar-search-background);display:flex;margin-top:var(--sidebar-search-space-above);position:relative}.sidebar-search-container:focus-within,.sidebar-search-container:hover{background:var(--color-sidebar-search-background--focus)}.sidebar-search-container:before{background-color:var(--color-sidebar-search-icon);content:"";height:var(--sidebar-search-icon-size);left:var(--sidebar-item-spacing-horizontal);-webkit-mask-image:var(--icon-search);mask-image:var(--icon-search);position:absolute;width:var(--sidebar-search-icon-size)}.sidebar-search{background:transparent;border:none;border-bottom:1px solid var(--color-sidebar-search-border);border-top:1px solid var(--color-sidebar-search-border);box-sizing:border-box;color:var(--color-sidebar-search-foreground);padding:var(--sidebar-search-input-spacing-vertical) var(--sidebar-search-input-spacing-horizontal) var(--sidebar-search-input-spacing-vertical) calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size));width:100%;z-index:10}.sidebar-search:focus{outline:none}.sidebar-search::-moz-placeholder{font-size:var(--sidebar-search-input-font-size)}.sidebar-search::placeholder{font-size:var(--sidebar-search-input-font-size)}#searchbox .highlight-link{margin:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0;text-align:center}#searchbox .highlight-link a{color:var(--color-sidebar-search-icon);font-size:var(--font-size--small--2)}.sidebar-tree{font-size:var(--sidebar-item-font-size);margin-bottom:var(--sidebar-item-spacing-vertical);margin-top:var(--sidebar-tree-space-above)}.sidebar-tree ul{display:flex;flex-direction:column;list-style:none;margin-bottom:0;margin-top:0;padding:0}.sidebar-tree li{margin:0;position:relative}.sidebar-tree li>ul{margin-left:var(--sidebar-item-spacing-horizontal)}.sidebar-tree .icon,.sidebar-tree .reference{color:var(--color-sidebar-link-text)}.sidebar-tree .reference{box-sizing:border-box;display:inline-block;height:100%;line-height:var(--sidebar-item-line-height);overflow-wrap:anywhere;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none;width:100%}.sidebar-tree .reference:hover{background:var(--color-sidebar-item-background--hover)}.sidebar-tree .reference.external:after{color:var(--color-sidebar-link-text);content:url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23607D8B' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M0 0h24v24H0z' stroke='none'/%3E%3Cpath d='M11 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-5M10 14 20 4M15 4h5v5'/%3E%3C/svg%3E");margin:0 .25rem;vertical-align:middle}.sidebar-tree .current-page>.reference{font-weight:700}.sidebar-tree label{align-items:center;cursor:pointer;display:flex;height:var(--sidebar-item-height);justify-content:center;position:absolute;right:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:var(--sidebar-expander-width)}.sidebar-tree .caption,.sidebar-tree :not(.caption)>.caption-text{color:var(--color-sidebar-caption-text);font-size:var(--sidebar-caption-font-size);font-weight:700;margin:var(--sidebar-caption-space-above) 0 0 0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-transform:uppercase}.sidebar-tree li.has-children>.reference{padding-right:var(--sidebar-expander-width)}.sidebar-tree .toctree-l1>.reference,.sidebar-tree .toctree-l1>label .icon{color:var(--color-sidebar-link-text--top-level)}.sidebar-tree label{background:var(--color-sidebar-item-expander-background)}.sidebar-tree label:hover{background:var(--color-sidebar-item-expander-background--hover)}.sidebar-tree .current>.reference{background:var(--color-sidebar-item-background--current)}.sidebar-tree .current>.reference:hover{background:var(--color-sidebar-item-background--hover)}.toctree-checkbox{display:none;position:absolute}.toctree-checkbox~ul{display:none}.toctree-checkbox~label .icon svg{transform:rotate(90deg)}.toctree-checkbox:checked~ul{display:block}.toctree-checkbox:checked~label .icon svg{transform:rotate(-90deg)}.toc-title-container{padding:var(--toc-title-padding);padding-top:var(--toc-spacing-vertical)}.toc-title{color:var(--color-toc-title-text);font-size:var(--toc-title-font-size);padding-left:var(--toc-spacing-horizontal);text-transform:uppercase}.no-toc{display:none}.toc-tree-container{padding-bottom:var(--toc-spacing-vertical)}.toc-tree{border-left:1px solid var(--color-background-border);font-size:var(--toc-font-size);line-height:1.3;padding-left:calc(var(--toc-spacing-horizontal) - var(--toc-item-spacing-horizontal))}.toc-tree>ul>li:first-child{padding-top:0}.toc-tree>ul>li:first-child>ul{padding-left:0}.toc-tree>ul>li:first-child>a{display:none}.toc-tree ul{list-style-type:none;margin-bottom:0;margin-top:0;padding-left:var(--toc-item-spacing-horizontal)}.toc-tree li{padding-top:var(--toc-item-spacing-vertical)}.toc-tree li.scroll-current>.reference{color:var(--color-toc-item-text--active);font-weight:700}.toc-tree .reference{color:var(--color-toc-item-text);overflow-wrap:anywhere;text-decoration:none}.toc-scroll{max-height:100vh;overflow-y:scroll}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here){background:rgba(255,0,0,.25);color:var(--color-problematic)}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here):before{content:"ERROR: Adding a table of contents in Furo-based documentation is unnecessary, and does not work well with existing styling.Add a 'this-will-duplicate-information-and-it-is-still-useful-here' class, if you want an escape hatch."}.text-align\:left>p{text-align:left}.text-align\:center>p{text-align:center}.text-align\:right>p{text-align:right}
+/*# sourceMappingURL=furo.css.map*/
\ No newline at end of file
diff --git a/_static/styles/furo.css.map b/_static/styles/furo.css.map
new file mode 100644
index 000000000..1924b3334
--- /dev/null
+++ b/_static/styles/furo.css.map
@@ -0,0 +1 @@
+{"version":3,"file":"styles/furo.css","mappings":"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F,kBACA,CACE,wEACA,CARA,YACA,CAKF,mBAFF,MACE,CAIE,gBAJF,iCAJE,cAGJ,CANI,oBAEA,CAKF,SAIE,2BADA,UACA,kBAGF,sCACA,CAFF,WACE,WACA,mBACE,kDACA,0EACA,uDAKJ,aACE,mDAII,CAJJ,6CAII,4BACA,sCACE,kEACA,+CACE,aACA,WADA,+BACA,uEANN,YACE,mDAEE,mBADF,0CACE,CADF,qBACE,0DACA,YACE,4DACA,sEANN,YACE,8CACA,kBADA,UACA,2CACE,2EACA,cACE,kEACA,mEANN,yBACE,4DACA,sBACE,+EAEE,iEACA,qEANN,sCACE,CAGE,iBAHF,gBAGE,qBACE,CAJJ,uBACA,gDACE,wDACA,6DAHF,2CACA,CADA,gBACA,eACE,CAGE,sBANN,8BACE,CAII,iBAFF,4DACA,WACE,YADF,uCACE,6EACA,2BANN,8CACE,kDACA,0CACE,8BACA,yFACE,sBACA,sFALJ,mEACA,sBACE,kEACA,6EACE,uCACA,kEALJ,qGAEE,kEACA,6EACE,uCACA,kEALJ,8CACA,uDACE,sEACA,2EACE,sCACA,iEALJ,mGACA,qCACE,oDACA,0DACE,6GACA,gDAGR,yDCrEA,sEACE,CACA,6GACE,gEACF,iGAIF,wFACE,qDAGA,mGAEE,2CAEF,4FACE,gCACF,wGACE,8DAEE,6FAIA,iJAKN,6GACE,gDAKF,yDACA,qCAGA,6BACA,kBACA,qDAKA,oCAEA,+DAGA,2CAGE,oDAIA,oEAEE,qBAGJ,wDAEE,uCAEF,kEAGA,8CAEA,uDAKA,oCAEA,yDAEE,gEAKF,+CC5FA,0EAGE,CACA,qDCLJ,+DAIE,sCAIA,kEACE,yBACA,2FAMA,gBACA,yGCbF,mBAOA,2MAIA,4HAYA,0DACE,8GAYF,8HAQE,mBAEA,6HAOF,YAGA,mIAME,eACA,CAFF,YAEE,4FAMJ,8BAEE,uBAYA,sCAEE,CAJF,oBAEA,CARA,wCAEA,CAHA,8BACA,CAFA,eACA,CAGA,wCAEA,CAEA,mDAIE,kCACE,6BACA,4CAKJ,kDAIA,eACE,aAGF,8BACE,uDACA,sCACA,cAEA,+BACA,CA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","sources":["webpack:///./node_modules/normalize.css/normalize.css","webpack:///./src/furo/assets/styles/base/_print.sass","webpack:///./src/furo/assets/styles/base/_screen-readers.sass","webpack:///./src/furo/assets/styles/base/_theme.sass","webpack:///./src/furo/assets/styles/variables/_fonts.scss","webpack:///./src/furo/assets/styles/variables/_spacing.scss","webpack:///./src/furo/assets/styles/variables/_icons.scss","webpack:///./src/furo/assets/styles/variables/_admonitions.scss","webpack:///./src/furo/assets/styles/variables/_colors.scss","webpack:///./src/furo/assets/styles/base/_typography.sass","webpack:///./src/furo/assets/styles/_scaffold.sass","webpack:///./src/furo/assets/styles/content/_admonitions.sass","webpack:///./src/furo/assets/styles/content/_api.sass","webpack:///./src/furo/assets/styles/content/_blocks.sass","webpack:///./src/furo/assets/styles/content/_captions.sass","webpack:///./src/furo/assets/styles/content/_code.sass","webpack:///./src/furo/assets/styles/content/_footnotes.sass","webpack:///./src/furo/assets/styles/content/_images.sass","webpack:///./src/furo/assets/styles/content/_indexes.sass","webpack:///./src/furo/assets/styles/content/_lists.sass","webpack:///./src/furo/assets/styles/content/_math.sass","webpack:///./src/furo/assets/styles/content/_misc.sass","webpack:///./src/furo/assets/styles/content/_rubrics.sass","webpack:///./src/furo/assets/styles/content/_sidebar.sass","webpack:///./src/furo/assets/styles/content/_tables.sass","webpack:///./src/furo/assets/styles/content/_target.sass","webpack:///./src/furo/assets/styles/content/_gui-labels.sass","webpack:///./src/furo/assets/styles/components/_footer.sass","webpack:///./src/furo/assets/styles/components/_sidebar.sass","webpack:///./src/furo/assets/styles/components/_table_of_contents.sass","webpack:///./src/furo/assets/styles/_shame.sass"],"sourcesContent":["/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/* Sections\n ========================================================================== */\n\n/**\n * Remove the margin in all browsers.\n */\n\nbody {\n margin: 0;\n}\n\n/**\n * Render the `main` element consistently in IE.\n */\n\nmain {\n display: block;\n}\n\n/**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n/* Grouping content\n ========================================================================== */\n\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\nhr {\n box-sizing: content-box; /* 1 */\n height: 0; /* 1 */\n overflow: visible; /* 2 */\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\npre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/* Text-level semantics\n ========================================================================== */\n\n/**\n * Remove the gray background on active links in IE 10.\n */\n\na {\n background-color: transparent;\n}\n\n/**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\nabbr[title] {\n border-bottom: none; /* 1 */\n text-decoration: underline; /* 2 */\n text-decoration: underline dotted; /* 2 */\n}\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\n * Add the correct font size in all browsers.\n */\n\nsmall {\n font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/* Embedded content\n ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10.\n */\n\nimg {\n border-style: none;\n}\n\n/* Forms\n ========================================================================== */\n\n/**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput { /* 1 */\n overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n/**\n * Correct the padding in Firefox.\n */\n\nfieldset {\n padding: 0.35em 0.75em 0.625em;\n}\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n\nlegend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n}\n\n/**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\n * Remove the default vertical scrollbar in IE 10+.\n */\n\ntextarea {\n overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/* Interactive\n ========================================================================== */\n\n/*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n\ndetails {\n display: block;\n}\n\n/*\n * Add the correct display in all browsers.\n */\n\nsummary {\n display: list-item;\n}\n\n/* Misc\n ========================================================================== */\n\n/**\n * Add the correct display in IE 10+.\n */\n\ntemplate {\n display: none;\n}\n\n/**\n * Add the correct display in IE 10.\n */\n\n[hidden] {\n display: none;\n}\n","// This file contains styles for managing print media.\n\n////////////////////////////////////////////////////////////////////////////////\n// Hide elements not relevant to print media.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Hide icon container.\n .content-icon-container\n display: none !important\n\n // Hide showing header links if hovering over when printing.\n .headerlink\n display: none !important\n\n // Hide mobile header.\n .mobile-header\n display: none !important\n\n // Hide navigation links.\n .related-pages\n display: none !important\n\n////////////////////////////////////////////////////////////////////////////////\n// Tweaks related to decolorization.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Apply a border around code which no longer have a color background.\n .highlight\n border: 0.1pt solid var(--color-foreground-border)\n\n////////////////////////////////////////////////////////////////////////////////\n// Avoid page break in some relevant cases.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n ul, ol, dl, a, table, pre, blockquote\n page-break-inside: avoid\n\n h1, h2, h3, h4, h5, h6, img, figure, caption\n page-break-inside: avoid\n page-break-after: avoid\n\n ul, ol, dl\n page-break-before: avoid\n",".visually-hidden\n position: absolute !important\n width: 1px !important\n height: 1px !important\n padding: 0 !important\n margin: -1px !important\n overflow: hidden !important\n clip: rect(0,0,0,0) !important\n white-space: nowrap !important\n border: 0 !important\n\n:-moz-focusring\n outline: auto\n","// This file serves as the \"skeleton\" of the theming logic.\n//\n// This contains the bulk of the logic for handling dark mode, color scheme\n// toggling and the handling of color-scheme-specific hiding of elements.\n\nbody\n @include fonts\n @include spacing\n @include icons\n @include admonitions\n @include default-admonition(#651fff, \"abstract\")\n @include default-topic(#14B8A6, \"pencil\")\n\n @include colors\n\n.only-light\n display: block !important\nhtml body .only-dark\n display: none !important\n\n// Ignore dark-mode hints if print media.\n@media not print\n // Enable dark-mode, if requested.\n body[data-theme=\"dark\"]\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n // Enable dark mode, unless explicitly told to avoid.\n @media (prefers-color-scheme: dark)\n body:not([data-theme=\"light\"])\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n//\n// Theme toggle presentation\n//\nbody[data-theme=\"auto\"]\n .theme-toggle svg.theme-icon-when-auto\n display: block\n\nbody[data-theme=\"dark\"]\n .theme-toggle svg.theme-icon-when-dark\n display: block\n\nbody[data-theme=\"light\"]\n .theme-toggle svg.theme-icon-when-light\n display: block\n","// Fonts used by this theme.\n//\n// There are basically two things here -- using the system font stack and\n// defining sizes for various elements in %ages. We could have also used `em`\n// but %age is easier to reason about for me.\n\n@mixin fonts {\n // These are adapted from https://systemfontstack.com/\n --font-stack: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,\n sans-serif, Apple Color Emoji, Segoe UI Emoji;\n --font-stack--monospace: \"SFMono-Regular\", Menlo, Consolas, Monaco,\n Liberation Mono, Lucida Console, monospace;\n\n --font-size--normal: 100%;\n --font-size--small: 87.5%;\n --font-size--small--2: 81.25%;\n --font-size--small--3: 75%;\n --font-size--small--4: 62.5%;\n\n // Sidebar\n --sidebar-caption-font-size: var(--font-size--small--2);\n --sidebar-item-font-size: var(--font-size--small);\n --sidebar-search-input-font-size: var(--font-size--small);\n\n // Table of Contents\n --toc-font-size: var(--font-size--small--3);\n --toc-font-size--mobile: var(--font-size--normal);\n --toc-title-font-size: var(--font-size--small--4);\n\n // Admonitions\n //\n // These aren't defined in terms of %ages, since nesting these is permitted.\n --admonition-font-size: 0.8125rem;\n --admonition-title-font-size: 0.8125rem;\n\n // Code\n --code-font-size: var(--font-size--small--2);\n\n // API\n --api-font-size: var(--font-size--small);\n}\n","// Spacing for various elements on the page\n//\n// If the user wants to tweak things in a certain way, they are permitted to.\n// They also have to deal with the consequences though!\n\n@mixin spacing {\n // Header!\n --header-height: calc(\n var(--sidebar-item-line-height) + 4 * #{var(--sidebar-item-spacing-vertical)}\n );\n --header-padding: 0.5rem;\n\n // Sidebar\n --sidebar-tree-space-above: 1.5rem;\n --sidebar-caption-space-above: 1rem;\n\n --sidebar-item-line-height: 1rem;\n --sidebar-item-spacing-vertical: 0.5rem;\n --sidebar-item-spacing-horizontal: 1rem;\n --sidebar-item-height: calc(\n var(--sidebar-item-line-height) + 2 *#{var(--sidebar-item-spacing-vertical)}\n );\n\n --sidebar-expander-width: var(--sidebar-item-height); // be square\n\n --sidebar-search-space-above: 0.5rem;\n --sidebar-search-input-spacing-vertical: 0.5rem;\n --sidebar-search-input-spacing-horizontal: 0.5rem;\n --sidebar-search-input-height: 1rem;\n --sidebar-search-icon-size: var(--sidebar-search-input-height);\n\n // Table of Contents\n --toc-title-padding: 0.25rem 0;\n --toc-spacing-vertical: 1.5rem;\n --toc-spacing-horizontal: 1.5rem;\n --toc-item-spacing-vertical: 0.4rem;\n --toc-item-spacing-horizontal: 1rem;\n}\n","// Expose theme icons as CSS variables.\n\n$icons: (\n // Adapted from tabler-icons\n // url: https://tablericons.com/\n \"search\":\n url('data:image/svg+xml;charset=utf-8, '),\n // Factored out from mkdocs-material on 24-Aug-2020.\n // url: https://squidfunk.github.io/mkdocs-material/reference/admonitions/\n \"pencil\":\n url('data:image/svg+xml;charset=utf-8, '),\n \"abstract\":\n url('data:image/svg+xml;charset=utf-8, '),\n \"info\":\n url('data:image/svg+xml;charset=utf-8, '),\n \"flame\":\n url('data:image/svg+xml;charset=utf-8, '),\n \"question\":\n url('data:image/svg+xml;charset=utf-8, '),\n \"warning\":\n url('data:image/svg+xml;charset=utf-8, '),\n \"failure\":\n url('data:image/svg+xml;charset=utf-8, '),\n \"spark\":\n url('data:image/svg+xml;charset=utf-8, ')\n);\n\n@mixin icons {\n @each $name, $glyph in $icons {\n --icon-#{$name}: #{$glyph};\n }\n}\n","// Admonitions\n\n// Structure of these is:\n// admonition-class: color \"icon-name\";\n//\n// The colors are translated into CSS variables below. The icons are\n// used directly in the main declarations to set the `mask-image` in\n// the title.\n\n// prettier-ignore\n$admonitions: (\n // Each of these has an reST directives for it.\n \"caution\": #ff9100 \"spark\",\n \"warning\": #ff9100 \"warning\",\n \"danger\": #ff5252 \"spark\",\n \"attention\": #ff5252 \"warning\",\n \"error\": #ff5252 \"failure\",\n \"hint\": #00c852 \"question\",\n \"tip\": #00c852 \"info\",\n \"important\": #00bfa5 \"flame\",\n \"note\": #00b0ff \"pencil\",\n \"seealso\": #448aff \"info\",\n \"admonition-todo\": #808080 \"pencil\"\n);\n\n@mixin default-admonition($color, $icon-name) {\n --color-admonition-title: #{$color};\n --color-admonition-title-background: #{rgba($color, 0.2)};\n\n --icon-admonition-default: var(--icon-#{$icon-name});\n}\n\n@mixin default-topic($color, $icon-name) {\n --color-topic-title: #{$color};\n --color-topic-title-background: #{rgba($color, 0.2)};\n\n --icon-topic-default: var(--icon-#{$icon-name});\n}\n\n@mixin admonitions {\n @each $name, $values in $admonitions {\n --color-admonition-title--#{$name}: #{nth($values, 1)};\n --color-admonition-title-background--#{$name}: #{rgba(\n nth($values, 1),\n 0.2\n )};\n }\n}\n","// Colors used throughout this theme.\n//\n// The aim is to give the user more control. Thus, instead of hard-coding colors\n// in various parts of the stylesheet, the approach taken is to define all\n// colors as CSS variables and reusing them in all the places.\n//\n// `colors-dark` depends on `colors` being included at a lower specificity.\n\n@mixin colors {\n --color-problematic: #b30000;\n\n // Base Colors\n --color-foreground-primary: black; // for main text and headings\n --color-foreground-secondary: #5a5c63; // for secondary text\n --color-foreground-muted: #646776; // for muted text\n --color-foreground-border: #878787; // for content borders\n\n --color-background-primary: white; // for content\n --color-background-secondary: #f8f9fb; // for navigation + ToC\n --color-background-hover: #efeff4ff; // for navigation-item hover\n --color-background-hover--transparent: #efeff400;\n --color-background-border: #eeebee; // for UI borders\n --color-background-item: #ccc; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #2962ff;\n --color-brand-content: #2a5adf;\n\n // API documentation\n --color-api-background: var(--color-background-hover--transparent);\n --color-api-background-hover: var(--color-background-hover);\n --color-api-overall: var(--color-foreground-secondary);\n --color-api-name: var(--color-problematic);\n --color-api-pre-name: var(--color-problematic);\n --color-api-paren: var(--color-foreground-secondary);\n --color-api-keyword: var(--color-foreground-primary);\n --color-highlight-on-target: #ffffcc;\n\n // Inline code background\n --color-inline-code-background: var(--color-background-secondary);\n\n // Highlighted text (search)\n --color-highlighted-background: #ddeeff;\n --color-highlighted-text: var(--color-foreground-primary);\n\n // GUI Labels\n --color-guilabel-background: #ddeeff80;\n --color-guilabel-border: #bedaf580;\n --color-guilabel-text: var(--color-foreground-primary);\n\n // Admonitions!\n --color-admonition-background: transparent;\n\n //////////////////////////////////////////////////////////////////////////////\n // Everything below this should be one of:\n // - var(...)\n // - *-gradient(...)\n // - special literal values (eg: transparent, none)\n //////////////////////////////////////////////////////////////////////////////\n\n // Tables\n --color-table-header-background: var(--color-background-secondary);\n --color-table-border: var(--color-background-border);\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: transparent;\n --color-card-marginals-background: var(--color-background-secondary);\n\n // Header\n --color-header-background: var(--color-background-primary);\n --color-header-border: var(--color-background-border);\n --color-header-text: var(--color-foreground-primary);\n\n // Sidebar (left)\n --color-sidebar-background: var(--color-background-secondary);\n --color-sidebar-background-border: var(--color-background-border);\n\n --color-sidebar-brand-text: var(--color-foreground-primary);\n --color-sidebar-caption-text: var(--color-foreground-muted);\n --color-sidebar-link-text: var(--color-foreground-secondary);\n --color-sidebar-link-text--top-level: var(--color-brand-primary);\n\n --color-sidebar-item-background: var(--color-sidebar-background);\n --color-sidebar-item-background--current: var(\n --color-sidebar-item-background\n );\n --color-sidebar-item-background--hover: linear-gradient(\n 90deg,\n var(--color-background-hover--transparent) 0%,\n var(--color-background-hover) var(--sidebar-item-spacing-horizontal),\n var(--color-background-hover) 100%\n );\n\n --color-sidebar-item-expander-background: transparent;\n --color-sidebar-item-expander-background--hover: var(\n --color-background-hover\n );\n\n --color-sidebar-search-text: var(--color-foreground-primary);\n --color-sidebar-search-background: var(--color-background-secondary);\n --color-sidebar-search-background--focus: var(--color-background-primary);\n --color-sidebar-search-border: var(--color-background-border);\n --color-sidebar-search-icon: var(--color-foreground-muted);\n\n // Table of Contents (right)\n --color-toc-background: var(--color-background-primary);\n --color-toc-title-text: var(--color-foreground-muted);\n --color-toc-item-text: var(--color-foreground-secondary);\n --color-toc-item-text--hover: var(--color-foreground-primary);\n --color-toc-item-text--active: var(--color-brand-primary);\n\n // Actual page contents\n --color-content-foreground: var(--color-foreground-primary);\n --color-content-background: transparent;\n\n // Links\n --color-link: var(--color-brand-content);\n --color-link--hover: var(--color-brand-content);\n --color-link-underline: var(--color-background-border);\n --color-link-underline--hover: var(--color-foreground-border);\n}\n\n@mixin colors-dark {\n --color-problematic: #ee5151;\n\n // Base Colors\n --color-foreground-primary: #ffffffcc; // for main text and headings\n --color-foreground-secondary: #9ca0a5; // for secondary text\n --color-foreground-muted: #81868d; // for muted text\n --color-foreground-border: #666666; // for content borders\n\n --color-background-primary: #131416; // for content\n --color-background-secondary: #1a1c1e; // for navigation + ToC\n --color-background-hover: #1e2124ff; // for navigation-item hover\n --color-background-hover--transparent: #1e212400;\n --color-background-border: #303335; // for UI borders\n --color-background-item: #444; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #2b8cee;\n --color-brand-content: #368ce2;\n\n // Highlighted text (search)\n --color-highlighted-background: #083563;\n\n // GUI Labels\n --color-guilabel-background: #08356380;\n --color-guilabel-border: #13395f80;\n\n // API documentation\n --color-api-keyword: var(--color-foreground-secondary);\n --color-highlight-on-target: #333300;\n\n // Admonitions\n --color-admonition-background: #18181a;\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: #18181a;\n --color-card-marginals-background: var(--color-background-hover);\n}\n","// This file contains the styling for making the content throughout the page,\n// including fonts, paragraphs, headings and spacing among these elements.\n\nbody\n font-family: var(--font-stack)\npre,\ncode,\nkbd,\nsamp\n font-family: var(--font-stack--monospace)\n\n// Make fonts look slightly nicer.\nbody\n -webkit-font-smoothing: antialiased\n -moz-osx-font-smoothing: grayscale\n\n// Line height from Bootstrap 4.1\narticle\n line-height: 1.5\n\n//\n// Headings\n//\nh1,\nh2,\nh3,\nh4,\nh5,\nh6\n line-height: 1.25\n font-weight: bold\n\n border-radius: 0.5rem\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n margin-left: -0.5rem\n margin-right: -0.5rem\n padding-left: 0.5rem\n padding-right: 0.5rem\n\n + p\n margin-top: 0\n\nh1\n font-size: 2.5em\n margin-top: 1.75rem\n margin-bottom: 1rem\nh2\n font-size: 2em\n margin-top: 1.75rem\nh3\n font-size: 1.5em\nh4\n font-size: 1.25em\nh5\n font-size: 1.125em\nh6\n font-size: 1em\n\nsmall\n opacity: 75%\n font-size: 80%\n\n// Paragraph\np\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n\n// Horizontal rules\nhr.docutils\n height: 1px\n padding: 0\n margin: 2rem 0\n background-color: var(--color-background-border)\n border: 0\n\n.centered\n text-align: center\n\n// Links\na\n text-decoration: underline\n\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &.muted-link\n color: inherit\n &:hover\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline--hover)\n","// This file contains the styles for the overall layouting of the documentation\n// skeleton, including the responsive changes as well as sidebar toggles.\n//\n// This is implemented as a mobile-last design, which isn't ideal, but it is\n// reasonably good-enough and I got pretty tired by the time I'd finished this\n// to move the rules around to fix this. Shouldn't take more than 3-4 hours,\n// if you know what you're doing tho.\n\n// HACK: Not all browsers account for the scrollbar width in media queries.\n// This results in horizontal scrollbars in the breakpoint where we go\n// from displaying everything to hiding the ToC. We accomodate for this by\n// adding a bit of padding to the TOC drawer, disabling the horizontal\n// scrollbar and allowing the scrollbars to cover the padding.\n// https://www.456bereastreet.com/archive/201301/media_query_width_and_vertical_scrollbars/\n\n// HACK: Always having the scrollbar visible, prevents certain browsers from\n// causing the content to stutter horizontally between taller-than-viewport and\n// not-taller-than-viewport pages.\n\nhtml\n overflow-x: hidden\n overflow-y: scroll\n scroll-behavior: smooth\n\n.sidebar-scroll, .toc-scroll, article[role=main] *\n // Override Firefox scrollbar style\n scrollbar-width: thin\n scrollbar-color: var(--color-foreground-border) transparent\n\n // Override Chrome scrollbar styles\n &::-webkit-scrollbar\n width: 0.25rem\n height: 0.25rem\n &::-webkit-scrollbar-thumb\n background-color: var(--color-foreground-border)\n border-radius: 0.125rem\n\n//\n// Overalls\n//\nhtml,\nbody\n height: 100%\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\narticle\n color: var(--color-content-foreground)\n background: var(--color-content-background)\n overflow-wrap: break-word\n\n.page\n display: flex\n // fill the viewport for pages with little content.\n min-height: 100%\n\n.mobile-header\n width: 100%\n height: var(--header-height)\n background-color: var(--color-header-background)\n color: var(--color-header-text)\n border-bottom: 1px solid var(--color-header-border)\n\n // Looks like sub-script/super-script have this, and we need this to\n // be \"on top\" of those.\n z-index: 10\n\n // We don't show the header on large screens.\n display: none\n\n // Add shadow when scrolled\n &.scrolled\n border-bottom: none\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.4rem rgba(0, 0, 0, 0.2)\n\n .header-center\n a\n color: var(--color-header-text)\n text-decoration: none\n\n.main\n display: flex\n flex: 1\n\n// Sidebar (left) also covers the entire left portion of screen.\n.sidebar-drawer\n box-sizing: border-box\n\n border-right: 1px solid var(--color-sidebar-background-border)\n background: var(--color-sidebar-background)\n\n display: flex\n justify-content: flex-end\n // These next two lines took me two days to figure out.\n width: calc((100% - #{$full-width}) / 2 + #{$sidebar-width})\n min-width: $sidebar-width\n\n// Scroll-along sidebars\n.sidebar-container,\n.toc-drawer\n box-sizing: border-box\n width: $sidebar-width\n\n.toc-drawer\n background: var(--color-toc-background)\n // See HACK described on top of this document\n padding-right: 1rem\n\n.sidebar-sticky,\n.toc-sticky\n position: sticky\n top: 0\n height: min(100%, 100vh)\n height: 100vh\n\n display: flex\n flex-direction: column\n\n.sidebar-scroll,\n.toc-scroll\n flex-grow: 1\n flex-shrink: 1\n\n overflow: auto\n scroll-behavior: smooth\n\n// Central items.\n.content\n padding: 0 $content-padding\n width: $content-width\n\n display: flex\n flex-direction: column\n justify-content: space-between\n\n.icon\n display: inline-block\n height: 1rem\n width: 1rem\n svg\n width: 100%\n height: 100%\n\n//\n// Accommodate announcement banner\n//\n.announcement\n background-color: var(--color-announcement-background)\n color: var(--color-announcement-text)\n\n height: var(--header-height)\n display: flex\n align-items: center\n overflow-x: auto\n & + .page\n min-height: calc(100% - var(--header-height))\n\n.announcement-content\n box-sizing: border-box\n padding: 0.5rem\n min-width: 100%\n white-space: nowrap\n text-align: center\n\n a\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-announcement-text)\n\n &:hover\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-link--hover)\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for theme\n////////////////////////////////////////////////////////////////////////////////\n.no-js .theme-toggle-container // don't show theme toggle if there's no JS\n display: none\n\n.theme-toggle-container\n vertical-align: middle\n\n.theme-toggle\n cursor: pointer\n border: none\n padding: 0\n background: transparent\n\n.theme-toggle svg\n vertical-align: middle\n height: 1rem\n width: 1rem\n color: var(--color-foreground-primary)\n display: none\n\n.theme-toggle-header\n float: left\n padding: 1rem 0.5rem\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for elements\n////////////////////////////////////////////////////////////////////////////////\n.toc-overlay-icon, .nav-overlay-icon\n display: none\n cursor: pointer\n\n .icon\n color: var(--color-foreground-secondary)\n height: 1rem\n width: 1rem\n\n.toc-header-icon, .nav-overlay-icon\n // for when we set display: flex\n justify-content: center\n align-items: center\n\n.toc-content-icon\n height: 1.5rem\n width: 1.5rem\n\n.content-icon-container\n float: right\n display: flex\n margin-top: 1.5rem\n margin-left: 1rem\n margin-bottom: 1rem\n gap: 0.5rem\n\n .edit-this-page svg\n color: inherit\n height: 1rem\n width: 1rem\n\n.sidebar-toggle\n position: absolute\n display: none\n// \n.sidebar-toggle[name=\"__toc\"]\n left: 20px\n.sidebar-toggle:checked\n left: 40px\n// \n\n.overlay\n position: fixed\n top: 0\n width: 0\n height: 0\n\n transition: width 0ms, height 0ms, opacity 250ms ease-out\n\n opacity: 0\n background-color: rgba(0, 0, 0, 0.54)\n.sidebar-overlay\n z-index: 20\n.toc-overlay\n z-index: 40\n\n// Keep things on top and smooth.\n.sidebar-drawer\n z-index: 30\n transition: left 250ms ease-in-out\n.toc-drawer\n z-index: 50\n transition: right 250ms ease-in-out\n\n// Show the Sidebar\n#__navigation:checked\n & ~ .sidebar-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .sidebar-drawer\n top: 0\n left: 0\n // Show the toc sidebar\n#__toc:checked\n & ~ .toc-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .toc-drawer\n top: 0\n right: 0\n\n////////////////////////////////////////////////////////////////////////////////\n// Back to top\n////////////////////////////////////////////////////////////////////////////////\n.back-to-top\n text-decoration: none\n\n display: none\n position: fixed\n left: 0\n top: 1rem\n padding: 0.5rem\n padding-right: 0.75rem\n border-radius: 1rem\n font-size: 0.8125rem\n\n background: var(--color-background-primary)\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), #6b728080 0px 0px 1px 0px\n\n z-index: 10\n\n margin-left: 50%\n transform: translateX(-50%)\n svg\n height: 1rem\n width: 1rem\n fill: currentColor\n display: inline-block\n\n span\n margin-left: 0.25rem\n\n .show-back-to-top &\n display: flex\n align-items: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Responsive layouting\n////////////////////////////////////////////////////////////////////////////////\n// Make things a bit bigger on bigger screens.\n@media (min-width: $full-width + $sidebar-width)\n html\n font-size: 110%\n\n@media (max-width: $full-width)\n // Collapse \"toc\" into the icon.\n .toc-content-icon\n display: flex\n .toc-drawer\n position: fixed\n height: 100vh\n top: 0\n right: -$sidebar-width\n border-left: 1px solid var(--color-background-muted)\n .toc-tree\n border-left: none\n font-size: var(--toc-font-size--mobile)\n\n // Accomodate for a changed content width.\n .sidebar-drawer\n width: calc((100% - #{$full-width - $sidebar-width}) / 2 + #{$sidebar-width})\n\n@media (max-width: $full-width - $sidebar-width)\n // Collapse \"navigation\".\n .nav-overlay-icon\n display: flex\n .sidebar-drawer\n position: fixed\n height: 100vh\n width: $sidebar-width\n\n top: 0\n left: -$sidebar-width\n\n // Swap which icon is visible.\n .toc-header-icon\n display: flex\n .toc-content-icon, .theme-toggle-content\n display: none\n .theme-toggle-header\n display: block\n\n // Show the header.\n .mobile-header\n position: sticky\n top: 0\n display: flex\n justify-content: space-between\n align-items: center\n\n .header-left,\n .header-right\n display: flex\n height: var(--header-height)\n padding: 0 var(--header-padding)\n label\n height: 100%\n width: 100%\n user-select: none\n\n .nav-overlay-icon .icon,\n .theme-toggle svg\n height: 1.25rem\n width: 1.25rem\n\n // Add a scroll margin for the content\n :target\n scroll-margin-top: var(--header-height)\n\n // Show back-to-top below the header\n .back-to-top\n top: calc(var(--header-height) + 0.5rem)\n\n // Center the page, and accommodate for the header.\n .page\n flex-direction: column\n justify-content: center\n .content\n margin-left: auto\n margin-right: auto\n\n@media (max-width: $content-width + 2* $content-padding)\n // Content should respect window limits.\n .content\n width: 100%\n overflow-x: auto\n\n@media (max-width: $content-width)\n .content\n padding: 0 $content-padding--small\n // Don't float sidebars to the right.\n article aside.sidebar\n float: none\n width: 100%\n margin: 1rem 0\n","//\n// The design here is strongly inspired by mkdocs-material.\n.admonition, .topic\n margin: 1rem auto\n padding: 0 0.5rem 0.5rem 0.5rem\n\n background: var(--color-admonition-background)\n\n border-radius: 0.2rem\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n font-size: var(--admonition-font-size)\n\n overflow: hidden\n page-break-inside: avoid\n\n // First element should have no margin, since the title has it.\n > :nth-child(2)\n margin-top: 0\n\n // Last item should have no margin, since we'll control that w/ padding\n > :last-child\n margin-bottom: 0\n\n.admonition p.admonition-title,\np.topic-title\n position: relative\n margin: 0 -0.5rem 0.5rem\n padding-left: 2rem\n padding-right: .5rem\n padding-top: .4rem\n padding-bottom: .4rem\n\n font-weight: 500\n font-size: var(--admonition-title-font-size)\n line-height: 1.3\n\n // Our fancy icon\n &::before\n content: \"\"\n position: absolute\n left: 0.5rem\n width: 1rem\n height: 1rem\n\n// Default styles\np.admonition-title\n background-color: var(--color-admonition-title-background)\n &::before\n background-color: var(--color-admonition-title)\n mask-image: var(--icon-admonition-default)\n mask-repeat: no-repeat\n\np.topic-title\n background-color: var(--color-topic-title-background)\n &::before\n background-color: var(--color-topic-title)\n mask-image: var(--icon-topic-default)\n mask-repeat: no-repeat\n\n//\n// Variants\n//\n.admonition\n border-left: 0.2rem solid var(--color-admonition-title)\n\n @each $type, $value in $admonitions\n &.#{$type}\n border-left-color: var(--color-admonition-title--#{$type})\n > .admonition-title\n background-color: var(--color-admonition-title-background--#{$type})\n &::before\n background-color: var(--color-admonition-title--#{$type})\n mask-image: var(--icon-#{nth($value, 2)})\n\n.admonition-todo > .admonition-title\n text-transform: uppercase\n","// This file stylizes the API documentation (stuff generated by autodoc). It's\n// deeply nested due to how autodoc structures the HTML without enough classes\n// to select the relevant items.\n\n// API docs!\ndl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)\n // Tweak the spacing of all the things!\n dd\n margin-left: 2rem\n > :first-child\n margin-top: 0.125rem\n > :last-child\n margin-bottom: 0.75rem\n\n // This is used for the arguments\n .field-list\n margin-bottom: 0.75rem\n\n // \"Headings\" (like \"Parameters\" and \"Return\")\n > dt\n text-transform: uppercase\n font-size: var(--font-size--small)\n\n dd:empty\n margin-bottom: 0.5rem\n dd > ul\n margin-left: -1.2rem\n > li\n > p:nth-child(2)\n margin-top: 0\n // When the last-empty-paragraph follows a paragraph, it doesn't need\n // to augument the existing spacing.\n > p + p:last-child:empty\n margin-top: 0\n margin-bottom: 0\n\n // Colorize the elements\n > dt\n color: var(--color-api-overall)\n\n.sig:not(.sig-inline)\n font-weight: bold\n\n font-size: var(--api-font-size)\n font-family: var(--font-stack--monospace)\n\n margin-left: -0.25rem\n margin-right: -0.25rem\n padding-top: 0.25rem\n padding-bottom: 0.25rem\n padding-right: 0.5rem\n\n // These are intentionally em, to properly match the font size.\n padding-left: 3em\n text-indent: -2.5em\n\n border-radius: 0.25rem\n\n background: var(--color-api-background)\n transition: background 100ms ease-out\n\n &:hover\n background: var(--color-api-background-hover)\n\n // adjust the size of the [source] link on the right.\n a.reference\n .viewcode-link\n font-weight: normal\n width: 3.5rem\n\nem.property\n font-style: normal\n &:first-child\n color: var(--color-api-keyword)\n.sig-name\n color: var(--color-api-name)\n.sig-prename\n font-weight: normal\n color: var(--color-api-pre-name)\n.sig-paren\n color: var(--color-api-paren)\n.sig-param\n font-style: normal\n\n.versionmodified\n font-style: italic\ndiv.versionadded, div.versionchanged, div.deprecated\n p\n margin-top: 0.125rem\n margin-bottom: 0.125rem\n\n// Align the [docs] and [source] to the right.\n.viewcode-link, .viewcode-back\n float: right\n text-align: right\n",".line-block\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n .line-block\n margin-top: 0rem\n margin-bottom: 0rem\n padding-left: 1rem\n","// Captions\narticle p.caption,\ntable > caption,\n.code-block-caption\n font-size: var(--font-size--small)\n text-align: center\n\n// Caption above a TOCTree\n.toctree-wrapper.compound\n .caption, :not(.caption) > .caption-text\n font-size: var(--font-size--small)\n text-transform: uppercase\n\n text-align: initial\n margin-bottom: 0\n\n > ul\n margin-top: 0\n margin-bottom: 0\n","// Inline code\ncode.literal, .sig-inline\n background: var(--color-inline-code-background)\n border-radius: 0.2em\n // Make the font smaller, and use padding to recover.\n font-size: var(--font-size--small--2)\n padding: 0.1em 0.2em\n\n pre.literal-block &\n font-size: inherit\n padding: 0\n\n p &\n border: 1px solid var(--color-background-border)\n\n.sig-inline\n font-family: var(--font-stack--monospace)\n\n// Code and Literal Blocks\n$code-spacing-vertical: 0.625rem\n$code-spacing-horizontal: 0.875rem\n\n// Wraps every literal block + line numbers.\ndiv[class*=\" highlight-\"],\ndiv[class^=\"highlight-\"]\n margin: 1em 0\n display: flex\n\n .table-wrapper\n margin: 0\n padding: 0\n\npre\n margin: 0\n padding: 0\n overflow: auto\n\n // Needed to have more specificity than pygments' \"pre\" selector. :(\n article[role=\"main\"] .highlight &\n line-height: 1.5\n\n &.literal-block,\n .highlight &\n font-size: var(--code-font-size)\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n // Make it look like all the other blocks.\n &.literal-block\n margin-top: 1rem\n margin-bottom: 1rem\n\n border-radius: 0.2rem\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n\n// All code is always contained in this.\n.highlight\n width: 100%\n border-radius: 0.2rem\n\n // Make line numbers and prompts un-selectable.\n .gp, span.linenos\n user-select: none\n pointer-events: none\n\n // Expand the line-highlighting.\n .hll\n display: block\n margin-left: -$code-spacing-horizontal\n margin-right: -$code-spacing-horizontal\n padding-left: $code-spacing-horizontal\n padding-right: $code-spacing-horizontal\n\n/* Make code block captions be nicely integrated */\n.code-block-caption\n display: flex\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n border-radius: 0.25rem\n border-bottom-left-radius: 0\n border-bottom-right-radius: 0\n font-weight: 300\n border-bottom: 1px solid\n\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n border-color: var(--color-background-border)\n\n + div[class]\n margin-top: 0\n pre\n border-top-left-radius: 0\n border-top-right-radius: 0\n\n// When `html_codeblock_linenos_style` is table.\n.highlighttable\n width: 100%\n display: block\n tbody\n display: block\n\n tr\n display: flex\n\n // Line numbers\n td.linenos\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n padding: $code-spacing-vertical $code-spacing-horizontal\n padding-right: 0\n border-top-left-radius: 0.2rem\n border-bottom-left-radius: 0.2rem\n\n .linenodiv\n padding-right: $code-spacing-horizontal\n font-size: var(--code-font-size)\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n\n // Actual code\n td.code\n padding: 0\n display: block\n flex: 1\n overflow: hidden\n\n .highlight\n border-top-left-radius: 0\n border-bottom-left-radius: 0\n\n// When `html_codeblock_linenos_style` is inline.\n.highlight\n span.linenos\n display: inline-block\n padding-left: 0\n padding-right: $code-spacing-horizontal\n margin-right: $code-spacing-horizontal\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n","// Inline Footnote Reference\n.footnote-reference\n font-size: var(--font-size--small--4)\n vertical-align: super\n\n// Definition list, listing the content of each note.\n// docutils <= 0.17\ndl.footnote.brackets\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\n display: grid\n grid-template-columns: max-content auto\n dt\n margin: 0\n > .fn-backref\n margin-left: 0.25rem\n\n &:after\n content: \":\"\n\n .brackets\n &:before\n content: \"[\"\n &:after\n content: \"]\"\n\n dd\n margin: 0\n padding: 0 1rem\n\n// docutils >= 0.18\naside.footnote\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\naside.footnote > span,\ndiv.citation > span\n float: left\n font-weight: 500\n padding-right: 0.25rem\n\naside.footnote > p,\ndiv.citation > p\n margin-left: 2rem\n","//\n// Figures\n//\nimg\n box-sizing: border-box\n max-width: 100%\n height: auto\n\narticle\n figure, .figure\n border-radius: 0.2rem\n\n margin: 0\n :last-child\n margin-bottom: 0\n\n .align-left\n float: left\n clear: left\n margin: 0 1rem 1rem\n\n .align-right\n float: right\n clear: right\n margin: 0 1rem 1rem\n\n .align-default,\n .align-center\n display: block\n text-align: center\n margin-left: auto\n margin-right: auto\n\n // WELL, table needs to be stylised like a table.\n table.align-default\n display: table\n text-align: initial\n",".genindex-jumpbox, .domainindex-jumpbox\n border-top: 1px solid var(--color-background-border)\n border-bottom: 1px solid var(--color-background-border)\n padding: 0.25rem\n\n.genindex-section, .domainindex-section\n h2\n margin-top: 0.75rem\n margin-bottom: 0.5rem\n ul\n margin-top: 0\n margin-bottom: 0\n","ul,\nol\n padding-left: 1.2rem\n\n // Space lists out like paragraphs\n margin-top: 1rem\n margin-bottom: 1rem\n // reduce margins within li.\n li\n > p:first-child\n margin-top: 0.25rem\n margin-bottom: 0.25rem\n\n > p:last-child\n margin-top: 0.25rem\n\n > ul,\n > ol\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n\nol\n &.arabic\n list-style: decimal\n &.loweralpha\n list-style: lower-alpha\n &.upperalpha\n list-style: upper-alpha\n &.lowerroman\n list-style: lower-roman\n &.upperroman\n list-style: upper-roman\n\n// Don't space lists out when they're \"simple\" or in a `.. toctree::`\n.simple,\n.toctree-wrapper\n li\n > ul,\n > ol\n margin-top: 0\n margin-bottom: 0\n\n// Definition Lists\n.field-list,\n.option-list,\ndl:not([class]),\ndl.simple,\ndl.footnote,\ndl.glossary\n dt\n font-weight: 500\n margin-top: 0.25rem\n + dt\n margin-top: 0\n\n .classifier::before\n content: \":\"\n margin-left: 0.2rem\n margin-right: 0.2rem\n\n dd\n > p:first-child,\n ul\n margin-top: 0.125rem\n\n ul\n margin-bottom: 0.125rem\n",".math-wrapper\n width: 100%\n overflow-x: auto\n\ndiv.math\n position: relative\n text-align: center\n\n .headerlink,\n &:focus .headerlink\n display: none\n\n &:hover .headerlink\n display: inline-block\n\n span.eqno\n position: absolute\n right: 0.5rem\n top: 50%\n transform: translate(0, -50%)\n z-index: 1\n","// Abbreviations\nabbr[title]\n cursor: help\n\n// \"Problematic\" content, as identified by Sphinx\n.problematic\n color: var(--color-problematic)\n\n// Keyboard / Mouse \"instructions\"\nkbd:not(.compound)\n margin: 0 0.2rem\n padding: 0 0.2rem\n border-radius: 0.2rem\n border: 1px solid var(--color-foreground-border)\n color: var(--color-foreground-primary)\n vertical-align: text-bottom\n\n font-size: var(--font-size--small--3)\n display: inline-block\n\n box-shadow: 0 0.0625rem 0 rgba(0, 0, 0, 0.2), inset 0 0 0 0.125rem var(--color-background-primary)\n\n background-color: var(--color-background-secondary)\n\n// Blockquote\nblockquote\n border-left: 4px solid var(--color-background-border)\n background: var(--color-background-secondary)\n\n margin-left: 0\n margin-right: 0\n padding: 0.5rem 1rem\n\n .attribution\n font-weight: 600\n text-align: right\n\n &.pull-quote,\n &.highlights\n font-size: 1.25em\n\n &.epigraph,\n &.pull-quote\n border-left-width: 0\n border-radius: 0.5rem\n\n &.highlights\n border-left-width: 0\n background: transparent\n\n// Center align embedded-in-text images\np .reference img\n vertical-align: middle\n","p.rubric\n line-height: 1.25\n font-weight: bold\n font-size: 1.125em\n\n // For Numpy-style documentation that's got rubrics within it.\n // https://github.com/pradyunsg/furo/discussions/505\n dd &\n line-height: inherit\n font-weight: inherit\n\n font-size: var(--font-size--small)\n text-transform: uppercase\n","article .sidebar\n float: right\n clear: right\n width: 30%\n\n margin-left: 1rem\n margin-right: 0\n\n border-radius: 0.2rem\n background-color: var(--color-background-secondary)\n border: var(--color-background-border) 1px solid\n\n > *\n padding-left: 1rem\n padding-right: 1rem\n\n > ul, > ol // lists need additional padding, because bullets.\n padding-left: 2.2rem\n\n .sidebar-title\n margin: 0\n padding: 0.5rem 1rem\n border-bottom: var(--color-background-border) 1px solid\n\n font-weight: 500\n\n// TODO: subtitle\n// TODO: dedicated variables?\n",".table-wrapper\n width: 100%\n overflow-x: auto\n margin-top: 1rem\n margin-bottom: 0.5rem\n padding: 0.2rem 0.2rem 0.75rem\n\ntable.docutils\n border-radius: 0.2rem\n border-spacing: 0\n border-collapse: collapse\n\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n th\n background: var(--color-table-header-background)\n\n td,\n th\n // Space things out properly\n padding: 0 0.25rem\n\n // Get the borders looking just-right.\n border-left: 1px solid var(--color-table-border)\n border-right: 1px solid var(--color-table-border)\n border-bottom: 1px solid var(--color-table-border)\n\n p\n margin: 0.25rem\n\n &:first-child\n border-left: none\n &:last-child\n border-right: none\n\n // MyST-parser tables set these classes for control of column alignment\n &.text-left\n text-align: left\n &.text-right\n text-align: right\n &.text-center\n text-align: center\n",":target\n scroll-margin-top: 0.5rem\n\n@media (max-width: $full-width - $sidebar-width)\n :target\n scroll-margin-top: calc(0.5rem + var(--header-height))\n\n // When a heading is selected\n section > span:target\n scroll-margin-top: calc(0.8rem + var(--header-height))\n\n// Permalinks\n.headerlink\n font-weight: 100\n user-select: none\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\ndl dt,\np.caption,\nfigcaption p,\ntable > caption,\n.code-block-caption\n > .headerlink\n margin-left: 0.5rem\n visibility: hidden\n &:hover > .headerlink\n visibility: visible\n\n // Don't change to link-like, if someone adds the contents directive.\n > .toc-backref\n color: inherit\n text-decoration-line: none\n\n// Figure and table captions are special.\nfigure:hover > figcaption > p > .headerlink,\ntable:hover > caption > .headerlink\n visibility: visible\n\n:target >, // Regular section[id] style anchors\nspan:target ~ // Non-regular span[id] style \"extra\" anchors\n h1,\n h2,\n h3,\n h4,\n h5,\n h6\n &:nth-of-type(1)\n background-color: var(--color-highlight-on-target)\n // .headerlink\n // visibility: visible\n code.literal\n background-color: transparent\n\ntable:target > caption,\nfigure:target\n background-color: var(--color-highlight-on-target)\n\n// Inline page contents\n.this-will-duplicate-information-and-it-is-still-useful-here li :target\n background-color: var(--color-highlight-on-target)\n\n// Code block permalinks\n.literal-block-wrapper:target .code-block-caption\n background-color: var(--color-highlight-on-target)\n\n// When a definition list item is selected\n//\n// There isn't really an alternative to !important here, due to the\n// high-specificity of API documentation's selector.\ndt:target\n background-color: var(--color-highlight-on-target) !important\n\n// When a footnote reference is selected\n.footnote > dt:target + dd,\n.footnote-reference:target\n background-color: var(--color-highlight-on-target)\n",".guilabel\n background-color: var(--color-guilabel-background)\n border: 1px solid var(--color-guilabel-border)\n color: var(--color-guilabel-text)\n\n padding: 0 0.3em\n border-radius: 0.5em\n font-size: 0.9em\n","// This file contains the styles used for stylizing the footer that's shown\n// below the content.\n\nfooter\n font-size: var(--font-size--small)\n display: flex\n flex-direction: column\n\n margin-top: 2rem\n\n// Bottom of page information\n.bottom-of-page\n display: flex\n align-items: center\n justify-content: space-between\n\n margin-top: 1rem\n padding-top: 1rem\n padding-bottom: 1rem\n\n color: var(--color-foreground-secondary)\n border-top: 1px solid var(--color-background-border)\n\n line-height: 1.5\n\n @media (max-width: $content-width)\n text-align: center\n flex-direction: column-reverse\n gap: 0.25rem\n\n .left-details\n font-size: var(--font-size--small)\n\n .right-details\n display: flex\n flex-direction: column\n gap: 0.25rem\n text-align: right\n\n .icons\n display: flex\n justify-content: flex-end\n gap: 0.25rem\n font-size: 1rem\n\n a\n text-decoration: none\n\n svg,\n img\n font-size: 1.125rem\n height: 1em\n width: 1em\n\n// Next/Prev page information\n.related-pages\n a\n display: flex\n align-items: center\n\n text-decoration: none\n &:hover .page-info .title\n text-decoration: underline\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n svg.furo-related-icon,\n svg.furo-related-icon > use\n flex-shrink: 0\n\n color: var(--color-foreground-border)\n\n width: 0.75rem\n height: 0.75rem\n margin: 0 0.5rem\n\n &.next-page\n max-width: 50%\n\n float: right\n clear: right\n text-align: right\n\n &.prev-page\n max-width: 50%\n\n float: left\n clear: left\n\n svg\n transform: rotate(180deg)\n\n.page-info\n display: flex\n flex-direction: column\n overflow-wrap: anywhere\n\n .next-page &\n align-items: flex-end\n\n .context\n display: flex\n align-items: center\n\n padding-bottom: 0.1rem\n\n color: var(--color-foreground-muted)\n font-size: var(--font-size--small)\n text-decoration: none\n","// This file contains the styles for the contents of the left sidebar, which\n// contains the navigation tree, logo, search etc.\n\n////////////////////////////////////////////////////////////////////////////////\n// Brand on top of the scrollable tree.\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-brand\n display: flex\n flex-direction: column\n flex-shrink: 0\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n text-decoration: none\n\n.sidebar-brand-text\n color: var(--color-sidebar-brand-text)\n overflow-wrap: break-word\n margin: var(--sidebar-item-spacing-vertical) 0\n font-size: 1.5rem\n\n.sidebar-logo-container\n margin: var(--sidebar-item-spacing-vertical) 0\n\n.sidebar-logo\n margin: 0 auto\n display: block\n max-width: 100%\n\n////////////////////////////////////////////////////////////////////////////////\n// Search\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-search-container\n display: flex\n align-items: center\n margin-top: var(--sidebar-search-space-above)\n\n position: relative\n\n background: var(--color-sidebar-search-background)\n &:hover,\n &:focus-within\n background: var(--color-sidebar-search-background--focus)\n\n &::before\n content: \"\"\n position: absolute\n left: var(--sidebar-item-spacing-horizontal)\n width: var(--sidebar-search-icon-size)\n height: var(--sidebar-search-icon-size)\n\n background-color: var(--color-sidebar-search-icon)\n mask-image: var(--icon-search)\n\n.sidebar-search\n box-sizing: border-box\n\n border: none\n border-top: 1px solid var(--color-sidebar-search-border)\n border-bottom: 1px solid var(--color-sidebar-search-border)\n\n padding-top: var(--sidebar-search-input-spacing-vertical)\n padding-bottom: var(--sidebar-search-input-spacing-vertical)\n padding-right: var(--sidebar-search-input-spacing-horizontal)\n padding-left: calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size))\n\n width: 100%\n\n color: var(--color-sidebar-search-foreground)\n background: transparent\n z-index: 10\n\n &:focus\n outline: none\n\n &::placeholder\n font-size: var(--sidebar-search-input-font-size)\n\n//\n// Hide Search Matches link\n//\n#searchbox .highlight-link\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0\n margin: 0\n text-align: center\n\n a\n color: var(--color-sidebar-search-icon)\n font-size: var(--font-size--small--2)\n\n////////////////////////////////////////////////////////////////////////////////\n// Structure/Skeleton of the navigation tree (left)\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-tree\n font-size: var(--sidebar-item-font-size)\n margin-top: var(--sidebar-tree-space-above)\n margin-bottom: var(--sidebar-item-spacing-vertical)\n\n ul\n padding: 0\n margin-top: 0\n margin-bottom: 0\n\n display: flex\n flex-direction: column\n\n list-style: none\n\n li\n position: relative\n margin: 0\n\n > ul\n margin-left: var(--sidebar-item-spacing-horizontal)\n\n .icon\n color: var(--color-sidebar-link-text)\n\n .reference\n box-sizing: border-box\n color: var(--color-sidebar-link-text)\n\n // Fill the parent.\n display: inline-block\n line-height: var(--sidebar-item-line-height)\n text-decoration: none\n\n // Don't allow long words to cause wrapping.\n overflow-wrap: anywhere\n\n height: 100%\n width: 100%\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n &:hover\n background: var(--color-sidebar-item-background--hover)\n\n // Add a nice little \"external-link\" arrow here.\n &.external::after\n content: url('data:image/svg+xml, ')\n margin: 0 0.25rem\n vertical-align: middle\n color: var(--color-sidebar-link-text)\n\n // Make the current page reference bold.\n .current-page > .reference\n font-weight: bold\n\n label\n position: absolute\n top: 0\n right: 0\n height: var(--sidebar-item-height)\n width: var(--sidebar-expander-width)\n\n cursor: pointer\n user-select: none\n\n display: flex\n justify-content: center\n align-items: center\n\n .caption, :not(.caption) > .caption-text\n font-size: var(--sidebar-caption-font-size)\n color: var(--color-sidebar-caption-text)\n\n font-weight: bold\n text-transform: uppercase\n\n margin: var(--sidebar-caption-space-above) 0 0 0\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n // If it has children, add a bit more padding to wrap the content to avoid\n // overlapping with the \n li.has-children\n > .reference\n padding-right: var(--sidebar-expander-width)\n\n // Colorize the top-level list items and icon.\n .toctree-l1\n & > .reference,\n & > label .icon\n color: var(--color-sidebar-link-text--top-level)\n\n // Color changes on hover\n label\n background: var(--color-sidebar-item-expander-background)\n &:hover\n background: var(--color-sidebar-item-expander-background--hover)\n\n .current > .reference\n background: var(--color-sidebar-item-background--current)\n &:hover\n background: var(--color-sidebar-item-background--hover)\n\n.toctree-checkbox\n position: absolute\n display: none\n\n////////////////////////////////////////////////////////////////////////////////\n// Togglable expand/collapse\n////////////////////////////////////////////////////////////////////////////////\n.toctree-checkbox\n ~ ul\n display: none\n\n ~ label .icon svg\n transform: rotate(90deg)\n\n.toctree-checkbox:checked\n ~ ul\n display: block\n\n ~ label .icon svg\n transform: rotate(-90deg)\n","// This file contains the styles for the contents of the right sidebar, which\n// contains the table of contents for the current page.\n.toc-title-container\n padding: var(--toc-title-padding)\n padding-top: var(--toc-spacing-vertical)\n\n.toc-title\n color: var(--color-toc-title-text)\n font-size: var(--toc-title-font-size)\n padding-left: var(--toc-spacing-horizontal)\n text-transform: uppercase\n\n// If the ToC is not present, hide these elements coz they're not relevant.\n.no-toc\n display: none\n\n.toc-tree-container\n padding-bottom: var(--toc-spacing-vertical)\n\n.toc-tree\n font-size: var(--toc-font-size)\n line-height: 1.3\n border-left: 1px solid var(--color-background-border)\n\n padding-left: calc(var(--toc-spacing-horizontal) - var(--toc-item-spacing-horizontal))\n\n // Hide the first \"top level\" bullet.\n > ul > li:first-child\n padding-top: 0\n & > ul\n padding-left: 0\n & > a\n display: none\n\n ul\n list-style-type: none\n margin-top: 0\n margin-bottom: 0\n padding-left: var(--toc-item-spacing-horizontal)\n li\n padding-top: var(--toc-item-spacing-vertical)\n\n &.scroll-current >.reference\n color: var(--color-toc-item-text--active)\n font-weight: bold\n\n .reference\n color: var(--color-toc-item-text)\n text-decoration: none\n overflow-wrap: anywhere\n\n.toc-scroll\n max-height: 100vh\n overflow-y: scroll\n\n// Be very annoying when someone includes the table of contents\n.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here)\n color: var(--color-problematic)\n background: rgba(255, 0, 0, 0.25)\n &::before\n content: \"ERROR: Adding a table of contents in Furo-based documentation is unnecessary, and does not work well with existing styling.Add a 'this-will-duplicate-information-and-it-is-still-useful-here' class, if you want an escape hatch.\"\n","// Shameful hacks, to work around bugs.\n\n// MyST parser doesn't correctly generate classes, to align table contents.\n// https://github.com/executablebooks/MyST-Parser/issues/412\n.text-align\\:left > p\n text-align: left\n\n.text-align\\:center > p\n text-align: center\n\n.text-align\\:right > p\n text-align: right\n"],"names":[],"sourceRoot":""}
\ No newline at end of file
diff --git a/code/capellambse.aird.html b/code/capellambse.aird.html
new file mode 100644
index 000000000..5a6864922
--- /dev/null
+++ b/code/capellambse.aird.html
@@ -0,0 +1,603 @@
+
+
+
+
+
+
+
+
+ capellambse.aird package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.aird package
+Functions for parsing and interacting with diagrams in a Capella model.
+
+
+class capellambse.aird. ActiveFilters
+Bases: MutableSet
[str
]
+A set of active filters on a Diagram.
+Enable access to set, add and remove active filters on a
+Diagram
.
+
+
+__init__ ( model , diagram )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+add ( value )
+Add an activated filter to the diagram.
+Writes a new <activatedFilters>
XML element to the
+<diagram:DSemanticDiagram>
XML element. If the value
is
+not apparent in capellambse.aird.GLOBAL_FILTERS
as a key
+it can not be applied when rendering. It should still be visible
+in the GUI.
+
+Parameters:
+value (str ) –
+
+Return type:
+None
+
+
+
+
+
+
+discard ( value )
+Remove the filter with the given value
from the diagram.
+Deletes <activatedFilters>
XML element from the diagram
+element tree.
+
+Parameters:
+value (str ) –
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.aird. DRepresentationDescriptor
+A representation descriptor.
+These are specific _Element
s found in AIRD files,
+which contain metadata about diagrams.
+alias of object
+
+
+
+
+class capellambse.aird. DiagramDescriptor
+Bases: NamedTuple
+DiagramDescriptor(fragment, name, styleclass, descriptor, uid, viewpoint, target)
+
+
+descriptor : _Element
+Alias for field number 3
+
+
+
+
+fragment : PurePosixPath
+Alias for field number 0
+
+
+
+
+name : str
+Alias for field number 1
+
+
+
+
+styleclass : str | None
+Alias for field number 2
+
+
+
+
+target : _Element
+Alias for field number 6
+
+
+
+
+uid : str
+Alias for field number 4
+
+
+
+
+viewpoint : str
+Alias for field number 5
+
+
+
+
+
+
+capellambse.aird. enumerate_descriptors ( model , * , viewpoint = None )
+Enumerate the representation descriptors in the model.
+
+Parameters:
+
+model (MelodyLoader ) – The MelodyLoader instance
+viewpoint (str | None ) – Only return diagrams of the given viewpoint. If not given, all
+diagrams are returned.
+
+
+Return type:
+Iterator [DRepresentationDescriptor ]
+
+
+
+
+
+
+capellambse.aird. enumerate_diagrams ( model )
+Enumerate the diagrams in the model.
+
+Parameters:
+model (MelodyLoader ) – The MelodyLoader instance
+
+Return type:
+Iterator [DiagramDescriptor ]
+
+
+
+
+
+
+capellambse.aird. find_target ( model , descriptor )
+
+Parameters:
+
+
+Return type:
+_Element
+
+
+
+
+
+
+capellambse.aird. get_styleclass ( descriptor )
+
+Parameters:
+descriptor (DRepresentationDescriptor ) –
+
+Return type:
+str | None
+
+
+
+
+
+
+capellambse.aird. iter_visible ( model , descriptor )
+Iterate over all semantic elements that are visible in a diagram.
+This is a much faster alternative to calling parse_diagram()
+and iterating over the diagram elements, if you only need to know
+which semantic elements are visible, but are not otherwise
+interested in the layout of the diagram.
+
+Parameters:
+
+
+Raises:
+ValueError – If the corresponding data or style element can’t be found in the
+ *.aird
file.
+
+Yields:
+etree._Element – A semantic element from the *.capella
file.
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+capellambse.aird. parse_diagram ( model , descriptor , ** params )
+Parse a single diagram from the model.
+
+Parameters:
+
+
+Return type:
+Diagram
+
+
+
+
+
+
+capellambse.aird. parse_diagrams ( model , ** params )
+Parse all diagrams from the model.
+
+Parameters:
+
+
+Return type:
+Iterator [Diagram ]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.diagram.html b/code/capellambse.diagram.html
new file mode 100644
index 000000000..3a04e33f0
--- /dev/null
+++ b/code/capellambse.diagram.html
@@ -0,0 +1,1627 @@
+
+
+
+
+
+
+
+
+ capellambse.diagram package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.diagram package
+Various diagramming related tools.
+This module is used to create diagrams, which can then be exported in
+various formats (such as SVG).
+
+
+class capellambse.diagram. Box
+Bases: object
+A Box.
+Some may call it rectangle.
+
+
+CHILD_MARGIN = 2
+
+
+
+
+JSON_TYPE = 'box'
+
+
+
+
+PORT_OVERHANG = 2
+
+
+
+
+__init__ ( pos , size , * , label = '' , floating_labels = None , description = None , uuid = None , parent = None , collapsed = False , minsize = (0, 0) , maxsize = (inf, inf) , context = None , port = False , features = None , styleclass = None , styleoverrides = None , hidelabel = False , hidden = False )
+Create a new box.
+
+Parameters:
+
+pos (Tuple [ float | int , float | int ] ) – A Vector2D describing the spatial position.
+size (Tuple [ float | int , float | int ] ) – A Vector2D describing the box’ size. If one or both of its
+components are 0, it/they will be calculated based on the
+Box’ label text and contained children.
+label (str ) – This box’ label text.
+floating_labels (MutableSequence [ Box ] | None ) – Additional box labels.
+description (str | None ) – Optional label text used only by Representation Links.
+uuid (str | None ) – UUID of the semantic element this box represents.
+parent (Box | None ) – This box’ parent box.
+collapsed (bool ) – Collapse this box and hide all its children. Note that
+setting this flag does not change the box’ size.
+minsize (Tuple [ float | int , float | int ] ) – When dynamically calculating Box size, the minimum size it
+should have. Default: zero.
+maxsize (Tuple [ float | int , float | int ] ) – When dynamically calculating Box size, the maximum size it
+can have. Default: infinite.
+context (Iterable [ str ] | None ) – A list of UUIDs of objects in this box’ context. This
+includes children and associated edges.
+port (bool ) – Flag this box as a port. Affects how context is added.
+features (MutableSequence [ str ] | None ) – Certain classes of Box (like Class
) have features, which
+is a list of strings that will be displayed inside the Box,
+separated from the label by a horizontal line.
+styleclass (str | None ) – The CSS style class to use.
+styleoverrides (MutableMapping [ str , str | RGB | MutableSequence [ str | RGB ] ] | None ) – A dict of CSS properties to override.
+hidelabel (bool ) – Set to True to skip drawing this box’ label.
+hidden (bool ) – Set to True to skip drawing this entire box.
+
+
+Return type:
+None
+
+
+
+
+
+
+add_context ( uuid )
+Add a UUID as context for this box.
+The context will bubble to the immediate parent if this box is a
+port.
+
+Parameters:
+uuid (str ) –
+
+Return type:
+None
+
+
+
+
+
+
+property bounds : Box
+Calculate the bounding box of this Box.
+
+
+
+
+property center : Vector2D
+Return the center point of this Box.
+
+
+
+
+context : set [ str ]
+
+
+
+
+create_portlabel ( labeltext , margin = 2 )
+Add a label to a port box.
+The port that this is called for must be snapped to its parent’s
+left or right side.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+property hidden : bool
+Return whether to skip this Box during rendering.
+
+
+
+
+maxsize
+A property that automatically converts 2-tuples into Vector2D.
+
+
+
+
+minsize
+A property that automatically converts 2-tuples into Vector2D.
+
+
+
+
+move ( offset , * , children = True )
+Move the box by the specified offset.
+
+Parameters:
+
+offset (Vector2D ) – The offset to move the box by.
+children (bool ) – Recursively move children as well. If False, the positions
+of children need to be adjusted separately.
+
+
+Return type:
+None
+
+
+
+
+
+
+property padding : Vector2D
+Return the horizontal and vertical padding of label text.
+
+
+
+
+property parent : Box | None
+Return the parent element of this Box.
+
+
+
+
+pos
+A property that automatically converts 2-tuples into Vector2D.
+
+
+
+
+property size : Vector2D
+Return the size of this Box.
+
+
+
+
+snap_to_parent ( )
+Snap this Box into the constraints set by its parent.
+If this Box is a port, ensure it lines up with the parent’s
+border, keeping an overhang of 2px.
+Otherwise, ensures that this Box will not overflow out of the
+parent’s border, keeping a padding of 2px.
+
+Return type:
+None
+
+
+
+
+
+
+vector_snap ( point , * , source = None , style = RoutingStyle.OBLIQUE )
+Snap the point
into this Box, coming from source
.
+
+Parameters:
+
+
+Return type:
+Vector2D
+
+
+
+
+
+
+
+
+class capellambse.diagram. Circle
+Bases: object
+Represents a circle.
+
+
+JSON_TYPE = 'circle'
+
+
+
+
+__init__ ( center , radius , * , uuid = None , styleclass = None , styleoverrides = None , hidden = False , context = None )
+Construct a Circle.
+
+Parameters:
+
+center (Tuple [ float | int , float | int ] ) – The Circle’s center point as Vector2D or 2-tuple.
+radius (float | int ) – The Circle radius in pixels.
+uuid (str | None ) – The Circle’s unique identifier.
+styleclass (str | None ) – The Circle’s CSS class.
+styleoverrides (MutableMapping [ str , str | RGB | MutableSequence [ str | RGB ] ] | None ) – Dict of CSS key/value pairs that override the class
+defaults.
+hidden (bool ) – True to skip drawing this Circle.
+context (Iterable [ str ] | None ) – A list of UUIDs of objects in this circle’s context.
+
+
+
+
+
+
+
+add_context ( uuid )
+Add a UUID as context for this circle.
+
+Parameters:
+uuid (str ) –
+
+Return type:
+None
+
+
+
+
+
+
+property bounds : Box
+Calculate the bounding box of this Circle.
+
+
+
+
+center
+A property that automatically converts 2-tuples into Vector2D.
+
+
+
+
+collapsed = False
+
+
+
+
+context : set [ str ]
+
+
+
+
+hidelabel = True
+
+
+
+
+label = None
+
+
+
+
+move ( offset , * , children = True )
+Move this Circle on the 2-dimensional plane.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+port = False
+
+
+
+
+vector_snap ( vector , * , source , style = RoutingStyle.OBLIQUE )
+Snap the vector onto this Circle, preferably in direction.
+
+Parameters:
+
+
+Return type:
+Vector2D
+
+
+
+
+
+
+
+
+class capellambse.diagram. Diagram
+Bases: object
+A complete diagram, including all elements required by it.
+
+
+__init__ ( name = 'Untitled Diagram' , viewport = None , elements = None , * , uuid = None , styleclass = None , params = None )
+Construct a new diagram.
+
+Parameters:
+
+name (str ) – The diagram’s name.
+viewport (Box | None ) – A Box describing this diagram’s viewport.
+elements (Sequence [ Box | Edge | Circle ] | None ) – A list
containing the diagram’s initial elements.
+uuid (str | None ) – The unique ID of this diagram.
+styleclass (str | None ) – The diagram class.
+params (dict [ str , Any ] | None ) – Additional parameters.
+
+
+
+
+
+
+
+add_element ( element , extend_viewport = True , * , force = False )
+Add an element to this diagram.
+
+Parameters:
+
+element (Box | Edge | Circle ) – The element to add.
+extend_viewport (bool ) – True to automatically extend the diagram viewport so that
+the added element is fully visible.
+force (bool ) – Normally an exception will be raised if another element with
+the same UUID as the new one already exists in the diagram.
+If this is set to True, the old element will be overwritten
+instead.
+
+
+Return type:
+None
+
+
+
+
+
+
+calculate_viewport ( )
+Recalculate the viewport so that all elements are contained.
+
+Return type:
+None
+
+
+
+
+
+
+normalize_viewport ( offset = 0 )
+Normalize the viewport.
+This function moves all elements contained within this diagram
+so that the top left corner of the viewport is at (0, 0) (or the
+specified offset, if given).
+If a single value is given as offset, it is applied to both X
+and Y coordinates.
+
+Parameters:
+offset (float | int | Tuple [ float | int , float | int ] ) –
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.diagram. DiagramJSONEncoder
+Bases: JSONEncoder
+JSON encoder that knows how to handle AIRD diagrams.
+
+
+default ( o )
+Implement this method in a subclass such that it returns
+a serializable object for o
, or calls the base implementation
+(to raise a TypeError
).
+For example, to support arbitrary iterators, you could
+implement default like this:
+def default ( self , o ):
+ try :
+ iterable = iter ( o )
+ except TypeError :
+ pass
+ else :
+ return list ( iterable )
+ # Let the base class default method raise the TypeError
+ return JSONEncoder . default ( self , o )
+
+
+
+Parameters:
+o (object ) –
+
+Return type:
+object
+
+
+
+
+
+
+
+
+class capellambse.diagram. Edge
+Bases: Vec2List
+An edge in the diagram.
+An Edge consists of a series of points that are traversed in order.
+Each point is given as Vector2D containing absolute coordinates. At
+least two points are required.
+
+
+JSON_TYPE = 'edge'
+
+
+
+
+__init__ ( points , * , labels = None , uuid = None , source = None , target = None , styleclass = None , styleoverrides = None , hidden = False , context = None )
+Construct an Edge.
+
+Parameters:
+
+source (Box | Edge | Circle | None ) – The source diagram element of this Edge.
+target (Box | Edge | Circle | None ) – The target diagram element of this Edge.
+labels (MutableSequence [ Box ] | None ) – Labels for this Edge. Each label is a Box
with pos
,
+size
and a simple str
label. Other configurations of
+Boxes are not supported. The hidden
flag is honored
+during rendering calculations.
+points (Iterable [ Tuple [ float | int , float | int ] ] ) – A list of Vector2D
s with the (absolute) points this
+edge follows.
+uuid (str | None ) – UUID of the semantic element this Edge represents.
+styleclass (str | None ) – The CSS style class to use.
+styleoverrides (MutableMapping [ str , str | RGB | MutableSequence [ str | RGB ] ] | None ) – A dict of CSS properties to override.
+hidden (bool ) – True to skip drawing this edge entirely.
+context (Iterable [ str ] | None ) – A list of UUIDs of objects in this edge’s context.
+
+
+
+
+
+
+
+add_context ( uuid )
+Add a UUID as context for this edge.
+
+Parameters:
+uuid (str ) –
+
+Return type:
+None
+
+
+
+
+
+
+property bounds : Box
+Calculate the bounding Box of this Edge.
+
+
+
+
+property center : Vector2D
+Calculate the point in the middle of this edge.
+
+
+
+
+collapsed = False
+
+
+
+
+context : set [ str ]
+
+
+
+
+property hidden : bool
+Return whether to skip this Edge during rendering.
+
+
+
+
+hidelabel = False
+
+
+
+
+property length : float
+Return length of this edge.
+
+
+
+
+move ( offset , * , children = True )
+Move all points of this edge by the specified offset.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+property points : Vec2List
+Return an iterable over this edge’s points.
+
+
+
+
+port = False
+
+
+
+
+vector_snap ( vector , * , source , style = RoutingStyle.OBLIQUE )
+Snap the vector
onto this Edge.
+
+Parameters:
+
+
+Return type:
+Vector2D
+
+
+
+
+
+
+
+
+class capellambse.diagram. RGB
+Bases: NamedTuple
+A color.
+Each color component (red, green, blue) is an integer in the range
+of 0..255 (inclusive). The alpha channel is a float between 0.0 and
+1.0 (inclusive). If it is 1, then the str()
form does not
+include transparency information.
+
+
+a : float
+Alias for field number 3
+
+
+
+
+b : int
+Alias for field number 2
+
+
+
+
+classmethod fromcss ( cssstring )
+Create an RGB from a CSS color definition.
+Examples of recognized color definitions and their equivalent
+constructor calls:
+"rgb(10, 20, 30)" -> RGB ( 10 , 20 , 30 )
+"rgba(50, 60, 70, 0.5)" -> RGB ( 50 , 60 , 70 , 0.5 )
+"#FF00FF" -> RGB ( 255 , 0 , 255 )
+"#ff00ff" -> RGB ( 255 , 0 , 255 )
+"#f0f" -> RGB ( 255 , 0 , 255 )
+"#FF00FF80" -> RGB ( 255 , 0 , 255 , 0.5 )
+"#f0fa" -> RGB ( 255 , 0 , 255 , 2 / 3 )
+
+
+
+Parameters:
+cssstring (str | RGB ) –
+
+Return type:
+RGB
+
+
+
+
+
+
+classmethod fromcsv ( csvstring )
+Create an RGB from a "r, g, b[, a]"
string.
+
+Parameters:
+csvstring (str ) –
+
+Return type:
+RGB
+
+
+
+
+
+
+classmethod fromhex ( hexstring )
+Create an RGB from a hexadecimal string.
+The string can have 3, 4, 6 or 8 hexadecimal characters. In the
+cases of 3 and 6 characters, the alpha channel is set to 1.0
+(fully opaque) and the remaining characters are interpreted as
+the red, green and blue components.
+
+Parameters:
+hexstring (str ) –
+
+Return type:
+RGB
+
+
+
+
+
+
+g : int
+Alias for field number 1
+
+
+
+
+r : int
+Alias for field number 0
+
+
+
+
+tohex ( )
+
+Return type:
+str
+
+
+
+
+
+
+
+
+class capellambse.diagram. RoutingStyle
+Bases: Enum
+
+
+MANHATTAN = 2
+
+
+
+
+OBLIQUE = 1
+
+
+
+
+TREE = 3
+
+
+
+
+
+
+class capellambse.diagram. Vec2List
+Bases: MutableSequence
[Vector2D
]
+A list that automatically converts its elements into Vector2D.
+
+
+__init__ ( values )
+
+Parameters:
+values (Iterable [ Tuple [ float | int , float | int ] ] ) –
+
+
+
+
+
+
+append ( value )
+S.append(value) – append value to the end of the sequence
+
+Parameters:
+value (Tuple [ float | int , float | int ] ) –
+
+Return type:
+None
+
+
+
+
+
+
+copy ( )
+Create a copy of this Vec2List.
+
+Return type:
+Vec2List
+
+
+
+
+
+
+extend ( values )
+S.extend(iterable) – extend sequence by appending elements from the iterable
+
+Parameters:
+values (Iterable [ Tuple [ float | int , float | int ] ] ) –
+
+Return type:
+None
+
+
+
+
+
+
+insert ( index , value )
+S.insert(index, value) – insert value before index
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.diagram. Vec2Property
+Bases: object
+A property that automatically converts 2-tuples into Vector2D.
+
+
+__init__ ( default = None )
+
+Parameters:
+default (Tuple [ float | int , float | int ] | None ) –
+
+
+
+
+
+
+default : Vector2D | None
+
+
+
+
+name : str | None
+
+
+
+
+
+
+class capellambse.diagram. Vector2D
+Bases: NamedTuple
+A vector in 2-dimensional space.
+
+
+angleto ( other )
+Calculate the angle to other
.
+This method calculates the angle that other
was rotated by
+in order to have the same direction as self
, in radians.
+Notes
+The returned angle will always constitute the shortest rotation
+possible, i.e. it can have values between \(-\pi\) and
+\(+\pi\) .
+
+Parameters:
+other (Tuple [ float | int , float | int ] ) –
+
+Return type:
+float
+
+
+
+
+
+
+boxsnap ( corner1 , corner2 )
+Snap this vector to the side of a box and return the result.
+
+Parameters:
+
+corner1 (Tuple [ float | int , float | int ] ) – A Vector2D describing the first corner of the target box.
+corner2 (Tuple [ float | int , float | int ] ) – A Vector2D describing the second corner of the target box.
+dirvec – Ignored.
+
+
+Return type:
+Vector2D
+
+
+
+
+
+
+closestaxis ( )
+Determine the axis closest to this Vector2D.
+
+Return type:
+Vector2D
+
+
+
+
+
+
+property length : float
+Calculate the length of this vector.
+
+
+
+
+property normalized : Vector2D
+Create a unit Vector2D with the same direction as this one.
+
+Raises:
+ZeroDivisionError – if this Vector2D has zero length
+
+
+
+
+
+
+rotatedby ( theta )
+Rotate this Vector2D by theta
radians.
+
+Parameters:
+theta (float | int ) –
+
+Return type:
+Vector2D
+
+
+
+
+
+
+property sqlength : float
+Calculate the squared length of this vector.
+
+
+
+
+x : float | int
+Alias for field number 0
+
+
+
+
+y : float | int
+Alias for field number 1
+
+
+
+
+
+
+capellambse.diagram. get_style ( diagramclass , objectclass )
+Fetch the default style for the given drawtype and styleclass.
+The style is returned as a dict with key-value pairs as used by CSS
+inside SVG graphics.
+All values contained in this dict are either of type str
,
+or of a class whose str()
representation results in a valid CSS
+value for its respective key – with one exception: color gradients.
+Flat colors are represented using the RGB
tuple subclass.
+Gradients are returned as a two-element list of RGB
s the
+first one is the color at the top of the object, the second one at
+the bottom.
+
+Parameters:
+
+diagramclass (str | None ) – The style class of the diagram.
+objectclass (str ) –
A packed str
describing the element’s type and style
+class in the form:
+
+The type can be: Box
, Edge
. The style class can be any
+known style class.
+
+
+
+Return type:
+dict [str , Any ]
+
+
+
+
+
+
+capellambse.diagram. get_styleclass ( obj )
+Return the styleclass for an individual model object.
+
+Parameters:
+obj (ModelObject ) – An object received from querying the High-Level API.
+
+Returns:
+A string used for styling and decorating given obj
in a
+diagram representation.
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.diagram. line_intersect ( line1 , line2 )
+Calculate the point where line1
and line2
intersect.
+Both lines are straight lines with infinite length that are defined
+by the given points.
+Notes
+The implementation is based on
+https://mathworld.wolfram.com/Line-LineIntersection.html .
+
+Parameters:
+
+
+Return type:
+Vector2D
+
+
+
+
+
+
+capellambse.diagram.capstyle module
+The color palette and default style definitions used by Capella.
+
+
+capellambse.diagram.capstyle. COLORS : dict [ str , RGB ] = {'_CAP_Activity_Border_Orange': (91, 64, 64, 1.0), '_CAP_Activity_Orange': (247, 218, 116, 1.0), '_CAP_Activity_Orange_min': (255, 255, 197, 1.0), '_CAP_Actor_Blue': (198, 230, 255, 1.0), '_CAP_Actor_Blue_label': (0, 0, 0, 1.0), '_CAP_Actor_Blue_min': (218, 253, 255, 1.0), '_CAP_Actor_Border_Blue': (74, 74, 151, 1.0), '_CAP_Association_Color': (0, 0, 0, 1.0), '_CAP_ChoicePseudoState_Border_Gray': (0, 0, 0, 1.0), '_CAP_ChoicePseudoState_Color': (168, 168, 168, 1.0), '_CAP_Class_Border_Brown': (123, 105, 79, 1.0), '_CAP_Class_Brown': (232, 224, 210, 1.0), '_CAP_CombinedFragment_Gray': (242, 242, 242, 1.0), '_CAP_Component_Blue': (150, 177, 218, 1.0), '_CAP_Component_Blue_min': (195, 230, 255, 1.0), '_CAP_Component_Border_Blue': (74, 74, 151, 1.0), '_CAP_Component_Label_Blue': (74, 74, 151, 1.0), '_CAP_ConfigurationItem_Gray': (242, 238, 225, 1.0), '_CAP_ConfigurationItem_Gray_min': (249, 248, 245, 1.0), '_CAP_Datatype_Border_Gray': (103, 103, 103, 1.0), '_CAP_Datatype_Gray': (225, 223, 215, 1.0), '_CAP_Datatype_LightBrown': (232, 224, 210, 1.0), '_CAP_Entity_Gray': (221, 221, 200, 1.0), '_CAP_Entity_Gray_border': (69, 69, 69, 1.0), '_CAP_Entity_Gray_label': (0, 0, 0, 1.0), '_CAP_Entity_Gray_min': (249, 248, 245, 1.0), '_CAP_ExchangeItem_Pinkkish': (246, 235, 235, 1.0), '_CAP_FCD': (233, 243, 222, 1.0), '_CAP_FCinFCD_Green': (148, 199, 97, 1.0), '_CAP_InterfaceDataPackage_LightGray': (250, 250, 250, 1.0), '_CAP_Interface_Border_Reddish': (124, 61, 61, 1.0), '_CAP_Interface_Pink': (240, 221, 221, 1.0), '_CAP_Lifeline_Gray': (128, 128, 128, 1.0), '_CAP_MSM_Mode_Gray': (195, 208, 208, 1.0), '_CAP_MSM_Mode_Gray_min': (234, 239, 239, 1.0), '_CAP_MSM_State_Gray': (208, 208, 208, 1.0), '_CAP_MSM_State_Gray_min': (239, 239, 239, 1.0), '_CAP_Mode_Gray': (165, 182, 180, 1.0), '_CAP_Node_Yellow': (255, 252, 183, 1.0), '_CAP_Node_Yellow_Border': (123, 105, 79, 1.0), '_CAP_Node_Yellow_Label': (0, 0, 0, 1.0), '_CAP_Node_Yellow_min': (255, 255, 220, 1.0), '_CAP_OperationalRole_Purple': (203, 174, 200, 1.0), '_CAP_Operational_Process_Reference_Orange': (250, 239, 203, 1.0), '_CAP_PhysicalPort_Yellow': (255, 244, 119, 1.0), '_CAP_StateMode_Border_Gray': (117, 117, 117, 1.0), '_CAP_StateTransition_Color': (0, 0, 0, 1.0), '_CAP_State_Gray': (228, 228, 228, 1.0), '_CAP_Unit_LightBrown': (214, 197, 171, 1.0), '_CAP_Unset_Gray': (205, 205, 205, 1.0), '_CAP_Unset_Gray_min': (234, 234, 234, 1.0), '_CAP_Value_LightBrown': (254, 253, 250, 1.0), '_CAP_xAB_Activity_Label_Orange': (91, 64, 64, 1.0), '_CAP_xAB_Function_Border_Green': (9, 92, 46, 1.0), '_CAP_xAB_Function_Green': (197, 255, 166, 1.0), '_CAP_xAB_Function_Label_Green': (9, 92, 46, 1.0), '_CAP_xBD_ControlNode': (223, 223, 223, 1.0), '_CAP_xDFB_Function_Border_Green': (77, 137, 20, 1.0), '_CAP_xDFB_Function_Green': (197, 255, 166, 1.0), '_CAP_xDFB_Function_Green_Label': (0, 0, 0, 1.0), '_CAP_xDFB_Function_Green_min': (244, 255, 224, 1.0), '_CAP_xDF_Activity_Label_Orange': (0, 0, 0, 1.0), 'black': (0, 0, 0, 1.0), 'dark_gray': (69, 69, 69, 1.0), 'dark_orange': (224, 133, 3, 1.0), 'dark_purple': (114, 73, 110, 1.0), 'gray': (136, 136, 136, 1.0), 'light_purple': (217, 196, 215, 1.0), 'light_yellow': (255, 245, 181, 1.0), 'red': (239, 41, 41, 1.0), 'white': (255, 255, 255, 1.0)}
+This dict maps the color names used by Capella to RGB tuples.
+
+
+
+
+capellambse.diagram.capstyle. CSSdef
+This dict contains the default styles that Capella applies, grouped
+by the diagram class they belong to.
+The first level of keys are the diagrams’ styleclasses. The special
+key “__GLOBAL__” applies to all diagrams.
+The second level contains the style definitions for each element that
+can appear in the diagram. The keys work in the following way:
+
+
+
+Type
is the element type; one of “Box” or “Edge” (note casing!)
+Class
is the element’s styleclass, e.g. “LogicalComponent”
+
+The Class
and the preceding dot may be absent, in which case that
+styling applies to all elements of that Type
regardless of their
+style class.
+The order of precedence for the four possible cases is the following,
+from most to least important:
+
+Diagram class specific, element type and class
+__GLOBAL__, element type and class
+Diagram class specific, only element type
+__GLOBAL__, only element type
+
+alias of Optional
[Union
[int
, str
, RGB
, List
[RGB
]]]
+
+
+
+
+class capellambse.diagram.capstyle. RGB
+Bases: NamedTuple
+A color.
+Each color component (red, green, blue) is an integer in the range
+of 0..255 (inclusive). The alpha channel is a float between 0.0 and
+1.0 (inclusive). If it is 1, then the str()
form does not
+include transparency information.
+
+
+a : float
+Alias for field number 3
+
+
+
+
+b : int
+Alias for field number 2
+
+
+
+
+classmethod fromcss ( cssstring )
+Create an RGB from a CSS color definition.
+Examples of recognized color definitions and their equivalent
+constructor calls:
+"rgb(10, 20, 30)" -> RGB ( 10 , 20 , 30 )
+"rgba(50, 60, 70, 0.5)" -> RGB ( 50 , 60 , 70 , 0.5 )
+"#FF00FF" -> RGB ( 255 , 0 , 255 )
+"#ff00ff" -> RGB ( 255 , 0 , 255 )
+"#f0f" -> RGB ( 255 , 0 , 255 )
+"#FF00FF80" -> RGB ( 255 , 0 , 255 , 0.5 )
+"#f0fa" -> RGB ( 255 , 0 , 255 , 2 / 3 )
+
+
+
+Parameters:
+cssstring (str | RGB ) –
+
+Return type:
+RGB
+
+
+
+
+
+
+classmethod fromcsv ( csvstring )
+Create an RGB from a "r, g, b[, a]"
string.
+
+Parameters:
+csvstring (str ) –
+
+Return type:
+RGB
+
+
+
+
+
+
+classmethod fromhex ( hexstring )
+Create an RGB from a hexadecimal string.
+The string can have 3, 4, 6 or 8 hexadecimal characters. In the
+cases of 3 and 6 characters, the alpha channel is set to 1.0
+(fully opaque) and the remaining characters are interpreted as
+the red, green and blue components.
+
+Parameters:
+hexstring (str ) –
+
+Return type:
+RGB
+
+
+
+
+
+
+g : int
+Alias for field number 1
+
+
+
+
+r : int
+Alias for field number 0
+
+
+
+
+tohex ( )
+
+Return type:
+str
+
+
+
+
+
+
+
+
+capellambse.diagram.capstyle. get_style ( diagramclass , objectclass )
+Fetch the default style for the given drawtype and styleclass.
+The style is returned as a dict with key-value pairs as used by CSS
+inside SVG graphics.
+All values contained in this dict are either of type str
,
+or of a class whose str()
representation results in a valid CSS
+value for its respective key – with one exception: color gradients.
+Flat colors are represented using the RGB
tuple subclass.
+Gradients are returned as a two-element list of RGB
s the
+first one is the color at the top of the object, the second one at
+the bottom.
+
+Parameters:
+
+diagramclass (str | None ) – The style class of the diagram.
+objectclass (str ) –
A packed str
describing the element’s type and style
+class in the form:
+
+The type can be: Box
, Edge
. The style class can be any
+known style class.
+
+
+
+Return type:
+dict [str , Any ]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.extensions.html b/code/capellambse.extensions.html
new file mode 100644
index 000000000..05f6cb88f
--- /dev/null
+++ b/code/capellambse.extensions.html
@@ -0,0 +1,730 @@
+
+
+
+
+
+
+
+
+ capellambse.extensions package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.extensions package
+
+
+
+capellambse.extensions.filtering module
+Implements the Capella Filtering extension.
+
+
+class capellambse.extensions.filtering. AssociatedCriteriaAccessor
+Bases: PhysicalAccessor
[FilteringCriterion
]
+
+
+__init__ ( )
+
+Return type:
+None
+
+
+
+
+
+
+aslist : type [ element.ElementList ] | None
+
+
+
+
+class_ : type [ T ]
+
+
+
+
+
+
+
+
+xtypes : cabc.Set [ str ]
+
+
+
+
+
+
+class capellambse.extensions.filtering. ComposedFilteringResult
+Bases: GenericElement
+A composed filtering result.
+
+
+
+
+class capellambse.extensions.filtering. FilteringCriterion
+Bases: GenericElement
+A single filtering criterion.
+
+
+filtered_objects
+The filtered objects of this FilteringCriterion.
+
+
+
+
+
+
+class capellambse.extensions.filtering. FilteringCriterionPkg
+Bases: GenericElement
+A package containing multiple filtering criteria.
+
+
+criteria
+The criteria of this FilteringCriterionPkg.
+
+
+
+
+packages : c.Accessor [ FilteringCriterionPkg ]
+The packages of this FilteringCriterionPkg.
+
+
+
+
+
+
+class capellambse.extensions.filtering. FilteringModel
+Bases: GenericElement
+A filtering model containing criteria to filter by.
+
+
+criteria
+The criteria of this FilteringModel.
+
+
+
+
+criterion_packages
+The criterion packages of this FilteringModel.
+
+
+
+
+
+
+class capellambse.extensions.filtering. FilteringResult
+Bases: GenericElement
+A filtering result.
+
+
+
+
+capellambse.extensions.filtering. init ( )
+
+Return type:
+None
+
+
+
+
+
+
+capellambse.extensions.pvmt module
+Property Value Management extension for CapellaMBSE.
+
+
+class capellambse.extensions.pvmt. PropertyValueProxy
+Bases: object
+Provides access to an element’s property values.
+Example for accessing property values on any object that has pvmt:
+>>> model . la . all_functions [ 0 ] . pvmt [ 'domain.group.property' ]
+'property'
+>>> model . la . all_functions [ 0 ] . pvmt [ 'domain.group' ]
+<pvmt.AppliedPropertyValueGroup "domain.group"(abcdef01-2345-6789-abcd-ef0123456789)>
+
+
+
+
Note
+
Access is only given if the PVMT Extension is successfully
+loaded on loading the model with the
+MelodyModel
.
+
+
+
+__init__ ( ** kw )
+
+Parameters:
+kw (Any ) –
+
+Return type:
+None
+
+
+
+
+
+
+classmethod from_model ( model , element )
+Create a PropertyValueProxy for an element.
+
+Parameters:
+
+
+Return type:
+PropertyValueProxy
+
+
+
+
+
+
+
+
+capellambse.extensions.pvmt. init ( )
+
+Return type:
+None
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.extensions.metrics.html b/code/capellambse.extensions.metrics.html
new file mode 100644
index 000000000..a05e37d6f
--- /dev/null
+++ b/code/capellambse.extensions.metrics.html
@@ -0,0 +1,579 @@
+
+
+
+
+
+
+
+
+ capellambse.extensions.metrics package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.extensions.metrics package
+Tools for statistical evaluation of model contents.
+
+
+capellambse.extensions.metrics. get_summary_badge ( model )
+Provide visual summary of model contents.
+
+Parameters:
+model (MelodyModel ) –
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.extensions.metrics.collector module
+Collection of tools for collection of statistical data from a model.
+Objects of interest are those that we see people working on most. We
+think that counting those may help us with model complexity evaluation -
+for example identify if a model is big or small or see where the
+modeling focus is (problem space / solution space / balanced)
+
+
+capellambse.extensions.metrics.collector. quantify_model_layers ( model )
+Count objects of interest and diagrams on model layers.
+
+Returns:
+
+
+
+Parameters:
+model (MelodyModel ) –
+
+Return type:
+tuple [list [int ], list [int ]]
+
+
+Notes
+The order of numbers in a list corresponds to the order of model
+layers - OA, SA, LA, PA.
+
+
+
+
+capellambse.extensions.metrics.composer module
+Collection of tools for drawing model complexity assessment badge.
+
+
+capellambse.extensions.metrics.composer. LEGEND = ((2, 'Operational Analysis'), (36, 'System Analysis'), (66, 'Logical Architecture'), (99, 'Physical Architecture'))
+The x-offset and label of each legend entry.
+
+
+
+
+capellambse.extensions.metrics.composer. draw_bar ( data , max_width , x , y , height = 8 , show_label_threshold = 0.1 )
+Construct a 4-segment bar plot (SVG string).
+Segment spacing is defined by {data}; Sum of {data} must match 1 for
+the thing to work the right way. Segments are labeled with “%” if
+the width is above {show_label_threshold}.
+
+Parameters:
+
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.extensions.metrics.composer. draw_diagrams_icon ( x , y )
+Create simple diagram icon (SVG string).
+
+Parameters:
+
+
+
+
+
+
+
+capellambse.extensions.metrics.composer. draw_group ( contents , fill = None , font_size = None , font_family = None )
+Construct a group (SVG string).
+
+Parameters:
+
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.extensions.metrics.composer. draw_labeled_bar ( x , y , label , segments , draw_icon )
+Construct a bar with label and icon (SVG string).
+
+Parameters:
+
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.extensions.metrics.composer. draw_legend ( x , y )
+Construct plot legend (SVG string).
+
+Parameters:
+
+
+
+
+
+
+
+capellambse.extensions.metrics.composer. draw_objects_icon ( x , y )
+Create simple objects icon (SVG string).
+
+Parameters:
+
+
+
+
+
+
+
+capellambse.extensions.metrics.composer. draw_rect ( x , y , width , height , fill = '#FFF' , stroke = '#333' , stroke_width = 0 )
+Construct a rectangle (SVG string).
+
+Parameters:
+
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.extensions.metrics.composer. draw_summary_badge ( objects , diagrams , scale = 4.0 )
+Construct summary badge (SVG string).
+
+Parameters:
+
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.extensions.metrics.composer. draw_text ( x , y , text , font_size = None )
+Construct a text element (SVG string).
+
+Parameters:
+
+
+Return type:
+str
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.extensions.reqif.html b/code/capellambse.extensions.reqif.html
new file mode 100644
index 000000000..76afbb1e8
--- /dev/null
+++ b/code/capellambse.extensions.reqif.html
@@ -0,0 +1,1219 @@
+
+
+
+
+
+
+
+
+ capellambse.extensions.reqif package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.extensions.reqif package
+Tools for handling ReqIF Requirements.
+
+
+
+class capellambse.extensions.reqif. AbstractRequirementsAttribute
+Bases: GenericElement
+
+
+definition
+The definition of this AbstractRequirementsAttribute.
+
+
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+class capellambse.extensions.reqif. AbstractRequirementsRelation
+Bases: ReqIFElement
+
+
+source
+The source of this AbstractRequirementsRelation.
+
+
+
+
+target
+The target of this AbstractRequirementsRelation.
+
+
+
+
+type : c.Accessor
+The type of this AbstractRequirementsRelation.
+
+
+
+
+
+
+class capellambse.extensions.reqif. AbstractType
+Bases: ReqIFElement
+
+
+attribute_definitions
+The attribute definitions of this AbstractType.
+
+
+
+
+owner
+The owner of this AbstractType.
+
+
+
+
+
+
+class capellambse.extensions.reqif. AttributeAccessor
+Bases: DirectProxyAccessor
[AbstractRequirementsAttribute
]
+
+
+__init__ ( )
+Create a DirectProxyAccessor.
+
+Parameters:
+
+class – The proxy class.
+xtypes – The xsi:type
(s) of the child element(s). If None, then
+the constructed proxy will be passed the original element
+instead of a child.
+aslist – If None, only a single element must match, which will be
+returned directly. If not None, must be a subclass of
+ElementList
,
+which will be used to return a list of all matched objects.
+follow_abstract – Follow the link in the abstractType
XML attribute of
+each list member and instantiate that object instead. The
+default is to instantiate the child elements directly.
+list_extra_args – Extra arguments to pass to the
+ElementList
+constructor.
+rootelem – A class or xsi:type
(or list thereof) that defines the
+path from the current object’s XML element to the search
+root. If None, the current element will be used directly.
+single_attr – If objects can be created with only a single attribute
+specified, this argument is the name of that attribute. This
+create_singleattr()
.
+
+
+Return type:
+None
+
+
+
+
+
+
+follow_abstract : bool
+
+
+
+
+rootelem : cabc.Sequence [ str ]
+
+
+
+
+
+
+class capellambse.extensions.reqif. AttributeDefinition
+Bases: ReqIFElement
+An attribute definition for requirement types.
+
+
+data_type
+The data type of this AttributeDefinition.
+
+
+
+
+
+
+class capellambse.extensions.reqif. AttributeDefinitionEnumeration
+Bases: ReqIFElement
+An enumeration attribute definition for requirement types.
+
+
+data_type
+The data type of this AttributeDefinitionEnumeration.
+
+
+
+
+multi_valued
+Boolean flag for setting multiple enumeration values on the attribute
+
+
+
+
+
+
+class capellambse.extensions.reqif. BooleanValueAttribute
+Bases: AbstractRequirementsAttribute
+A string value attribute.
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+class capellambse.extensions.reqif. CapellaIncomingRelation
+Bases: AbstractRequirementsRelation
+A Relation between a requirement and an object.
+
+
+
+
+class capellambse.extensions.reqif. CapellaModule
+Bases: ReqIFElement
+A ReqIF Module that bundles multiple Requirement folders.
+
+
+attributes
+The attributes of this CapellaModule.
+
+
+
+
+folders
+The folders of this CapellaModule.
+
+
+
+
+requirement_types_folders
+The requirement types folders of this CapellaModule.
+
+
+
+
+requirements
+The requirements of this CapellaModule.
+
+
+
+
+to_reqif ( to , * , metadata = None , pretty = False , compress = None )
+Export this module as ReqIF XML.
+You can override some auto-generated metadata placed in the header
+section by passing a dictionary as metadata
. The following keys
+are supported. Unsupported keys are silently ignored.
+
+creation_time
: A datetime.datetime
object that specifies
+this document’s creation time. Default to the current time.
+comment
: Override the ReqIF file’s comment. Defaults to a
+text derived from the model and module names.
+title
: Specify the document title. Defaults to the module’s
+long_name
.
+
+
+Parameters:
+
+to (str | PathLike | IO [ bytes ] ) – Where to export to. Can be the name of a file, or a file-like
+object opened in binary mode.
+metadata (Mapping [ str , Any ] | None ) – A dictionary with additional metadata (see above).
+pretty (bool ) – Format the XML human-readable.
+compress (bool | None ) – Write compressed data (*.reqifz
). Defaults to True
+if target
is a string or path-like and its name ends in
+.reqifz
, otherwise defaults to False
.
+
+
+Return type:
+None
+
+
+
+
+
+
+type : c.Accessor
+The type of this CapellaModule.
+
+
+
+
+
+
+class capellambse.extensions.reqif. CapellaOutgoingRelation
+Bases: AbstractRequirementsRelation
+A Relation between an object and a requirement.
+
+
+source
+The source of this CapellaOutgoingRelation.
+
+
+
+
+target
+The target of this CapellaOutgoingRelation.
+
+
+
+
+
+
+class capellambse.extensions.reqif. CapellaTypesFolder
+Bases: ReqIFElement
+
+
+data_type_definitions
+The data type definitions of this CapellaTypesFolder.
+
+
+
+
+module_types
+The module types of this CapellaTypesFolder.
+
+
+
+
+relation_types
+The relation types of this CapellaTypesFolder.
+
+
+
+
+requirement_types
+The requirement types of this CapellaTypesFolder.
+
+
+
+
+
+
+class capellambse.extensions.reqif. DataTypeDefinition
+Bases: ReqIFElement
+A data type definition for requirement types.
+
+
+
+
+class capellambse.extensions.reqif. DateValueAttribute
+Bases: AbstractRequirementsAttribute
+A value attribute that stores a date and time.
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+class capellambse.extensions.reqif. ElementRelationAccessor
+Bases: WritableAccessor
[rq.AbstractRequirementsRelation
]
+Provides access to RequirementsRelations of a GenericElement.
+
+
+__init__ ( )
+
+Return type:
+None
+
+
+
+
+
+
+aslist : type [ ElementListCouplingMixin ] | None
+
+
+
+
+purge_references ( obj , target )
+Do nothing.
+This is a no-op, as this accessor provides a virtual relation.
+The relation objects it handles are cleaned up by removing the
+source or target attribute.
+
+Parameters:
+
+
+Return type:
+Generator [None, None, None]
+
+
+
+
+
+
+
+
+class capellambse.extensions.reqif. EnumValue
+Bases: ReqIFElement
+An enumeration value for EnumerationDataTypeDefinition
.
+
+
+
+
+class capellambse.extensions.reqif. EnumerationDataTypeDefinition
+Bases: ReqIFElement
+An enumeration data type definition for requirement types.
+
+
+values
+The values of this EnumerationDataTypeDefinition.
+
+
+
+
+
+
+class capellambse.extensions.reqif. EnumerationValueAttribute
+Bases: AbstractRequirementsAttribute
+An enumeration attribute.
+
+
+definition
+The definition of this EnumerationValueAttribute.
+
+
+
+
+property value
+
+
+
+
+values
+The values of this EnumerationValueAttribute.
+
+
+
+
+
+
+class capellambse.extensions.reqif. Folder
+Bases: Requirement
+A folder that stores Requirements.
+
+
+folders : c.Accessor
+The folders of this Folder.
+
+
+
+
+requirements
+The requirements of this Folder.
+
+
+
+
+
+
+class capellambse.extensions.reqif. IntegerValueAttribute
+Bases: AbstractRequirementsAttribute
+An integer value attribute.
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+class capellambse.extensions.reqif. InternalRelation
+Bases: AbstractRequirementsRelation
+A Relation between two requirements.
+
+
+
+
+class capellambse.extensions.reqif. ModuleType
+Bases: AbstractType
+A requirement-module type.
+
+
+
+
+class capellambse.extensions.reqif. RealValueAttribute
+Bases: AbstractRequirementsAttribute
+A floating-point number value attribute.
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+class capellambse.extensions.reqif. RelationType
+Bases: AbstractType
+A requirement-relation type.
+
+
+
+
+class capellambse.extensions.reqif. RelationsList
+Bases: ElementList
[rq.AbstractRequirementsRelation]
+
+
+__init__ ( model , elements , elemclass = None , * , source )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+by_relation_class ( class_ )
+
+Parameters:
+class_ (Literal [ 'incoming' , 'outgoing' , 'internal' ] ) –
+
+Return type:
+RelationsList
+
+
+
+
+
+
+by_relation_type ( reltype )
+
+Parameters:
+reltype (str ) –
+
+Return type:
+RelationsList
+
+
+
+
+
+
+
+
+class capellambse.extensions.reqif. ReqIFElement
+Bases: GenericElement
+Attributes shared by all ReqIF elements.
+
+
+description : str
+
+
+
+
+identifier
+
+
+
+
+long_name
+
+
+
+
+name
+
+
+
+
+prefix
+
+
+
+
+property type
+
+
+
+
+
+
+class capellambse.extensions.reqif. Requirement
+Bases: ReqIFElement
+A ReqIF Requirement.
+
+
+attributes
+The attributes of this Requirement.
+
+
+
+
+chapter_name
+
+
+
+
+foreign_id
+
+
+
+
+owner
+The owner of this Requirement.
+
+
+
+
+related : c.Accessor [ c.GenericElement ]
+The related of this Requirement.
+
+
+
+
+relations : c.Accessor [ AbstractRequirementsRelation ]
+The relations of this Requirement.
+
+
+
+
+text
+
+
+
+
+type : c.Accessor
+The type of this Requirement.
+
+
+
+
+
+
+class capellambse.extensions.reqif. RequirementType
+Bases: AbstractType
+A requirement type.
+
+
+
+
+class capellambse.extensions.reqif. RequirementsRelationAccessor
+Bases: WritableAccessor
[rq.AbstractRequirementsRelation
]
+Searches for requirement relations in the architecture layer.
+
+
+__init__ ( * args , ** kw )
+
+Return type:
+None
+
+
+
+
+
+
+aslist : type [ ElementListCouplingMixin ] | None
+
+
+
+
+create ( elmlist , / , * type_hints , ** kw )
+Create and return a new element of type elmclass
.
+
+Parameters:
+
+elmlist (ElementListCouplingMixin ) – The (coupled)
+ElementList
to
+insert the new object into.
+type_hints (str | None ) – Hints for finding the correct type of element to create. Can
+either be a full or shortened xsi:type
string, or an
+abbreviation defined by the specific Accessor instance.
+kw (Any ) – Initialize the properties of the new object. Depending on
+the object’s type, some attributes may be required.
+
+
+Return type:
+InternalRelation | CapellaIncomingRelation
+
+
+
+
+
+
+delete ( elmlist , obj )
+Delete the obj
from the model.
+
+Return type:
+None
+
+
+
+
+
+
+insert ( elmlist , index , value )
+Insert the value
object into the model.
+The object must be inserted at an appropriate place, so that, if
+elmlist
were to be created afresh, value
would show up
+at index index
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+purge_references ( obj , target )
+Do nothing.
+This is a no-op, as this accessor provides a virtual relation.
+The relation objects it handles are cleaned up by removing the
+source or target attribute.
+
+Parameters:
+
+
+Return type:
+Generator [None, None, None]
+
+
+
+
+
+
+
+
+class capellambse.extensions.reqif. StringValueAttribute
+Bases: AbstractRequirementsAttribute
+A string value attribute.
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+capellambse.extensions.reqif. init ( )
+
+Return type:
+None
+
+
+
+
+
+
+capellambse.extensions.reqif.exporter module
+Implementation of a ReqIF 1.1 and 1.2 exporter.
+
+
+capellambse.extensions.reqif.exporter. export_module ( module , target , * , metadata = None , pretty = False , compress = None )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.filehandler.html b/code/capellambse.filehandler.html
new file mode 100644
index 000000000..ec60ef589
--- /dev/null
+++ b/code/capellambse.filehandler.html
@@ -0,0 +1,2243 @@
+
+
+
+
+
+
+
+
+ capellambse.filehandler package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.filehandler package
+
+
+class capellambse.filehandler. FileHandler
+Bases: object
+Abstract super class for file handler implementations.
+
+Parameters:
+
+path (str | os.PathLike ) – The location of the remote. The exact accepted forms are
+determined by the specific file handler implementation, for
+example the LocalFileHandler
accepts only local paths, and
+the GitFileHandler
accepts everything that Git accepts.
+subdir – Consider all paths relative to this subdirectory, instead of the
+root of the file handler’s hierarchy.
+
+
+
+
+
+__init__ ( path , * , subdir = '/' , ** kw )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+abstract get_model_info ( )
+
+Return type:
+modelinfo.ModelInfo
+
+
+
+
+
+
+is_dir ( path , / )
+
+Parameters:
+path (str | PurePosixPath ) –
+
+
+
+
+
+
+is_file ( path , / )
+
+Parameters:
+path (str | PurePosixPath ) –
+
+
+
+
+
+
+iterdir ( path = '.' , / )
+Iterate over the contents of a directory.
+This method is equivalent to calling
+fh.rootdir.joinpath(path).iterdir()
.
+
+Parameters:
+path (str | PurePosixPath ) – The directory to list. If not given, lists the contents of
+the root directory (i.e. the one specified by path
and
+subdir
).
+
+Return type:
+Iterator [FilePath [Self ]]
+
+
+
+
+
+
+abstract open ( filename , mode = 'rb' )
+Open the model file for reading or writing.
+A “file” in this context does not necessarily refer to a
+physical file on disk; it may just as well be streamed in via
+network or other means. Due to this, the file-like returned by
+this method is not required to support random access.
+
+Parameters:
+
+filename (str | PurePosixPath ) – The name of the file, relative to the path
that was
+given to the constructor.
+mode (Literal [ 'r' , 'rb' , 'w' , 'wb' ] ) – The mode to open the file in. Either "r"
or "rb"
for
+reading, or "w"
or "wb"
for writing a new file. Be
+aware that this method may refuse to open a file for writing
+unless a transaction was started with
+write_transaction()
first.
+
+
+Return type:
+IO [bytes ]
+
+
+
+
+
+
+path : str | PathLike
+
+
+
+
+read_file ( path , / )
+Read a file.
+This method is a convenience wrapper around open()
.
+
+Parameters:
+path (str | PurePosixPath ) –
+
+Return type:
+bytes
+
+
+
+
+
+
+property rootdir : FilePath [ Self ]
+The root directory of the file handler.
+
+
+
+
+write_file ( path , content , / )
+Write a file.
+This method is a convenience wrapper around open()
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+write_transaction ( ** kw )
+Start a transaction for writing new model files.
+During a transaction, writable objects returned by
+open()
buffer their contents in a temporary location,
+and once the transaction ends, all updated files are committed
+to their destinations at once. If the transaction is aborted,
+for example because an exception was raised, then all changes
+must be rolled back to the state immediately before the
+transaction. If, during a transaction, any relevant file is
+touched without the file handler knowing about it, the behavior
+is undefined.
+Note that open()
may refuse to open a file as writable
+if no transaction is currently open. This depends on the needs
+of the underlying abstract file system.
+Transaction arguments
+A concrete file handler implementation may accept arbitrary
+additional arguments to this method. The implementation should
+however always support the case of no arguments given, in which
+case it should start a transaction with sensible defaults, and
+it should also accept and ignore any arguments it does not
+understand. All additional arguments must be passed in via
+keywords. Positional arguments are not supported.
+The return value of the context manager’s __enter__()
method
+is expected to be a mapping of all the keyword arguments that
+were not understood. Client code may use this to react properly
+(e.g. by aborting the transaction early) if a required keyword
+argument is found to be not supported by the underlying file
+handler. If a subclass wishes to call its super class’
+write_transaction()
method, it should remove all the keyword
+arguments that it handles itself and pass on the others
+unchanged.
+Well-known arguments
+The following arguments are considered well-known, and their
+meaning is expected to be the same for all file handlers that
+support them.
+
+dry_run
(bool
): If set to True
, changes made
+during the transaction should be rolled back instead of
+being committed, just as if an exception had been raised.
+author_name
(str
): The name of the author of the
+changes.
+author_email
(str
): The e-mail address to record
+alongside the author_name
.
+commit_msg
(str
): A message describing the changes,
+which will be recorded in the version control system.
+remote_branch
(str
): If the model came from a remote
+version control system, changes are normally pushed back to
+the same branch on that remote. This argument specifies an
+alternative branch name to push to (which may not yet exist
+on the remote).
+
+
+Parameters:
+kw (Any ) –
+
+Return type:
+ContextManager [Mapping [str , Any ]]
+
+
+
+
+
+
+
+
+exception capellambse.filehandler. TransactionClosedError
+Bases: RuntimeError
+Raised when a transaction must be opened first to write files.
+
+
+
+
+capellambse.filehandler. get_filehandler ( path , ** kwargs )
+
+Parameters:
+
+
+Return type:
+FileHandler
+
+
+
+
+
+
+capellambse.filehandler.abc module
+The abstract FileHandler superclass and utilities.
+
+
+capellambse.filehandler.abc. AbstractFilePath
+alias of FilePath
+
+
+
+
+class capellambse.filehandler.abc. FileHandler
+Bases: object
+Abstract super class for file handler implementations.
+
+Parameters:
+
+path (str | os.PathLike ) – The location of the remote. The exact accepted forms are
+determined by the specific file handler implementation, for
+example the LocalFileHandler
accepts only local paths, and
+the GitFileHandler
accepts everything that Git accepts.
+subdir – Consider all paths relative to this subdirectory, instead of the
+root of the file handler’s hierarchy.
+
+
+
+
+
+__init__ ( path , * , subdir = '/' , ** kw )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+abstract get_model_info ( )
+
+Return type:
+modelinfo.ModelInfo
+
+
+
+
+
+
+is_dir ( path , / )
+
+Parameters:
+path (str | PurePosixPath ) –
+
+
+
+
+
+
+is_file ( path , / )
+
+Parameters:
+path (str | PurePosixPath ) –
+
+
+
+
+
+
+iterdir ( path = '.' , / )
+Iterate over the contents of a directory.
+This method is equivalent to calling
+fh.rootdir.joinpath(path).iterdir()
.
+
+Parameters:
+path (str | PurePosixPath ) – The directory to list. If not given, lists the contents of
+the root directory (i.e. the one specified by path
and
+subdir
).
+
+Return type:
+Iterator [FilePath [Self ]]
+
+
+
+
+
+
+abstract open ( filename , mode = 'rb' )
+Open the model file for reading or writing.
+A “file” in this context does not necessarily refer to a
+physical file on disk; it may just as well be streamed in via
+network or other means. Due to this, the file-like returned by
+this method is not required to support random access.
+
+Parameters:
+
+filename (str | PurePosixPath ) – The name of the file, relative to the path
that was
+given to the constructor.
+mode (Literal [ 'r' , 'rb' , 'w' , 'wb' ] ) – The mode to open the file in. Either "r"
or "rb"
for
+reading, or "w"
or "wb"
for writing a new file. Be
+aware that this method may refuse to open a file for writing
+unless a transaction was started with
+write_transaction()
first.
+
+
+Return type:
+IO [bytes ]
+
+
+
+
+
+
+path : str | PathLike
+
+
+
+
+read_file ( path , / )
+Read a file.
+This method is a convenience wrapper around open()
.
+
+Parameters:
+path (str | PurePosixPath ) –
+
+Return type:
+bytes
+
+
+
+
+
+
+property rootdir : FilePath [ Self ]
+The root directory of the file handler.
+
+
+
+
+write_file ( path , content , / )
+Write a file.
+This method is a convenience wrapper around open()
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+write_transaction ( ** kw )
+Start a transaction for writing new model files.
+During a transaction, writable objects returned by
+open()
buffer their contents in a temporary location,
+and once the transaction ends, all updated files are committed
+to their destinations at once. If the transaction is aborted,
+for example because an exception was raised, then all changes
+must be rolled back to the state immediately before the
+transaction. If, during a transaction, any relevant file is
+touched without the file handler knowing about it, the behavior
+is undefined.
+Note that open()
may refuse to open a file as writable
+if no transaction is currently open. This depends on the needs
+of the underlying abstract file system.
+Transaction arguments
+A concrete file handler implementation may accept arbitrary
+additional arguments to this method. The implementation should
+however always support the case of no arguments given, in which
+case it should start a transaction with sensible defaults, and
+it should also accept and ignore any arguments it does not
+understand. All additional arguments must be passed in via
+keywords. Positional arguments are not supported.
+The return value of the context manager’s __enter__()
method
+is expected to be a mapping of all the keyword arguments that
+were not understood. Client code may use this to react properly
+(e.g. by aborting the transaction early) if a required keyword
+argument is found to be not supported by the underlying file
+handler. If a subclass wishes to call its super class’
+write_transaction()
method, it should remove all the keyword
+arguments that it handles itself and pass on the others
+unchanged.
+Well-known arguments
+The following arguments are considered well-known, and their
+meaning is expected to be the same for all file handlers that
+support them.
+
+dry_run
(bool
): If set to True
, changes made
+during the transaction should be rolled back instead of
+being committed, just as if an exception had been raised.
+author_name
(str
): The name of the author of the
+changes.
+author_email
(str
): The e-mail address to record
+alongside the author_name
.
+commit_msg
(str
): A message describing the changes,
+which will be recorded in the version control system.
+remote_branch
(str
): If the model came from a remote
+version control system, changes are normally pushed back to
+the same branch on that remote. This argument specifies an
+alternative branch name to push to (which may not yet exist
+on the remote).
+
+
+Parameters:
+kw (Any ) –
+
+Return type:
+ContextManager [Mapping [str , Any ]]
+
+
+
+
+
+
+
+
+class capellambse.filehandler.abc. FilePath
+Bases: PathLike
[str
], Traversable
, Generic
[_F
]
+A path to a file in a file handler.
+This is an abstract class with FileHandler-agnostic implementations
+of some of Traversable’s methods. It is not meant to be instantiated
+directly, but rather to be used as a base class for concrete file
+path implementations.
+Note that some of these implementations may be inefficient, and
+subclasses are encouraged to override them with more efficient
+implementations if possible.
+
+
+__init__ ( parent , path )
+
+Parameters:
+
+
+
+
+
+
+
+is_dir ( )
+Return True if self is a directory
+
+Return type:
+bool
+
+
+
+
+
+
+is_file ( )
+Return True if self is a file
+
+Return type:
+bool
+
+
+
+
+
+
+iterdir ( path = '.' )
+Yield Traversable objects in self
+
+Parameters:
+path (str | PurePosixPath ) –
+
+Return type:
+Iterator [Self ]
+
+
+
+
+
+
+joinpath ( path )
+Return Traversable resolved with any descendants applied.
+Each descendant should be a path segment relative to self
+and each may contain multiple levels separated by
+posixpath.sep
(/
).
+
+Parameters:
+path (str | PurePosixPath ) –
+
+Return type:
+Self
+
+
+
+
+
+
+property name : str
+The base name of this object without any parent references.
+
+
+
+
+open ( mode = 'rb' , buffering = -1 , encoding = None , errors = None , newline = None )
+mode may be ‘r’ or ‘rb’ to open as text or binary. Return a handle
+suitable for reading (same as pathlib.Path.open).
+When opening as text, accepts encoding parameters such as those
+accepted by io.TextIOWrapper.
+
+Parameters:
+
+
+Return type:
+IO [bytes ]
+
+
+
+
+
+
+property parent : Self
+
+
+
+
+read_bytes ( )
+Read contents of self as bytes
+
+Return type:
+bytes
+
+
+
+
+
+
+read_text ( encoding = None )
+Read contents of self as text
+
+Parameters:
+encoding (str | None ) –
+
+Return type:
+str
+
+
+
+
+
+
+rglob ( pattern )
+
+Parameters:
+pattern (str ) –
+
+Return type:
+Iterator [Self ]
+
+
+
+
+
+
+property stem : str
+
+
+
+
+property suffix : str
+
+
+
+
+
+
+exception capellambse.filehandler.abc. TransactionClosedError
+Bases: RuntimeError
+Raised when a transaction must be opened first to write files.
+
+
+
+
+capellambse.filehandler.git module
+
+
+class capellambse.filehandler.git. GitFileHandler
+Bases: FileHandler
+File handler for git://
and related protocols.
+
+Parameters:
+
+revision – The Git revision to check out. Either a branch or tag name, a
+full ref name, or the object name (i.e. hash) of a commit-ish.
+username (str ) – The user name for authentication with the Git remote.
+password (str ) – The password for authentication with the Git remote.
+identity_file (str ) – Authenticate against the remote with the private key in this
+file. Defaults to using SSH’s algorithm for determining a
+suitable key. (SSH only, ignored otherwise)
+known_hosts_file (str ) – An OpenSSH-style known_hosts
file containing the public key
+of the remote server. (SSH only, ignored otherwise)
+disable_cache – Wipe the local cache and create a fresh, new clone.
+update_cache – Contact the remote and make sure that the local cache is up to
+date. Note that setting this to False
does not necessarily
+inhibit all attempts to contact the remote; it just disables the
+initial “fetch” operation. Later operations may still require to
+access the server, for example to download Git-LFS files.
+shallow (bool ) –
Make a shallow clone. This can drastically reduce network and
+disk usage when cloning large models, by only downloading the
+latest revision
and not downloading the history that leads
+up to it.
+Note that, when this is set to True
(the default), existing
+non-shallow caches will be made shallow. However, when it is set
+to False
, shallow caches will not be unshallowed.
+
+
+
+
+
+
+
+__init__ ( path , revision = 'HEAD' , username = '' , password = '' , identity_file = '' , known_hosts_file = '' , disable_cache = False , update_cache = True , * , subdir = '/' , shallow = True )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+cache_dir : Path
+Path to the temporary work tree created by this file handler.
+
+
+
+
+get_model_info ( )
+
+Return type:
+ModelInfo
+
+
+
+
+
+
+identity_file : str
+
+
+
+
+iterdir ( path = '.' )
+Iterate over the files in the given directory.
+
+Parameters:
+path (str | PurePosixPath ) – The path to the directory to iterate over.
+
+Return type:
+Iterator [GitPath ]
+
+
+
+
+
+
+known_hosts_file : str
+
+
+
+
+open ( filename , mode = 'rb' )
+Open the model file for reading or writing.
+A “file” in this context does not necessarily refer to a
+physical file on disk; it may just as well be streamed in via
+network or other means. Due to this, the file-like returned by
+this method is not required to support random access.
+
+Parameters:
+
+filename (str | PurePosixPath ) – The name of the file, relative to the path
that was
+given to the constructor.
+mode (Literal [ 'r' , 'rb' , 'w' , 'wb' ] ) – The mode to open the file in. Either "r"
or "rb"
for
+reading, or "w"
or "wb"
for writing a new file. Be
+aware that this method may refuse to open a file for writing
+unless a transaction was started with
+write_transaction()
first.
+
+
+Return type:
+BinaryIO
+
+
+
+
+
+
+password : str
+
+
+
+
+property rootdir : GitPath
+The root directory of the repository.
+
+
+
+
+shallow : bool
+
+
+
+
+username : str
+
+
+
+
+write_transaction ( ** kw )
+Create a transaction that records all changes as a new commit.
+
+Parameters:
+
+author_name – The name of the commit author.
+author_email – The e-mail address of the commit author.
+commit_msg – The commit message.
+dry_run – If True, stop before updating the revision
pointer. The
+commit will be created, but will not be part of any branch
+or tag.
+remote_branch –
An alternative branch name to push to on the remote, instead
+of pushing back to the same branch. This is required if
+push
is True
and the revision
that was passed to
+the constructor does not refer to a branch (or looks like a
+git object).
+Note: For convenience, refs/heads/
will be prepended
+automatically to this name if it isn’t already present. This
+also means that it is not possible to create tags or other
+types of refs; passing in something like refs/tags/v2.4
+would result in the full ref name
+refs/heads/refs/tags/v2.4
.
+
+push – Set to False
to inhibit pushing the changes back.
+push_options – Additional git push options. See --push-option
in
+git-push(1)
. Ignored if push
is False
.
+kw (Any ) –
+
+
+Raises:
+ValueError –
+
+
+Return type:
+ContextManager [Mapping [str , Any ]]
+
+
+
+
+
+
+
+
+class capellambse.filehandler.git. GitPath
+Bases: FilePath
[GitFileHandler
]
+
+
+__init__ ( parent , path , type = None )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+is_dir ( )
+Return True if self is a directory
+
+Return type:
+bool
+
+
+
+
+
+
+is_file ( )
+Return True if self is a file
+
+Return type:
+bool
+
+
+
+
+
+
+
+
+capellambse.filehandler.git_askpass module
+
+
+capellambse.filehandler.gitlab_artifacts module
+
+
+class capellambse.filehandler.gitlab_artifacts. GitlabArtifactsFiles
+Bases: FileHandler
+Download files from Gitlab’s artifacts hosting service.
+This file handler is roughly equivalent to an HTTPFileHandler with
+appropriate headers and the following URL:
+ https://<path>/api/v4/projects/<project>/jobs/artifacts/<branch>/raw/<subdir>/%s?job_name=<job>
+
+
+One important difference is that this file handler will always use
+the latest successful job, regardless of the overall pipeline
+status, while an HTTPFileHandler with the above URL would only
+consider jobs from successful pipelines.
+This file handler uses several of the Gitlab CI/CD pre-defined
+environment variables . Refer to the documentation for their exact
+meaning and behavior during CI runs, and see below for how they are
+used.
+
+Parameters:
+
+path (str | os.PathLike ) –
The base URL of the Gitlab server. Must start with one of
+glart://
, glart+http://
or glart+https://
; the
+glart:
prefix uses HTTPS to communicate with the server. May
+also be set to glart:
(without a server name), which uses
+the $CI_SERVER_URL
environment variable to find the
+instance; if that is not set, the public Gitlab instance at
+https://gitlab.com
is used.
+Example: If your project is hosted at
+https://gitlab.example.com/my_username/my_cool_project
, use
+glart://gitlab.example.com
as path argument.
+
+token –
A personal or project access token with read_api
permission
+on the specified project. The following ways are supported for
+passing the token, which are checked in order:
+
+Directly via this argument.
+If the argument starts with a dollar sign ($
), it is
+treated as the name of an environment variable that points to
+a file containing the token. This is compatible with
+variables of type “File” in Gitlab CI/CD.
+A file called gitlab_artifacts_token
in the
+$CREDENTIALS_DIRECTORY
.
+The CI_JOB_TOKEN
environment variable. This is intended
+for use in Gitlab pipelines, in order to avoid having to
+create explicit tokens. Note that your instance might be set
+up with restrictive default permissions for the job token.
+
+
+project – The path (e.g. my_username/my_cool_project
) or numeric ID of the
+project to pull the artifacts from. Defaults to the
+$CI_PROJECT_ID
environment variable, which Gitlab sets to
+the project currently executing a pipeline.
+branch – The branch to pull artifacts from. Defaults to the value of the
+CI_DEFAULT_BRANCH
environment variable, or main
if that
+is unset. Ignored if a numeric ID is given for job
.
+job –
Name of the job to pull artifacts from. May also be a numeric
+job ID.
+If a job name was given, the Gitlab API is queried for the most
+recent successful job on the given branch
that has attached
+artifacts. Note that jobs whose artifacts have been deleted (for
+example, because their retention period expired) are ignored.
+By default, at most 1000 jobs will be checked. This includes all
+successful jobs in the repo, regardless of their name or the
+branch they ran on. This number can be changed using the
+CAPELLAMBSE_GLART_MAX_JOBS
environment variable.
+
+subdir – An optional path prefix inside the artifacts archive to prepend
+to all file names.
+disable_cache – Clear the local cache and discard any previously cached data.
+
+
+
+
+
+
+__init__ ( path , * , subdir = '/' , token = None , project = None , branch = None , job , disable_cache = False )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+get_model_info ( )
+
+Return type:
+ModelInfo
+
+
+
+
+
+
+open ( filename , mode = 'rb' )
+Open the model file for reading or writing.
+A “file” in this context does not necessarily refer to a
+physical file on disk; it may just as well be streamed in via
+network or other means. Due to this, the file-like returned by
+this method is not required to support random access.
+
+Parameters:
+
+filename (str | PurePosixPath ) – The name of the file, relative to the path
that was
+given to the constructor.
+mode (Literal [ 'r' , 'rb' , 'w' , 'wb' ] ) – The mode to open the file in. Either "r"
or "rb"
for
+reading, or "w"
or "wb"
for writing a new file. Be
+aware that this method may refuse to open a file for writing
+unless a transaction was started with
+write_transaction()
first.
+
+
+Return type:
+BinaryIO
+
+
+
+
+
+
+
+
+capellambse.filehandler.http module
+
+
+class capellambse.filehandler.http. DownloadStream
+Bases: BinaryIO
+
+
+__init__ ( session , url , chunk_size = 1048576 )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+close ( )
+
+Return type:
+None
+
+
+
+
+
+
+read ( n = -1 )
+
+Parameters:
+n (int ) –
+
+Return type:
+bytes
+
+
+
+
+
+
+readable ( )
+
+Return type:
+bool
+
+
+
+
+
+
+writable ( )
+
+Return type:
+bool
+
+
+
+
+
+
+write ( s )
+
+Parameters:
+s (bytes | bytearray ) –
+
+Return type:
+int
+
+
+
+
+
+
+
+
+class capellambse.filehandler.http. HTTPFileHandler
+Bases: FileHandler
+A remote file handler that fetches files using HTTP GET.
+
+
+__init__ ( path , username = None , password = None , * , headers = None , subdir = '/' )
+Connect to a remote server through HTTP or HTTPS.
+This file handler supports two ways of specifying a URL:
+
+If a plain URL is passed, the requested file name is appended
+after a forward slash /
.
+The URL may contain one or more of the following escape
+sequences to provide more fine-grained control over how and
+where the file name is inserted into the URL:
+
+%s
: The path to the file, with everything except
+forward slashes percent-escaped
+%q
: The path to the file, with forward slashes percent
+escaped as well
+%d
: The directory name, without trailing slash, like %s
+%n
: The file name without extension
+%e
: The file extension without leading dot
+%%
: A literal percent sign
+
+
+
+Examples: When requesting the file name demo/my model.aird
,
+…
+
+https://example.com/~user
as path
results in the URL
+https://example.com/~user/demo/my%20model.aird
+https://example.com/~user/%s
results in
+https://example.com/~user/demo/my%20model.aird
+https://example.com/?file=%q
results in
+https://example.com/?file=demo%2Fmy%20model.aird
+
+Note that the file name that is inserted into the URL will never
+start with a forward slash. This means that a URL like
+https://example.com%s
will not work; you need to hard-code
+the slash at the appropriate place.
+This also applies to the %q
escape. If the server expects
+the file name argument to start with a slash, hard-code a
+percent-escaped slash in the URL. For example, instead of
+...?file=%q
use ...?file=%2F%q
.
+
+Parameters:
+
+path (str | PathLike ) – The base URL to fetch files from. Must start with
+http://
or https://
. See above for how to specify
+complex URLs.
+username (str | None ) – The username for HTTP Basic Auth.
+password (str | None ) – The password for HTTP Basic Auth.
+headers (Mapping [ str , str ] | None ) – Additional HTTP headers to send to the server.
+subdir (str | PurePosixPath ) – Prepend this path to all requested files. It is subject to
+the same file name escaping rules explained above.
+
+
+Return type:
+None
+
+
+
+
+
+
+get_model_info ( )
+
+Return type:
+ModelInfo
+
+
+
+
+
+
+iterdir ( path = '.' , / )
+Iterate over the contents of a directory.
+This method is equivalent to calling
+fh.rootdir.joinpath(path).iterdir()
.
+
+Parameters:
+path (str | PurePosixPath ) – The directory to list. If not given, lists the contents of
+the root directory (i.e. the one specified by path
and
+subdir
).
+
+Return type:
+Iterator [FilePath [Self ]]
+
+
+
+
+
+
+open ( filename , mode = 'rb' )
+Open the model file for reading or writing.
+A “file” in this context does not necessarily refer to a
+physical file on disk; it may just as well be streamed in via
+network or other means. Due to this, the file-like returned by
+this method is not required to support random access.
+
+Parameters:
+
+filename (str | PurePosixPath ) – The name of the file, relative to the path
that was
+given to the constructor.
+mode (Literal [ 'r' , 'rb' , 'w' , 'wb' ] ) – The mode to open the file in. Either "r"
or "rb"
for
+reading, or "w"
or "wb"
for writing a new file. Be
+aware that this method may refuse to open a file for writing
+unless a transaction was started with
+write_transaction()
first.
+
+
+Return type:
+BinaryIO
+
+
+
+
+
+
+write_transaction ( ** kw )
+Start a transaction for writing new model files.
+During a transaction, writable objects returned by
+open()
buffer their contents in a temporary location,
+and once the transaction ends, all updated files are committed
+to their destinations at once. If the transaction is aborted,
+for example because an exception was raised, then all changes
+must be rolled back to the state immediately before the
+transaction. If, during a transaction, any relevant file is
+touched without the file handler knowing about it, the behavior
+is undefined.
+Note that open()
may refuse to open a file as writable
+if no transaction is currently open. This depends on the needs
+of the underlying abstract file system.
+Transaction arguments
+A concrete file handler implementation may accept arbitrary
+additional arguments to this method. The implementation should
+however always support the case of no arguments given, in which
+case it should start a transaction with sensible defaults, and
+it should also accept and ignore any arguments it does not
+understand. All additional arguments must be passed in via
+keywords. Positional arguments are not supported.
+The return value of the context manager’s __enter__()
method
+is expected to be a mapping of all the keyword arguments that
+were not understood. Client code may use this to react properly
+(e.g. by aborting the transaction early) if a required keyword
+argument is found to be not supported by the underlying file
+handler. If a subclass wishes to call its super class’
+write_transaction()
method, it should remove all the keyword
+arguments that it handles itself and pass on the others
+unchanged.
+Well-known arguments
+The following arguments are considered well-known, and their
+meaning is expected to be the same for all file handlers that
+support them.
+
+dry_run
(bool
): If set to True
, changes made
+during the transaction should be rolled back instead of
+being committed, just as if an exception had been raised.
+author_name
(str
): The name of the author of the
+changes.
+author_email
(str
): The e-mail address to record
+alongside the author_name
.
+commit_msg
(str
): A message describing the changes,
+which will be recorded in the version control system.
+remote_branch
(str
): If the model came from a remote
+version control system, changes are normally pushed back to
+the same branch on that remote. This argument specifies an
+alternative branch name to push to (which may not yet exist
+on the remote).
+
+
+Parameters:
+kw (Any ) –
+
+Return type:
+NoReturn
+
+
+
+
+
+
+
+
+capellambse.filehandler.local module
+
+
+class capellambse.filehandler.local. LocalFileHandler
+Bases: FileHandler
+
+
+__init__ ( path , * , subdir = '/' )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+get_model_info ( )
+
+Return type:
+ModelInfo
+
+
+
+
+
+
+iterdir ( subdir = '.' )
+Iterate over the contents of a directory.
+This method is equivalent to calling
+fh.rootdir.joinpath(path).iterdir()
.
+
+Parameters:
+
+path – The directory to list. If not given, lists the contents of
+the root directory (i.e. the one specified by path
and
+subdir
).
+subdir (str | PurePosixPath ) –
+
+
+Return type:
+Iterator [LocalFilePath ]
+
+
+
+
+
+
+open ( filename , mode = 'rb' )
+Open the model file for reading or writing.
+A “file” in this context does not necessarily refer to a
+physical file on disk; it may just as well be streamed in via
+network or other means. Due to this, the file-like returned by
+this method is not required to support random access.
+
+Parameters:
+
+filename (str | PurePosixPath ) – The name of the file, relative to the path
that was
+given to the constructor.
+mode (Literal [ 'r' , 'rb' , 'w' , 'wb' ] ) – The mode to open the file in. Either "r"
or "rb"
for
+reading, or "w"
or "wb"
for writing a new file. Be
+aware that this method may refuse to open a file for writing
+unless a transaction was started with
+write_transaction()
first.
+
+
+Return type:
+BinaryIO
+
+
+
+
+
+
+property rootdir : LocalFilePath
+The root directory of the file handler.
+
+
+
+
+write_transaction ( * , dry_run = False , ** kw )
+Start a write transaction.
+During the transaction, file writes are redirected to temporary
+files next to the target files, and if the transaction ends
+successfully they are moved to their destinations all at once.
+
+Parameters:
+
+
+Return type:
+Generator [Mapping [str , Any ], None, None]
+
+
+
+
+
+
+
+
+class capellambse.filehandler.local. LocalFilePath
+Bases: FilePath
[LocalFileHandler
]
+
+
+is_dir ( )
+Return True if self is a directory
+
+Return type:
+bool
+
+
+
+
+
+
+is_file ( )
+Return True if self is a file
+
+Return type:
+bool
+
+
+
+
+
+
+
+
+capellambse.filehandler.memory module
+
+
+class capellambse.filehandler.memory. MemoryFile
+Bases: BinaryIO
+
+
+__init__ ( data , mode )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+read ( n = -1 )
+
+Parameters:
+n (int ) –
+
+Return type:
+bytes
+
+
+
+
+
+
+write ( s )
+
+Parameters:
+s (bytes | bytearray ) –
+
+Return type:
+int
+
+
+
+
+
+
+
+
+class capellambse.filehandler.memory. MemoryFileHandler
+Bases: FileHandler
+A file handler that stores data in memory.
+
+
+__init__ ( path = 'memory:' , * , subdir = '/' )
+Initialize a new memory file handler.
+
+Parameters:
+
+path (str | PathLike ) – An optional path to a directory to use as fallback. Opened
+files’ contents will be prepopulated with the contents of
+files from this directory.
+subdir (str | PurePosixPath ) – An optional path to prepend to all opened (physical) files.
+
+
+Return type:
+None
+
+
+
+
+
+
+get_model_info ( )
+
+Return type:
+ModelInfo
+
+
+
+
+
+
+iterdir ( path = '/' , / )
+Iterate over the contents of a directory.
+This method is equivalent to calling
+fh.rootdir.joinpath(path).iterdir()
.
+
+Parameters:
+path (str | PurePosixPath ) – The directory to list. If not given, lists the contents of
+the root directory (i.e. the one specified by path
and
+subdir
).
+
+Return type:
+Iterator [MemoryFilePath ]
+
+
+
+
+
+
+open ( filename , mode = 'rb' )
+Open the model file for reading or writing.
+A “file” in this context does not necessarily refer to a
+physical file on disk; it may just as well be streamed in via
+network or other means. Due to this, the file-like returned by
+this method is not required to support random access.
+
+Parameters:
+
+filename (str | PurePosixPath ) – The name of the file, relative to the path
that was
+given to the constructor.
+mode (Literal [ 'r' , 'rb' , 'w' , 'wb' ] ) – The mode to open the file in. Either "r"
or "rb"
for
+reading, or "w"
or "wb"
for writing a new file. Be
+aware that this method may refuse to open a file for writing
+unless a transaction was started with
+write_transaction()
first.
+
+
+Return type:
+BinaryIO
+
+
+
+
+
+
+property rootdir : MemoryFilePath
+The root directory of the file handler.
+
+
+
+
+
+
+class capellambse.filehandler.memory. MemoryFilePath
+Bases: FilePath
[MemoryFileHandler
]
+
+
+is_dir ( )
+Return True if self is a directory
+
+Return type:
+bool
+
+
+
+
+
+
+is_file ( )
+Return True if self is a file
+
+Return type:
+bool
+
+
+
+
+
+
+
+
+capellambse.filehandler.zip module
+
+
+class capellambse.filehandler.zip. ZipFileHandler
+Bases: FileHandler
+File handler that can read from zip files.
+
+Parameters:
+
+path (str | os.PathLike ) –
Location of the zip file. May contain a nested path, like
+zip+https://host.name/%s
, which will be resolved using an
+appropriate file handler.
+If zipname
is not passed or is None, the path may include the zip
+file name as well, using either !
or /
as separator. For
+example, the following calls are equivalent:
+ZipFileHandler ( "zip+https://host.name/path/to/file.zip" )
+ZipFileHandler ( "zip+https://host.name/path/to!file.zip" )
+ZipFileHandler ( "zip+https://host.name/path/to/ %s !file.zip" )
+
+
+
+
Note
+
The %s
replacement shown in this example is done by the
+underlying HTTPFileHandler
,
+which is used to fetch the nested https://
URL. Other nested
+protocols may require different syntax.)
+
+
+
Note
+
It is currently not possible to pass down arbitrary arguments to the
+underlying FileHandler other than the path
.
+
+
+zipname – Name of the zip file in the above path.
+subdir –
A subdirectory inside the zip file to use as base directory.
+If the zip file contains only a single directory entry and no
+other files at the root, this directory is used as default. Pass
+subdir="."
explicitly to override this behaviour.
+
+
+
+
+
+
+__init__ ( path , zipname = None , subdir = None )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+get_model_info ( )
+
+Return type:
+ModelInfo
+
+
+
+
+
+
+is_dir ( path , / )
+
+Parameters:
+path (str | PurePosixPath ) –
+
+Return type:
+bool
+
+
+
+
+
+
+is_file ( path , / )
+
+Parameters:
+path (str | PurePosixPath ) –
+
+Return type:
+bool
+
+
+
+
+
+
+iterdir ( path = '.' , / )
+Iterate over the contents of a directory.
+This method is equivalent to calling
+fh.rootdir.joinpath(path).iterdir()
.
+
+Parameters:
+path (str | PurePosixPath ) – The directory to list. If not given, lists the contents of
+the root directory (i.e. the one specified by path
and
+subdir
).
+
+Return type:
+Iterator [FilePath [ZipFileHandler ]]
+
+
+
+
+
+
+open ( filename , mode = 'rb' )
+Open the model file for reading or writing.
+A “file” in this context does not necessarily refer to a
+physical file on disk; it may just as well be streamed in via
+network or other means. Due to this, the file-like returned by
+this method is not required to support random access.
+
+Parameters:
+
+filename (str | PurePosixPath ) – The name of the file, relative to the path
that was
+given to the constructor.
+mode (Literal [ 'r' , 'rb' , 'w' , 'wb' ] ) – The mode to open the file in. Either "r"
or "rb"
for
+reading, or "w"
or "wb"
for writing a new file. Be
+aware that this method may refuse to open a file for writing
+unless a transaction was started with
+write_transaction()
first.
+
+
+Return type:
+IO [bytes ]
+
+
+
+
+
+
+property rootdir : FilePath [ ZipFileHandler ]
+The root directory of the file handler.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.html b/code/capellambse.html
new file mode 100644
index 000000000..d4d4a749a
--- /dev/null
+++ b/code/capellambse.html
@@ -0,0 +1,2607 @@
+
+
+
+
+
+
+
+
+ capellambse package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse package
+The capellambse package.
+
+
+capellambse. load_model_extensions ( )
+Load all model extensions.
+This function loads all entry points in the group
+capellambse.model_extensions
and executes them.
+Note that this function must be placed at the end of the top-level
+__init__.py
, in order to ensure that all submodules were
+initialized before loading any extensions.
+
+Return type:
+None
+
+
+
+
+
+
+
+capellambse.auditing module
+
+
+class capellambse.auditing. AttributeAuditor
+Bases: object
+Audits access to attributes of ModelElements.
+
+
Warning
+
This will permanently add an audit hook to the global hook
+table. The auditor will keep the model alive, which may consume
+excessive memory. To avoid this, call the auditor object’s
+detach()
method once you are done with it. This is
+automatically done if you use it as a context manager.
+
+Examples
+>>> auditor = AttributeAuditor ( model , { "name" , "description" })
+>>> print ( model . la . all_components [ 0 ] . name )
+Hogwarts
+>>> auditor . recorded_ids
+{'0d2edb8f-fa34-4e73-89ec-fb9a63001440'}
+>>> # Cleanup
+>>> auditor . detach ()
+
+
+>>> with AttributeAuditor ( model , { "name" , "description" }) as recorded_ids :
+... print ( model . la . all_components [ 0 ] . name )
+...
+Hogwarts
+>>> recorded_ids
+{'0d2edb8f-fa34-4e73-89ec-fb9a63001440'}
+
+
+
+
+__init__ ( model , attrs = () )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+detach ( )
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.auditing. WriteProtector
+Bases: object
+Prevents accidental modifications to a model.
+This class intentionally has very limited features. It is intended
+as inspiration and guidance for more specific classes that make more
+sophisticated use of audit events.
+This class also contains a publicly usable set of events that
+signify changes to the model.
+
+
+__init__ ( model )
+
+Parameters:
+model (MelodyModel ) –
+
+Return type:
+None
+
+
+
+
+
+
+detach ( )
+
+Return type:
+None
+
+
+
+
+
+
+events : Final = frozenset({'capellambse.create', 'capellambse.delete', 'capellambse.insert', 'capellambse.setattr', 'capellambse.setitem'})
+Contains all built-in audit events that may modify the model.
+
+
+
+
+
+
+capellambse.cli_helpers module
+Helpers for working with models in CLI scripts.
+
+
+capellambse.cli_helpers. ModelCLI ( * __ , ** _ )
+Raise a dependency error.
+
+
+
+
+capellambse.cli_helpers. ModelInfoCLI ( * __ , ** _ )
+Raise a dependency error.
+
+
+
+
+capellambse.cli_helpers. enumerate_known_models ( )
+Enumerate the models that are found in the known_models
folders.
+Two places are searched for models: The known_models folder in the
+user’s configuration directory, and the known_models folder in the
+installed capellambse
package.
+Run the following command to print the location of the user’s
+known_models folder:
+ python -m capellambse.cli_helpers
+
+
+In order to make a custom model known, place a JSON file in one of
+these known_models folders. It should contain a dictionary with
+the keyword arguments to MelodyModel
-
+specifically it needs a path
, optionally an entrypoint
, and
+any additional arguments that the underlying
+FileHandler
might need to gain
+access to the model.
+Files in the user’s configuration directory take precedence over
+files in the package directory. If a file with the same name exists
+in both places, the one in the user’s configuration directory will
+be used.
+Be aware that relative paths in the JSON will be interpreted
+relative to the current working directory.
+
+Return type:
+Iterator [Traversable ]
+
+
+
+
+
+
+capellambse.cli_helpers. loadcli ( value )
+Load a model from a file or JSON string.
+This function works like loadinfo()
, and also loads the model
+for convenience.
+
+Parameters:
+value (str | PathLike [ str ] ) – As described for loadinfo()
.
+
+Returns:
+The loaded model, as described by the value .
+
+Return type:
+MelodyModel
+
+
+Examples
+def main ():
+ model = capellambse . loadcli ( sys . argv [ 1 ])
+
+
+
+
+
+
+capellambse.cli_helpers. loadinfo ( value )
+Load information about how to load a model as dict.
+
+Parameters:
+value (str | PathLike [ str ] ) –
One of the following:
+
+A str or PathLike pointing to an .aird
file
+A str or PathLike pointing to a .json
file, which
+contains the arguments to instantiate a
+MelodyModel
+The contents of such a JSON file (as string)
+
+
+
+Returns:
+A dict with information about how to load a
+MelodyModel
.
+
+Return type:
+dict [str , Any ]
+
+Raises:
+
+TypeError – If the value cannot be parsed as described above.
+ValueError – If the value looks like a “known model” name, but the name is
+ not defined.
+
+
+
+Examples
+def main ():
+ modelinfo = capellambse . loadinfo ( sys . argv [ 1 ])
+ # change any options, for example:
+ modelinfo [ "diagram_cache" ] = "/tmp/diagrams"
+ model = MelodyModel ( ** modelinfo )
+
+
+
+
+
+
+capellambse.decl module
+Support for YAML-based declarative modelling.
+A YAML-based approach to describing how to create and modify
+capellambse
compatible models.
+For an in-depth explanation, please refer to the full
+documentation about declarative modelling .
+
+
+class capellambse.decl. FindBy
+Bases: object
+Find an object by specific attributes.
+
+
+__init__ ( attributes )
+
+Parameters:
+attributes (Mapping [ str , Any ] ) –
+
+Return type:
+None
+
+
+
+
+
+
+attributes : Mapping [ str , Any ]
+
+
+
+
+
+
+capellambse.decl. NewObject
+alias of _NewObject
+
+
+
+
+class capellambse.decl. Promise
+Bases: object
+References a model object that will be created later.
+
+
+__init__ ( identifier )
+
+Parameters:
+identifier (str ) –
+
+Return type:
+None
+
+
+
+
+
+
+identifier : str
+
+
+
+
+
+
+class capellambse.decl. UUIDReference
+Bases: object
+References a model object by its UUID.
+
+
+__init__ ( uuid )
+
+Parameters:
+uuid (UUIDString ) –
+
+Return type:
+None
+
+
+
+
+
+
+uuid : UUIDString
+
+
+
+
+
+
+exception capellambse.decl. UnfulfilledPromisesError
+Bases: RuntimeError
+A promise could not be fulfilled.
+This exception is raised when a promise is referenced via
+!promise
, but it is never fulfilled by declaring an object with
+the same promise_id
.
+
+
+
+
+class capellambse.decl. YDMDumper
+Bases: SafeDumper
+A YAML dumper with extensions for declarative modelling.
+
+
+represent_findby ( data )
+
+Parameters:
+data (Any ) –
+
+Return type:
+Node
+
+
+
+
+
+
+represent_newobj ( data )
+
+Parameters:
+data (Any ) –
+
+Return type:
+Node
+
+
+
+
+
+
+represent_promise ( data )
+
+Parameters:
+data (Any ) –
+
+Return type:
+Node
+
+
+
+
+
+
+represent_uuidref ( data )
+
+Parameters:
+data (Any ) –
+
+Return type:
+Node
+
+
+
+
+
+
+yaml_representers = {<class 'NoneType'>: <function SafeRepresenter.represent_none>, <class 'bool'>: <function SafeRepresenter.represent_bool>, <class 'bytes'>: <function SafeRepresenter.represent_binary>, <class 'capellambse.decl.FindBy'>: <function YDMDumper.represent_findby>, <class 'capellambse.decl.Promise'>: <function YDMDumper.represent_promise>, <class 'capellambse.decl.UUIDReference'>: <function YDMDumper.represent_uuidref>, <class 'capellambse.model.common.accessors._NewObject'>: <function YDMDumper.represent_newobj>, <class 'datetime.date'>: <function SafeRepresenter.represent_date>, <class 'datetime.datetime'>: <function SafeRepresenter.represent_datetime>, <class 'dict'>: <function SafeRepresenter.represent_dict>, <class 'float'>: <function SafeRepresenter.represent_float>, <class 'int'>: <function SafeRepresenter.represent_int>, <class 'list'>: <function SafeRepresenter.represent_list>, <class 'set'>: <function SafeRepresenter.represent_set>, <class 'str'>: <function SafeRepresenter.represent_str>, <class 'tuple'>: <function SafeRepresenter.represent_list>, None: <function SafeRepresenter.represent_undefined>}
+
+
+
+
+
+
+class capellambse.decl. YDMLoader
+Bases: SafeLoader
+A YAML loader with extensions for declarative modelling.
+
+
+construct_findby ( node )
+
+Parameters:
+node (Node ) –
+
+Return type:
+FindBy
+
+
+
+
+
+
+construct_newobj ( node )
+
+Parameters:
+node (Node ) –
+
+Return type:
+_NewObject
+
+
+
+
+
+
+construct_promise ( node )
+
+Parameters:
+node (Node ) –
+
+Return type:
+Promise
+
+
+
+
+
+
+construct_uuidref ( node )
+
+Parameters:
+node (Node ) –
+
+Return type:
+UUIDReference
+
+
+
+
+
+
+yaml_constructors = {'!find': <function YDMLoader.construct_findby>, '!new_object': <function YDMLoader.construct_newobj>, '!promise': <function YDMLoader.construct_promise>, '!uuid': <function YDMLoader.construct_uuidref>, 'tag:yaml.org,2002:binary': <function SafeConstructor.construct_yaml_binary>, 'tag:yaml.org,2002:bool': <function SafeConstructor.construct_yaml_bool>, 'tag:yaml.org,2002:float': <function SafeConstructor.construct_yaml_float>, 'tag:yaml.org,2002:int': <function SafeConstructor.construct_yaml_int>, 'tag:yaml.org,2002:map': <function SafeConstructor.construct_yaml_map>, 'tag:yaml.org,2002:null': <function SafeConstructor.construct_yaml_null>, 'tag:yaml.org,2002:omap': <function SafeConstructor.construct_yaml_omap>, 'tag:yaml.org,2002:pairs': <function SafeConstructor.construct_yaml_pairs>, 'tag:yaml.org,2002:seq': <function SafeConstructor.construct_yaml_seq>, 'tag:yaml.org,2002:set': <function SafeConstructor.construct_yaml_set>, 'tag:yaml.org,2002:str': <function SafeConstructor.construct_yaml_str>, 'tag:yaml.org,2002:timestamp': <function SafeConstructor.construct_yaml_timestamp>, None: <function SafeConstructor.construct_undefined>}
+
+
+
+
+
+
+capellambse.decl. apply ( model , file )
+Apply a declarative modelling file to the given model.
+
+Parameters:
+
+
+Return type:
+dict [Promise , ModelObject ]
+
+
+Notes
+This function is not transactional: If an exception occurs during
+this function, the model will be left partially modified, with no
+reliable way to know how much of the YAML input has been consumed.
+It is therefore advised to reload or discard the model immediately
+in these cases, to avoid working with an inconsistent state.
+Even though the YAML layout suggests linear execution from top to
+bottom, the actual order in which modifications are executed is
+implementation defined. This is necessary to support promises with
+!promise
, but reorderings are still possible even if no promises
+are used in an input document.
+
+
+
+
+capellambse.decl. dump ( instructions )
+Dump an instruction stream to YAML.
+
+Parameters:
+instructions (Sequence [ Mapping [ str , Any ] ] ) –
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.decl. load ( file )
+Load an instruction stream from a YAML file.
+
+Parameters:
+file (IO [ str ] | str | PathLike [ Any ] ) – An open file-like object, or a path or PathLike pointing to such
+a file. Files are expected to use UTF-8 encoding.
+
+Return type:
+list [dict [str , Any ]]
+
+
+
+
+
+
+capellambse.diagram_cache module
+CLI for the diagram cache updating feature.
+
+
+capellambse.helpers module
+Miscellaneous utility functions used throughout the modules.
+
+
+class capellambse.helpers. EverythingContainer
+Bases: Container
[Any
]
+A container that contains everything.
+
+
+
+
+capellambse.helpers. escape_linked_text ( loader , attr_text )
+Transform simple HTML with object links into LinkedText
.
+This is the inverse operation of unescape_linked_text()
.
+
+Parameters:
+
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.helpers. extent_func ( text , fonttype = 'OpenSans-Regular.ttf' , size = 12 )
+Calculate the display size of the given text.
+
+Parameters:
+
+text (str ) – Text to calculate pixel size on
+fonttype (str ) – The font type / face
+size (int ) – Font size (px)
+
+
+Returns:
+
+
+
+Return type:
+tuple [float , float ]
+
+
+
+
+
+
+capellambse.helpers. flatten_html_string ( text )
+Convert an HTML-string to plain text.
+
+Parameters:
+text (str ) –
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.helpers. flock ( file )
+
+Parameters:
+file (Path ) –
+
+Return type:
+Iterator [None]
+
+
+
+
+
+
+capellambse.helpers. get_text_extent ( text , width = inf , fonttype = 'OpenSans-Regular.ttf' , fontsize = 12 )
+Calculate the bounding box size of text
after line wrapping.
+
+Parameters:
+
+text (str ) – Text to calculate the size for.
+width (float | int ) – Maximum line length (px).
+fonttype (str ) – The font type / face
+fontsize (int ) – Font size (px)
+
+
+Returns:
+
+
+
+Return type:
+tuple [float , float ]
+
+
+
+
+
+
+capellambse.helpers. get_transformation ( class_ , pos , size )
+Calculate transformation for class.
+The Scaling factor .725, translation constants (6, 5) are arbitrarily
+chosen to fit. Currently only ChoicePseudoState is tranformed.
+
+Parameters:
+
+
+Return type:
+dict [str , str ]
+
+
+
+
+
+
+capellambse.helpers. is_uuid_string ( string )
+Validate that string
is a valid UUID.
+
+Parameters:
+string (Any ) –
+
+Return type:
+TypeGuard [UUIDString ]
+
+
+
+
+
+
+capellambse.helpers. load_font ( fonttype , size )
+
+Parameters:
+
+fonttype (str ) –
+size (int ) –
+
+
+Return type:
+FreeTypeFont
+
+
+
+
+
+
+capellambse.helpers. normalize_pure_path ( path , * , base = '/' )
+Make a PurePosixPath relative to base and collapse ..
components.
+
+Parameters:
+
+
+Returns:
+The normalized path.
+
+Return type:
+pathlib.PurePosixPath
+
+
+
+
+
+
+capellambse.helpers. ntuples ( num : int , iterable : Iterable [ _T ] , * , pad : Literal [ False ] = False ) → Iterator [ tuple [ _T , ... ] ]
+
+capellambse.helpers. ntuples ( num : int , iterable : Iterable [ _T ] , * , pad : Literal [ True ] ) → Iterator [ tuple [ _T | None , ... ] ]
+Yield N items of iterable
at once.
+
+Parameters:
+
+num – The number of items to yield at once.
+iterable – An iterable.
+pad – If the items in iterable
are not evenly divisible by n
,
+pad the last yielded tuple with None
s. If False, the last
+tuple will be discarded.
+
+
+Yields:
+items – A num
long tuple of items from iterable
.
+
+
+
+
+
+
+capellambse.helpers. process_html_fragments ( markup , node_callback )
+Repair and modify HTML markup.
+The original markup, which can be an HTML fragment (without a root
+element), is parsed and processed, and then reassembled into a
+Markup instance. If the original markup contained any errors or
+inconsistencies, these are repaired in the returned Markup instance.
+
+Parameters:
+
+markup (str ) – The markup string to modify.
+node_callback (Callable [ [ _Element ] , None ] ) –
A callback function to process each node in the parsed markup.
+The function should accept a single
+lxml.etree._Element
as argument; its return
+value is ignored.
+Note that, since the markup is parsed as fragments, more than
+the first element passed to the callback may have no parent.
+The callback will not be invoked for leading text, if there is
+any, and thus it has no ability to influence it.
+
+
+
+Returns:
+The processed markup.
+
+Return type:
+markupsafe.Markup
+
+
+
+
+
+
+capellambse.helpers. relpath_pure ( path , start )
+Calculate the relative path between two pure paths.
+Unlike pathlib.PurePath.relative_to()
, this method can cope
+with path
not being a subpath of start
. And unlike the
+os.path.relpath()
function, it does not involve any filesystem
+access.
+
+Parameters:
+
+
+Return type:
+PurePosixPath
+
+
+
+
+
+
+capellambse.helpers. repair_html ( markup )
+Try to repair broken HTML markup to prevent parse errors.
+
+Parameters:
+markup (str ) – The markup to try and repair.
+
+Returns:
+The repaired markup.
+
+Return type:
+markupsafe.Markup
+
+
+
+
+
+
+capellambse.helpers. resolve_namespace ( tag )
+Resolve a ‘:’-delimited symbolic namespace to its canonical form.
+
+Parameters:
+tag (str ) – Symbolic namespace delimited by ‘:’.
+
+Returns:
+Tag string in canonical form.
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.helpers. split_links ( links )
+Split a string containing intra- and inter-fragment links.
+Intra-fragment links are simply “#UUID”, whereas inter-fragment
+links look like “xtype fragment#UUID”. Multiple such links are
+space-separated in a single long string to form a list. This
+function splits such a string back into its individual components
+(each being either an intra- or inter-fragment link), and yields
+them.
+
+Yields:
+str – A single link from the list.
+
+Parameters:
+links (str ) –
+
+Return type:
+Iterator [str ]
+
+
+
+
+
+
+capellambse.helpers. ssvparse ( string , cast , * , parens = ('', '') , sep = ',' , num = 0 )
+Parse a string of sep
-separated values wrapped in parens
.
+
+Parameters:
+
+string (str ) – The input string.
+cast (Callable [ [ str ] , _T ] ) – A type to cast the values into.
+parens (Sequence [ str ] ) – The parentheses that must exist around the input. Either a
+two-character string or a 2-tuple of strings.
+sep (str ) – The separator between values.
+num (int ) – If non-zero, only accept exactly this many values.
+
+
+Returns:
+A list of values cast into the given type.
+
+Return type:
+list [_T]
+
+Raises:
+ValueError – If the parentheses are missing around the input string, or if
+ the expected number of values doesn’t match the actual number.
+
+
+
+
+
+
+capellambse.helpers. unescape_linked_text ( loader , attr_text )
+Transform the linkedText
into regular HTML.
+
+Parameters:
+
+
+Return type:
+Markup
+
+
+
+
+
+
+capellambse.helpers. word_wrap ( text , width )
+Perform word wrapping for proportional fonts.
+Whitespace at the beginning of input lines is preserved, but other
+whitespace is collapsed to single spaces. Words are kept as a whole,
+possibly leading to exceeding width bound.
+
+Parameters:
+
+
+Returns:
+A list of strings, one for each line, after wrapping.
+
+Return type:
+list [str ]
+
+
+
+
+
+
+capellambse.helpers. xpath_fetch_unique ( xpath : str | XPath , tree : _Element , elm_name : str , elm_uid : str | None = None , * , optional : Literal [ False ] = False ) → _Element
+
+capellambse.helpers. xpath_fetch_unique ( xpath : str | XPath , tree : _Element , elm_name : str , elm_uid : str | None = None , * , optional : Literal [ True ] ) → _Element | None
+Fetch an XPath result from the tree, ensuring that it’s unique.
+
+Parameters:
+
+xpath – The lxml.etree.XPath
object to apply, or an XPath
+expression as str.
+tree – The (sub-)tree to which the XPath will be applied.
+elm_name – A human-readable element name for error messages.
+elm_uid – UID of the element which triggered this lookup. Will be included
+in the error message if an error occured.
+optional – True to return None in case the element is not found. Otherwise
+a ValueError will be raised.
+
+
+Returns:
+The Element found by given xpath
.
+
+Return type:
+lxml.etree._Element | None
+
+Raises:
+ValueError – If more than one element was found matching the xpath
, or if
+ optional
is False
and no matching element was found.
+
+
+
+
+
+
+capellambse.helpers. xtype_of ( elem )
+Return the xsi:type
of the element.
+If the element has an xsi:type
attribute, its value is returned.
+If the element does not have an xsi:type
, this function resolves
+the tag’s namespace to the symbolic name and reconstructs the type
+with the namespace:tag
template.
+
+Parameters:
+elem (_Element ) – The lxml.etree._Element
object to return the
+xsi:type
for.
+
+Raises:
+
+
+Returns:
+The xsi:type
string of the provided element or None
if
+the type could not be determined.
+
+Return type:
+str | None
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.loader.html b/code/capellambse.loader.html
new file mode 100644
index 000000000..e7bd84fde
--- /dev/null
+++ b/code/capellambse.loader.html
@@ -0,0 +1,2086 @@
+
+
+
+
+
+
+
+
+ capellambse.loader package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.loader package
+The MelodyLoader loads and provides access to a Capella model.
+It is using LXML internally to efficiently parse and navigate through
+the Capella-generated XML files. For more information about LXML, see
+the LXML Documentation .
+
+
+capellambse.loader.core module
+Helps loading Capella models (including fragmented variants).
+
+
+exception capellambse.loader.core. CorruptModelError
+Bases: Exception
+Raised when the model is corrupted and cannot be processed safely.
+In addition to the short description in the exception’s arguments,
+some validators may also produce additional information in the form
+of CRITICAL log messages just before this exception is raised.
+
+
+
+
+class capellambse.loader.core. FragmentType
+Bases: Enum
+The type of an XML fragment.
+
+
+OTHER = 3
+
+
+
+
+SEMANTIC = 1
+
+
+
+
+VISUAL = 2
+
+
+
+
+
+
+class capellambse.loader.core. MelodyLoader
+Bases: object
+Facilitates extensive access to Polarsys / Capella projects.
+
+
+__init__ ( path , entrypoint = None , * , resources = None , ignore_duplicate_uuids_and_void_all_warranties = False , ** kwargs )
+Construct a MelodyLoader.
+
+Parameters:
+
+path (str | PathLike | FileHandler ) – The path
argument to the primary file handler, or the
+primary file handler itself.
+entrypoint (str | PurePosixPath | None ) – The entry point into the model, i.e. the top-level .aird
+file. This must be located within the primary file handler.
+resources (Mapping [ str , FileHandler | str | PathLike | dict [ str , Any ] ] | None ) – Additional file handler instances that provide library
+resources that are referenced from the model.
+ignore_duplicate_uuids_and_void_all_warranties (bool ) – Ignore corruption due to duplicate UUIDs (see below).
+kwargs (Any ) – Additional arguments to the primary file handler, if
+necessary.
+
+
+Raises:
+CorruptModelError – If the model is corrupt.
+
+ Currently the only kind of corruption that is detected is
+ duplicated UUIDs (either within a fragment or across
+ multiple fragments).
+
+ It is possible to ignore this error and load the model
+ anyways by setting the keyword-only argument
+ ignore_duplicate_uuids_and_void_all_warranties to
+ True
. However, this will lead to strange behavior like
+ random exceptions when searching or filtering, or
+ accidentally working with the wrong object. If you try to
+ make changes to the model, always make sure that you have an
+ up to date backup ready. In order to prevent accidental
+ overwrites with an even corrupter model, you must therefore
+ also set the i_have_a_recent_backup keyword argument to
+ True
when calling save()
.
+
+Return type:
+None
+
+
+
+
+
+
+add_namespace ( fragment , name , uri = None , / )
+Add the given namespace to the given tree’s root element.
+
+Parameters:
+
+fragment (str | PurePosixPath | _Element ) – Either the name of a fragment (as
+PurePosixPath
or str
), or a model
+element. In the latter case, the fragment that contains this
+element is used.
+name (str ) – The canonical name of this namespace. This typically uses
+reverse DNS notation in Capella.
+uri (str | None ) – The namespace URI. If not specified, the canonical name will
+be used to look up the URI in the list of known namespaces.
+
+
+Return type:
+None
+
+
+
+
+
+
+check_duplicate_uuids ( )
+
+Return type:
+None
+
+
+
+
+
+
+create_link ( from_element , to_element , * , include_target_type = None )
+Create a link to to_element
from from_element
.
+
+Parameters:
+
+from_element (_Element ) – The source element of the link.
+to_element (_Element ) – The target element of the link.
+include_target_type (bool | None ) –
Whether to include the target type in cross-fragment link
+definitions.
+If set to True, it will always be included, False will
+always exclude it. Setting it to None (the default) will use
+a simple heuristic: It will be added unless the
+from_element
is in a visual-only fragment (aird /
+airdfragment).
+Regardless of this setting, the target type will never be
+included if the link does not cross fragment boundaries.
+
+
+
+Returns:
+A link in one of the formats described by follow_link()
.
+Which format is used depends on whether from_element
and
+to_element
live in the the same fragment, and whether the
+include_target_type
parameter is set.
+
+Return type:
+str
+
+
+
+
+
+
+property filehandler : FileHandler
+The file handler containing the original model.
+This is a shorthand for self.resources["\0"]
.
+
+
+
+
+find_by_xsi_type ( * xsi_types , roots = None )
+Find all elements matching any of the given xsi:type
s.
+
+Parameters:
+
+xsi_types (str ) – xsi:type
strings to match, for example
+“org.polarsys.capella.core.data.cs:InterfacePkg”
+roots (_Element | Iterable [ _Element ] ) – A list of XML elements to use as roots for the query.
+Defaults to all tree roots.
+
+
+Return type:
+list [_Element ]
+
+
+
+
+
+
+find_fragment ( element )
+Find the name of the fragment that contains element
.
+
+Parameters:
+element (_Element ) –
+
+Return type:
+PurePosixPath
+
+
+
+
+
+
+follow_link ( from_element , link )
+Follow a single link and return the target element.
+Valid links have one of the following two formats:
+
+Within the same fragment, a reference is the target’s UUID
+prepended with a #
, for example
+#7a5b8b30-f596-43d9-b810-45ab02f4a81c
.
+A reference to a different fragment contains the target’s
+xsi:type
and the path of the fragment, relative to the
+current one. For example, to link from main.capella
into
+frag/logical.capellafragment
, the reference could be:
+org.polarsys.capella.core.data.capellacore:Constraint
+frag/logical.capellafragment#7a5b8b30-f596-43d9-b810-45ab02f4a81c
.
+To link back to the project root from there, it could look
+like: org.polarsys.capella.core.data.pa:PhysicalArchitecture
+../main.capella#26e187b6-72e7-4872-8d8d-70b96243c96c
.
+
+
+Parameters:
+
+
+Raises:
+
+ValueError – If the link is malformed
+FileNotFoundError – If the target fragment is not loaded (only applicable if
+ from_element
is not None and fragment
is part of the
+ link)
+RuntimeError – If the expected xsi:type
does not match the actual
+ xsi:type
of the found target
+KeyError – If the target cannot be found
+
+
+Return type:
+_Element
+
+
+
+
+
+
+follow_links ( from_element , links , * , ignore_broken = False )
+Follow multiple links and return all results as list.
+The format for an individual link is the same as accepted by
+follow_link()
. Multiple links are separated by a single space.
+If any target cannot be found, None
will be inserted at that
+point in the returned list.
+
+Parameters:
+
+from_element (_Element | None ) – The element at the start of the link. This is needed to verify
+cross-fragment links.
+links (str ) – A string containing space-separated links as described in
+follow_link()
.
+ignore_broken (bool ) – Ignore broken references instead of raising a KeyError.
+
+
+Raises:
+
+KeyError – If any link points to a non-existing target. Can be
+ suppressed with ignore_broken
.
+ValueError – If any link is malformed.
+RuntimeError – If any expected xsi:type
does not match the actual
+ xsi:type
of the found target.
+
+
+Return type:
+list [_Element ]
+
+
+
+
+
+
+generate_uuid ( parent , * , want = None )
+Generate a unique UUID for a new child of parent
.
+The generated ID is guaranteed to be unique across all currently
+loaded fragments.
+
+Parameters:
+
+parent (_Element ) – The parent element below which the new UUID will be used.
+want (str | None ) – Try this UUID first, and use it if it satisfies all other
+constraints. If it does not satisfy all constraints (e.g. it
+would be non-unique), a random UUID will be generated as
+normal.
+
+
+Returns:
+The new UUID.
+
+Return type:
+str
+
+
+
+
+
+
+get_model_info ( )
+Return information about the loaded model.
+
+Return type:
+ModelInfo
+
+
+
+
+
+
+idcache_index ( subtree )
+Index the IDs of subtree
.
+This method must be called after adding subtree
to the XML
+tree.
+
+Parameters:
+subtree (_Element ) – The new element that was just inserted.
+
+Return type:
+None
+
+
+
+
+
+
+idcache_rebuild ( )
+Rebuild the ID caches of all loaded ModelFile
instances.
+
+Return type:
+None
+
+
+
+
+
+
+idcache_remove ( subtree )
+Remove the subtree
from the ID cache.
+This method must be called before actually removing subtree
+from the XML tree.
+
+Parameters:
+subtree (_Element ) – The element that is about to be removed.
+
+Return type:
+None
+
+
+
+
+
+
+iterall ( * tags )
+Iterate over all elements in all trees by tags.
+
+Parameters:
+tags (str ) – Optionally restrict the iterator to the given tags.
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+iterall_xt ( * xtypes , trees = None )
+Iterate over all elements in all trees by xsi:type
s.
+
+Parameters:
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+iterancestors ( element , * tags )
+Iterate over the ancestors of element
.
+This method will follow fragment links back to the origin point.
+
+Parameters:
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+iterchildren_xt ( element , * xtypes )
+Iterate over the children of element
.
+This method will follow links into different fragment files and
+yield those elements as if they were direct children.
+
+Parameters:
+
+element (_Element ) – The parent element under which to search for children.
+xtypes (str ) – Only yield elements whose xsi:type
matches one of those
+given here. If no types are given, all elements are yielded.
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+iterdescendants ( root_elm , * tags )
+Iterate over all descendants of root_elm
.
+This method will follow links into different fragment files and
+yield those elements as if they were part of the origin subtree.
+
+Parameters:
+
+root_elm (_Element ) – The root element of the tree
+tags (str ) – Only yield elements with a matching XML tag. If none are
+given, all elements are yielded.
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+iterdescendants_xt ( element , * xtypes )
+Iterate over all descendants of element
by xsi:type
.
+This method will follow links into different fragment files and
+yield those elements as if they were part of the origin subtree.
+
+Parameters:
+
+element (_Element ) – The root element of the tree
+xtypes (str ) – Only yield elements whose xsi:type
matches one of those
+given here. If no types are given, all elements are yielded.
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+new_uuid ( parent , * , want = None )
+Context Manager around generate_uuid()
.
+This context manager yields a newly generated model-wide unique
+UUID that can be inserted into a new element during the with
+block. It tries to keep the ID cache consistent in some harder
+to manage edge cases, like exceptions being thrown. Additionally
+it checks that the generated UUID was actually used in the tree;
+not using it before the with
block ends is an error and
+provokes an Exception.
+
+
Note
+
You still need to call idcache_index()
on the
+newly inserted element!
+
+Example usage:
+>>> with ldr . new_uuid ( parent_elm ) as obj_id :
+... child_elm = parent_elm . makeelement ( "ownedObjects" )
+... child_elm . set ( "id" , obj_id )
+... parent_elm . append ( child_elm )
+... ldr . idcache_index ( child_elm )
+
+
+If you intend to reserve a UUID that should be inserted later,
+use generate_uuid()
directly.
+
+Parameters:
+
+parent (_Element ) – The parent element below which the new UUID will be used.
+want (str | None ) – Request this UUID. The request may or may not be fulfilled;
+always use the actual UUID returned by the context manager.
+
+
+Return type:
+Generator [str , None, None]
+
+
+
+
+
+
+referenced_viewpoints ( )
+
+Return type:
+Iterator [tuple [str , str ]]
+
+
+
+
+
+
+save ( ** kw )
+Save all model files.
+
+Parameters:
+kw (Any ) – Additional keyword arguments accepted by the file handler in
+use. Please see the respective documentation for more info.
+
+Return type:
+None
+
+
+
+Notes
+With a filehandler
that contacts a remote location (such
+as the capellambse.filehandler.git.GitFileHandler
with
+non-local repositories), saving might fail if the local state
+has gone out of sync with the remote state. To avoid this,
+always leave the update_cache
parameter at its default value
+of True
if you intend to save changes.
+
+
+
+
+write_tmp_project_dir ( )
+Create a temporary directory with this model as Capella project.
+This method writes the loaded project files (model and library
+files, if any) into a temporary directory. The main model is
+always placed in a subdirectory called “main_model”; any library
+models are placed in subdirectories named after the resource
+that the library was loaded from. Additionally, a .project
+file is generated in each subdirectory to allow direct import
+into Capella.
+The directory yielded from this method can be directly used as
+the workspace of a Capella instance.
+
+Return type:
+Iterator [Path ]
+
+
+
+
+
+
+xpath ( query , * , namespaces = None , roots = None )
+Run an XPath query on all fragments.
+Note that, unlike the iter_*
methods, placeholder elements
+are not followed into their respective fragment.
+
+Parameters:
+
+query (str | XPath ) – The XPath query
+namespaces (Mapping [ str , str ] | None ) – Namespaces used in the query. Defaults to all known
+namespaces.
+roots (_Element | Iterable [ _Element ] | None ) – A list of XML elements to use as roots for the query.
+Defaults to all tree roots.
+
+
+Returns:
+A list of all matching elements.
+
+Return type:
+list [lxml.etree._Element ]
+
+
+
+
+
+
+xpath2 ( query , * , namespaces = None , roots = None )
+Run an XPath query and return the fragments and elements.
+Note that, unlike the iter_*
methods, placeholder elements
+are not followed into their respective fragment.
+The tuples have the fragment where the match was found as first
+element, and the LXML element as second one.
+
+Parameters:
+
+query (str | XPath ) – The XPath query
+namespaces (Mapping [ str , str ] | None ) – Namespaces used in the query. Defaults to all known
+namespaces.
+roots (_Element | Iterable [ _Element ] | None ) – A list of XML elements to use as roots for the query.
+Defaults to all tree roots.
+
+
+Returns:
+
A list of 2-tuples, containing:
+
+The fragment name where the match was found.
+The matching element.
+
+
+
+Return type:
+list [tuple [pathlib.PurePosixPath , lxml.etree._Element ]]
+
+
+
+
+
+
+
+
+class capellambse.loader.core. ModelFile
+Bases: object
+Represents a single file in the model (i.e. a fragment).
+
+
+__init__ ( filename , handler , * , ignore_uuid_dups )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+add_namespace ( name , uri )
+Add the given namespace to this tree’s root element.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+enumerate_uuids ( )
+Enumerate all UUIDs used in this fragment.
+
+Return type:
+set [str ]
+
+
+
+
+
+
+property fragment_type : FragmentType
+
+
+
+
+idcache_index ( subtree )
+Index the IDs of subtree
.
+
+Parameters:
+subtree (_Element ) –
+
+Return type:
+None
+
+
+
+
+
+
+idcache_rebuild ( )
+Invalidate and rebuild this file’s ID cache.
+
+Return type:
+None
+
+
+
+
+
+
+idcache_remove ( source )
+Remove the ID or all IDs below the source from the ID cache.
+
+Parameters:
+source (str | _Element ) –
+
+Return type:
+None
+
+
+
+
+
+
+idcache_reserve ( new_id )
+Reserve the given ID for an element to be inserted later.
+
+Parameters:
+new_id (str ) –
+
+Return type:
+None
+
+
+
+
+
+
+iterall_xt ( xtypes )
+Iterate over all elements in this tree by xsi:type
.
+
+Parameters:
+xtypes (Container [ str ] ) –
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+property tree : _ElementTree
+
+
+
+
+unfollow_href ( element_id )
+Unfollow a fragment link and return the placeholder element.
+If the given UUID is not linked to from this file, None is
+returned.
+
+Parameters:
+element_id (str ) –
+
+Return type:
+_Element
+
+
+
+
+
+
+write_xml ( file , encoding = 'utf-8' )
+Write this file’s XML into the file specified by path
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+capellambse.loader.exs module
+An Eclipse-like XML serializer.
+The libxml2 XML serializer produces very different output from the one
+used by Capella. This causes a file saved by libxml2 to look vastly
+different, even though semantically nothing might have changed at all.
+This module implements a serializer which produces output like Capella
+does.
+
+
+capellambse.loader.exs. serialize ( tree , / , * , encoding = 'utf-8' , errors = 'strict' , line_length = 80 , siblings = None )
+Serialize an XML tree.
+The iterator returned by this function yields the serialized XML
+piece by piece.
+
+Parameters:
+
+tree (_Element | _ElementTree ) – The XML tree to serialize.
+encoding (str ) – The encoding to use when generating XML.
+errors (str ) – The encoding error handling behavior.
+line_length (float | int ) – The number of characters after which to force a line break.
+siblings (bool | None ) – Also include siblings of the given subtree. Defaults to yes if
+‘tree’ is an element tree, no if it’s a single element.
+
+
+Returns:
+An iterator that yields the serialized XML piece by piece.
+
+Return type:
+Iterator[str ]
+
+
+
+
+
+
+capellambse.loader.exs. to_bytes ( tree , / , * , encoding = 'utf-8' , errors = 'strict' , declare_encoding = True )
+Serialize an XML tree as a str
.
+At the start of the document, an XML processing instruction will be
+inserted declaring the used encoding. Pass
+declare_encoding=False
to inhibit this behavior.
+
+Parameters:
+
+tree (_Element ) – The XML tree to serialize.
+encoding (str ) – The encoding to use. An XML processing instruction will be
+inserted which declares the used encoding.
+errors (str ) – How to handle errors during encoding.
+declare_encoding (bool ) –
+
+
+Returns:
+The serialized XML, encoded using encoding
.
+
+Return type:
+bytes
+
+
+
+
+
+
+capellambse.loader.exs. to_string ( tree , / )
+Serialize an XML tree as a str
.
+No XML processing instruction will be inserted at the start of the
+document.
+
+Parameters:
+tree (_Element ) – The XML tree to serialize.
+
+Returns:
+The serialized XML.
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.loader.exs. write ( tree , / , file , * , encoding = 'utf-8' , errors = 'strict' , line_length = 80 , siblings = False )
+Write the XML tree to file
.
+
+Parameters:
+
+tree (_Element ) – The XML tree to serialize.
+file (_HasWrite | PathLike | str | bytes ) – An open file or a PathLike to write the XML into.
+encoding (str ) – The file encoding to use when opening a file.
+errors (str ) – Set the encoding error handling behavior of newly opened files.
+line_length (float | int ) – The number of characters after which to force a line break.
+siblings (bool ) – Also include siblings of the given subtree.
+
+
+Return type:
+None
+
+
+
+
+
+
+capellambse.loader.filehandler module
+
+
+class capellambse.loader.filehandler. FileHandler
+Bases: object
+Abstract super class for file handler implementations.
+
+Parameters:
+
+path (str | os.PathLike ) – The location of the remote. The exact accepted forms are
+determined by the specific file handler implementation, for
+example the LocalFileHandler
accepts only local paths, and
+the GitFileHandler
accepts everything that Git accepts.
+subdir – Consider all paths relative to this subdirectory, instead of the
+root of the file handler’s hierarchy.
+
+
+
+
+
+__init__ ( path , * , subdir = '/' , ** kw )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+abstract get_model_info ( )
+
+Return type:
+modelinfo.ModelInfo
+
+
+
+
+
+
+is_dir ( path , / )
+
+Parameters:
+path (str | PurePosixPath ) –
+
+
+
+
+
+
+is_file ( path , / )
+
+Parameters:
+path (str | PurePosixPath ) –
+
+
+
+
+
+
+iterdir ( path = '.' , / )
+Iterate over the contents of a directory.
+This method is equivalent to calling
+fh.rootdir.joinpath(path).iterdir()
.
+
+Parameters:
+path (str | PurePosixPath ) – The directory to list. If not given, lists the contents of
+the root directory (i.e. the one specified by path
and
+subdir
).
+
+Return type:
+Iterator [FilePath [Self ]]
+
+
+
+
+
+
+abstract open ( filename , mode = 'rb' )
+Open the model file for reading or writing.
+A “file” in this context does not necessarily refer to a
+physical file on disk; it may just as well be streamed in via
+network or other means. Due to this, the file-like returned by
+this method is not required to support random access.
+
+Parameters:
+
+filename (str | PurePosixPath ) – The name of the file, relative to the path
that was
+given to the constructor.
+mode (Literal [ 'r' , 'rb' , 'w' , 'wb' ] ) – The mode to open the file in. Either "r"
or "rb"
for
+reading, or "w"
or "wb"
for writing a new file. Be
+aware that this method may refuse to open a file for writing
+unless a transaction was started with
+write_transaction()
first.
+
+
+Return type:
+IO [bytes ]
+
+
+
+
+
+
+path : str | PathLike
+
+
+
+
+read_file ( path , / )
+Read a file.
+This method is a convenience wrapper around open()
.
+
+Parameters:
+path (str | PurePosixPath ) –
+
+Return type:
+bytes
+
+
+
+
+
+
+property rootdir : FilePath [ Self ]
+The root directory of the file handler.
+
+
+
+
+write_file ( path , content , / )
+Write a file.
+This method is a convenience wrapper around open()
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+write_transaction ( ** kw )
+Start a transaction for writing new model files.
+During a transaction, writable objects returned by
+open()
buffer their contents in a temporary location,
+and once the transaction ends, all updated files are committed
+to their destinations at once. If the transaction is aborted,
+for example because an exception was raised, then all changes
+must be rolled back to the state immediately before the
+transaction. If, during a transaction, any relevant file is
+touched without the file handler knowing about it, the behavior
+is undefined.
+Note that open()
may refuse to open a file as writable
+if no transaction is currently open. This depends on the needs
+of the underlying abstract file system.
+Transaction arguments
+A concrete file handler implementation may accept arbitrary
+additional arguments to this method. The implementation should
+however always support the case of no arguments given, in which
+case it should start a transaction with sensible defaults, and
+it should also accept and ignore any arguments it does not
+understand. All additional arguments must be passed in via
+keywords. Positional arguments are not supported.
+The return value of the context manager’s __enter__()
method
+is expected to be a mapping of all the keyword arguments that
+were not understood. Client code may use this to react properly
+(e.g. by aborting the transaction early) if a required keyword
+argument is found to be not supported by the underlying file
+handler. If a subclass wishes to call its super class’
+write_transaction()
method, it should remove all the keyword
+arguments that it handles itself and pass on the others
+unchanged.
+Well-known arguments
+The following arguments are considered well-known, and their
+meaning is expected to be the same for all file handlers that
+support them.
+
+dry_run
(bool
): If set to True
, changes made
+during the transaction should be rolled back instead of
+being committed, just as if an exception had been raised.
+author_name
(str
): The name of the author of the
+changes.
+author_email
(str
): The e-mail address to record
+alongside the author_name
.
+commit_msg
(str
): A message describing the changes,
+which will be recorded in the version control system.
+remote_branch
(str
): If the model came from a remote
+version control system, changes are normally pushed back to
+the same branch on that remote. This argument specifies an
+alternative branch name to push to (which may not yet exist
+on the remote).
+
+
+Parameters:
+kw (Any ) –
+
+Return type:
+ContextManager [Mapping [str , Any ]]
+
+
+
+
+
+
+
+
+exception capellambse.loader.filehandler. TransactionClosedError
+Bases: RuntimeError
+Raised when a transaction must be opened first to write files.
+
+
+
+
+capellambse.loader.filehandler. get_filehandler ( path , ** kwargs )
+
+Parameters:
+
+
+Return type:
+FileHandler
+
+
+
+
+
+
+capellambse.loader.modelinfo module
+
+
+class capellambse.loader.modelinfo. ModelInfo
+Bases: object
+ModelInfo(branch: ‘str | None’ = None, title: ‘str | None’ = None, url: ‘str | None’ = None, revision: ‘str | None’ = None, rev_hash: ‘str | None’ = None, capella_version: ‘str | None’ = None, viewpoints: ‘dict[str, str]’ = <factory>)
+
+
+__init__ ( branch=None , title=None , url=None , revision=None , rev_hash=None , capella_version=None , viewpoints=<factory> )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+branch : str | None = None
+
+
+
+
+capella_version : str | None = None
+
+
+
+
+rev_hash : str | None = None
+
+
+
+
+revision : str | None = None
+
+
+
+
+title : str | None = None
+
+
+
+
+url : str | None = None
+
+
+
+
+viewpoints : dict [ str , str ]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.model.common.html b/code/capellambse.model.common.html
new file mode 100644
index 000000000..d5e62d914
--- /dev/null
+++ b/code/capellambse.model.common.html
@@ -0,0 +1,3126 @@
+
+
+
+
+
+
+
+
+ capellambse.model.common package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.model.common package
+Common classes used by all MelodyModel functions.
+
+
+
+capellambse.model.common. XTYPE_ANCHORS = {'capellambse.extensions.filtering': 'filtering', 'capellambse.extensions.reqif._capellareq': 'CapellaRequirements', 'capellambse.extensions.reqif._requirements': 'Requirements', 'capellambse.model': 'org.polarsys.capella.core.data.capellamodeller', 'capellambse.model.crosslayer': 'org.polarsys.capella.core.data', 'capellambse.model.diagram': 'viewpoint', 'capellambse.model.layers': 'org.polarsys.capella.core.data'}
+A mapping from anchor modules to Capella packages.
+This dictionary maps Python modules and packages to the Capella packages
+they represent. build_xtype
and related functions/classes can then
+use this information to automatically derive an xsi:type
from any
+class that is defined in such an anchor module (or a submodule of one).
+
+
+
+
+capellambse.model.common. XTYPE_HANDLERS : dict [ str | None , dict [ str , type [ Any ] ] ] = {'org.polarsys.capella.core.data.ctx:SystemAnalysis': {'org.polarsys.capella.core.data.ctx:Capability': <class 'capellambse.model.layers.ctx.Capability'>, 'org.polarsys.capella.core.data.ctx:CapabilityExploitation': <class 'capellambse.model.layers.ctx.CapabilityExploitation'>, 'org.polarsys.capella.core.data.ctx:CapabilityInvolvement': <class 'capellambse.model.layers.ctx.CapabilityInvolvement'>, 'org.polarsys.capella.core.data.ctx:CapabilityPkg': <class 'capellambse.model.layers.ctx.CapabilityPkg'>, 'org.polarsys.capella.core.data.ctx:Mission': <class 'capellambse.model.layers.ctx.Mission'>, 'org.polarsys.capella.core.data.ctx:MissionInvolvement': <class 'capellambse.model.layers.ctx.MissionInvolvement'>, 'org.polarsys.capella.core.data.ctx:MissionPkg': <class 'capellambse.model.layers.ctx.MissionPkg'>, 'org.polarsys.capella.core.data.ctx:SystemComponent': <class 'capellambse.model.layers.ctx.SystemComponent'>, 'org.polarsys.capella.core.data.ctx:SystemComponentPkg': <class 'capellambse.model.layers.ctx.SystemComponentPkg'>, 'org.polarsys.capella.core.data.ctx:SystemFunction': <class 'capellambse.model.layers.ctx.SystemFunction'>, 'org.polarsys.capella.core.data.ctx:SystemFunctionPkg': <class 'capellambse.model.layers.ctx.SystemFunctionPkg'>}, 'org.polarsys.capella.core.data.la:LogicalArchitecture': {'org.polarsys.capella.core.data.la:CapabilityRealization': <class 'capellambse.model.layers.la.CapabilityRealization'>, 'org.polarsys.capella.core.data.la:CapabilityRealizationPkg': <class 'capellambse.model.layers.la.CapabilityRealizationPkg'>, 'org.polarsys.capella.core.data.la:LogicalComponent': <class 'capellambse.model.layers.la.LogicalComponent'>, 'org.polarsys.capella.core.data.la:LogicalComponentPkg': <class 'capellambse.model.layers.la.LogicalComponentPkg'>, 'org.polarsys.capella.core.data.la:LogicalFunction': <class 'capellambse.model.layers.la.LogicalFunction'>, 'org.polarsys.capella.core.data.la:LogicalFunctionPkg': <class 'capellambse.model.layers.la.LogicalFunctionPkg'>}, 'org.polarsys.capella.core.data.oa:OperationalAnalysis': {'org.polarsys.capella.core.data.oa:CommunicationMean': <class 'capellambse.model.layers.oa.CommunicationMean'>, 'org.polarsys.capella.core.data.oa:Entity': <class 'capellambse.model.layers.oa.Entity'>, 'org.polarsys.capella.core.data.oa:EntityOperationalCapabilityInvolvement': <class 'capellambse.model.layers.oa.EntityOperationalCapabilityInvolvement'>, 'org.polarsys.capella.core.data.oa:EntityPkg': <class 'capellambse.model.layers.oa.EntityPkg'>, 'org.polarsys.capella.core.data.oa:OperationalActivity': <class 'capellambse.model.layers.oa.OperationalActivity'>, 'org.polarsys.capella.core.data.oa:OperationalActivityPkg': <class 'capellambse.model.layers.oa.OperationalActivityPkg'>, 'org.polarsys.capella.core.data.oa:OperationalCapability': <class 'capellambse.model.layers.oa.OperationalCapability'>, 'org.polarsys.capella.core.data.oa:OperationalCapabilityPkg': <class 'capellambse.model.layers.oa.OperationalCapabilityPkg'>, 'org.polarsys.capella.core.data.oa:OperationalProcess': <class 'capellambse.model.layers.oa.OperationalProcess'>}, 'org.polarsys.capella.core.data.pa:PhysicalArchitecture': {'org.polarsys.capella.core.data.pa:PhysicalComponent': <class 'capellambse.model.layers.pa.PhysicalComponent'>, 'org.polarsys.capella.core.data.pa:PhysicalComponentPkg': <class 'capellambse.model.layers.pa.PhysicalComponentPkg'>, 'org.polarsys.capella.core.data.pa:PhysicalFunction': <class 'capellambse.model.layers.pa.PhysicalFunction'>, 'org.polarsys.capella.core.data.pa:PhysicalFunctionPkg': <class 'capellambse.model.layers.pa.PhysicalFunctionPkg'>}, None: {'CapellaRequirements:CapellaIncomingRelation': <class 'capellambse.extensions.reqif._capellareq.CapellaIncomingRelation'>, 'CapellaRequirements:CapellaModule': <class 'capellambse.extensions.reqif._capellareq.CapellaModule'>, 'CapellaRequirements:CapellaOutgoingRelation': <class 'capellambse.extensions.reqif._capellareq.CapellaOutgoingRelation'>, 'CapellaRequirements:CapellaTypesFolder': <class 'capellambse.extensions.reqif._capellareq.CapellaTypesFolder'>, 'Requirements:AttributeDefinition': <class 'capellambse.extensions.reqif._requirements.AttributeDefinition'>, 'Requirements:AttributeDefinitionEnumeration': <class 'capellambse.extensions.reqif._requirements.AttributeDefinitionEnumeration'>, 'Requirements:BooleanValueAttribute': <class 'capellambse.extensions.reqif._requirements.BooleanValueAttribute'>, 'Requirements:DataTypeDefinition': <class 'capellambse.extensions.reqif._requirements.DataTypeDefinition'>, 'Requirements:DateValueAttribute': <class 'capellambse.extensions.reqif._requirements.DateValueAttribute'>, 'Requirements:EnumValue': <class 'capellambse.extensions.reqif._requirements.EnumValue'>, 'Requirements:EnumerationDataTypeDefinition': <class 'capellambse.extensions.reqif._requirements.EnumerationDataTypeDefinition'>, 'Requirements:EnumerationValueAttribute': <class 'capellambse.extensions.reqif._requirements.EnumerationValueAttribute'>, 'Requirements:Folder': <class 'capellambse.extensions.reqif._requirements.Folder'>, 'Requirements:IntegerValueAttribute': <class 'capellambse.extensions.reqif._requirements.IntegerValueAttribute'>, 'Requirements:InternalRelation': <class 'capellambse.extensions.reqif._requirements.InternalRelation'>, 'Requirements:ModuleType': <class 'capellambse.extensions.reqif._requirements.ModuleType'>, 'Requirements:RealValueAttribute': <class 'capellambse.extensions.reqif._requirements.RealValueAttribute'>, 'Requirements:RelationType': <class 'capellambse.extensions.reqif._requirements.RelationType'>, 'Requirements:Requirement': <class 'capellambse.extensions.reqif._requirements.Requirement'>, 'Requirements:RequirementType': <class 'capellambse.extensions.reqif._requirements.RequirementType'>, 'Requirements:StringValueAttribute': <class 'capellambse.extensions.reqif._requirements.StringValueAttribute'>, 'filtering:ComposedFilteringResult': <class 'capellambse.extensions.filtering.ComposedFilteringResult'>, 'filtering:FilteringCriterion': <class 'capellambse.extensions.filtering.FilteringCriterion'>, 'filtering:FilteringCriterionPkg': <class 'capellambse.extensions.filtering.FilteringCriterionPkg'>, 'filtering:FilteringModel': <class 'capellambse.extensions.filtering.FilteringModel'>, 'filtering:FilteringResult': <class 'capellambse.extensions.filtering.FilteringResult'>, 'org.polarsys.capella.core.data.capellacommon:DeepHistoryPseudoState': <class 'capellambse.model.crosslayer.capellacommon.DeepHistoryPseudoState'>, 'org.polarsys.capella.core.data.capellacommon:FinalState': <class 'capellambse.model.crosslayer.capellacommon.FinalState'>, 'org.polarsys.capella.core.data.capellacommon:ForkPseudoState': <class 'capellambse.model.crosslayer.capellacommon.ForkPseudoState'>, 'org.polarsys.capella.core.data.capellacommon:GenericTrace': <class 'capellambse.model.crosslayer.capellacommon.GenericTrace'>, 'org.polarsys.capella.core.data.capellacommon:InitialPseudoState': <class 'capellambse.model.crosslayer.capellacommon.InitialPseudoState'>, 'org.polarsys.capella.core.data.capellacommon:JoinPseudoState': <class 'capellambse.model.crosslayer.capellacommon.JoinPseudoState'>, 'org.polarsys.capella.core.data.capellacommon:Mode': <class 'capellambse.model.crosslayer.capellacommon.Mode'>, 'org.polarsys.capella.core.data.capellacommon:Region': <class 'capellambse.model.crosslayer.capellacommon.Region'>, 'org.polarsys.capella.core.data.capellacommon:ShallowHistoryPseudoState': <class 'capellambse.model.crosslayer.capellacommon.ShallowHistoryPseudoState'>, 'org.polarsys.capella.core.data.capellacommon:State': <class 'capellambse.model.crosslayer.capellacommon.State'>, 'org.polarsys.capella.core.data.capellacommon:StateMachine': <class 'capellambse.model.crosslayer.capellacommon.StateMachine'>, 'org.polarsys.capella.core.data.capellacommon:StateTransition': <class 'capellambse.model.crosslayer.capellacommon.StateTransition'>, 'org.polarsys.capella.core.data.capellacommon:TerminatePseudoState': <class 'capellambse.model.crosslayer.capellacommon.TerminatePseudoState'>, 'org.polarsys.capella.core.data.capellacore:BooleanPropertyValue': <class 'capellambse.model.crosslayer.capellacore.BooleanPropertyValue'>, 'org.polarsys.capella.core.data.capellacore:Constraint': <class 'capellambse.model.crosslayer.capellacore.Constraint'>, 'org.polarsys.capella.core.data.capellacore:EnumerationPropertyLiteral': <class 'capellambse.model.crosslayer.capellacore.EnumerationPropertyLiteral'>, 'org.polarsys.capella.core.data.capellacore:EnumerationPropertyType': <class 'capellambse.model.crosslayer.capellacore.EnumerationPropertyType'>, 'org.polarsys.capella.core.data.capellacore:EnumerationPropertyValue': <class 'capellambse.model.crosslayer.capellacore.EnumerationPropertyValue'>, 'org.polarsys.capella.core.data.capellacore:FloatPropertyValue': <class 'capellambse.model.crosslayer.capellacore.FloatPropertyValue'>, 'org.polarsys.capella.core.data.capellacore:Generalization': <class 'capellambse.model.crosslayer.capellacore.Generalization'>, 'org.polarsys.capella.core.data.capellacore:IntegerPropertyValue': <class 'capellambse.model.crosslayer.capellacore.IntegerPropertyValue'>, 'org.polarsys.capella.core.data.capellacore:PropertyValueGroup': <class 'capellambse.model.crosslayer.capellacore.PropertyValueGroup'>, 'org.polarsys.capella.core.data.capellacore:PropertyValuePkg': <class 'capellambse.model.crosslayer.capellacore.PropertyValuePkg'>, 'org.polarsys.capella.core.data.capellacore:StringPropertyValue': <class 'capellambse.model.crosslayer.capellacore.StringPropertyValue'>, 'org.polarsys.capella.core.data.capellamodeller:Library': <class 'capellambse.model.MelodyModel'>, 'org.polarsys.capella.core.data.capellamodeller:Project': <class 'capellambse.model.MelodyModel'>, 'org.polarsys.capella.core.data.cs:ComponentRealization': <class 'capellambse.model.crosslayer.cs.ComponentRealization'>, 'org.polarsys.capella.core.data.cs:ExchangeItemAllocation': <class 'capellambse.model.crosslayer.cs.ExchangeItemAllocation'>, 'org.polarsys.capella.core.data.cs:Interface': <class 'capellambse.model.crosslayer.cs.Interface'>, 'org.polarsys.capella.core.data.cs:InterfacePkg': <class 'capellambse.model.crosslayer.cs.InterfacePkg'>, 'org.polarsys.capella.core.data.cs:Part': <class 'capellambse.model.crosslayer.cs.Part'>, 'org.polarsys.capella.core.data.cs:PhysicalLink': <class 'capellambse.model.crosslayer.cs.PhysicalLink'>, 'org.polarsys.capella.core.data.cs:PhysicalPath': <class 'capellambse.model.crosslayer.cs.PhysicalPath'>, 'org.polarsys.capella.core.data.cs:PhysicalPort': <class 'capellambse.model.crosslayer.cs.PhysicalPort'>, 'org.polarsys.capella.core.data.ctx:SystemAnalysis': <class 'capellambse.model.layers.ctx.SystemAnalysis'>, 'org.polarsys.capella.core.data.fa:AbstractFunction': <class 'capellambse.model.crosslayer.fa.AbstractFunction'>, 'org.polarsys.capella.core.data.fa:ComponentExchange': <class 'capellambse.model.crosslayer.fa.ComponentExchange'>, 'org.polarsys.capella.core.data.fa:ComponentPort': <class 'capellambse.model.crosslayer.fa.ComponentPort'>, 'org.polarsys.capella.core.data.fa:ControlNode': <class 'capellambse.model.crosslayer.fa.ControlNode'>, 'org.polarsys.capella.core.data.fa:FunctionInputPort': <class 'capellambse.model.crosslayer.fa.FunctionInputPort'>, 'org.polarsys.capella.core.data.fa:FunctionOutputPort': <class 'capellambse.model.crosslayer.fa.FunctionOutputPort'>, 'org.polarsys.capella.core.data.fa:FunctionPort': <class 'capellambse.model.crosslayer.fa.FunctionPort'>, 'org.polarsys.capella.core.data.fa:FunctionRealization': <class 'capellambse.model.crosslayer.fa.FunctionRealization'>, 'org.polarsys.capella.core.data.fa:FunctionalChain': <class 'capellambse.model.crosslayer.fa.FunctionalChain'>, 'org.polarsys.capella.core.data.fa:FunctionalChainInvolvementFunction': <class 'capellambse.model.crosslayer.fa.FunctionalChainInvolvementFunction'>, 'org.polarsys.capella.core.data.fa:FunctionalChainInvolvementLink': <class 'capellambse.model.crosslayer.fa.FunctionalChainInvolvementLink'>, 'org.polarsys.capella.core.data.fa:FunctionalChainReference': <class 'capellambse.model.crosslayer.fa.FunctionalChainReference'>, 'org.polarsys.capella.core.data.fa:FunctionalExchange': <class 'capellambse.model.crosslayer.fa.FunctionalExchange'>, 'org.polarsys.capella.core.data.information.datatype:BooleanType': <class 'capellambse.model.crosslayer.information.datatype.BooleanType'>, 'org.polarsys.capella.core.data.information.datatype:Enumeration': <class 'capellambse.model.crosslayer.information.datatype.Enumeration'>, 'org.polarsys.capella.core.data.information.datatype:NumericType': <class 'capellambse.model.crosslayer.information.datatype.NumericType'>, 'org.polarsys.capella.core.data.information.datatype:PhysicalQuantity': <class 'capellambse.model.crosslayer.information.datatype.PhysicalQuantity'>, 'org.polarsys.capella.core.data.information.datatype:StringType': <class 'capellambse.model.crosslayer.information.datatype.StringType'>, 'org.polarsys.capella.core.data.information.datavalue:ComplexValue': <class 'capellambse.model.crosslayer.information.datavalue.ComplexValue'>, 'org.polarsys.capella.core.data.information.datavalue:EnumerationLiteral': <class 'capellambse.model.crosslayer.information.datavalue.EnumerationLiteral'>, 'org.polarsys.capella.core.data.information.datavalue:EnumerationReference': <class 'capellambse.model.crosslayer.information.datavalue.EnumerationReference'>, 'org.polarsys.capella.core.data.information.datavalue:LiteralNumericValue': <class 'capellambse.model.crosslayer.information.datavalue.LiteralNumericValue'>, 'org.polarsys.capella.core.data.information.datavalue:LiteralStringValue': <class 'capellambse.model.crosslayer.information.datavalue.LiteralStringValue'>, 'org.polarsys.capella.core.data.information.datavalue:ValuePart': <class 'capellambse.model.crosslayer.information.datavalue.ValuePart'>, 'org.polarsys.capella.core.data.information:Association': <class 'capellambse.model.crosslayer.information.Association'>, 'org.polarsys.capella.core.data.information:Class': <class 'capellambse.model.crosslayer.information.Class'>, 'org.polarsys.capella.core.data.information:Collection': <class 'capellambse.model.crosslayer.information.Collection'>, 'org.polarsys.capella.core.data.information:DataPkg': <class 'capellambse.model.crosslayer.information.DataPkg'>, 'org.polarsys.capella.core.data.information:ExchangeItem': <class 'capellambse.model.crosslayer.information.ExchangeItem'>, 'org.polarsys.capella.core.data.information:ExchangeItemElement': <class 'capellambse.model.crosslayer.information.ExchangeItemElement'>, 'org.polarsys.capella.core.data.information:InformationRealization': <class 'capellambse.model.crosslayer.information.InformationRealization'>, 'org.polarsys.capella.core.data.information:PortAllocation': <class 'capellambse.model.crosslayer.information.PortAllocation'>, 'org.polarsys.capella.core.data.information:Property': <class 'capellambse.model.crosslayer.information.Property'>, 'org.polarsys.capella.core.data.information:Union': <class 'capellambse.model.crosslayer.information.Union'>, 'org.polarsys.capella.core.data.information:Unit': <class 'capellambse.model.crosslayer.information.Unit'>, 'org.polarsys.capella.core.data.interaction:AbstractCapabilityExtend': <class 'capellambse.model.crosslayer.interaction.AbstractCapabilityExtend'>, 'org.polarsys.capella.core.data.interaction:AbstractCapabilityGeneralization': <class 'capellambse.model.crosslayer.interaction.AbstractCapabilityGeneralization'>, 'org.polarsys.capella.core.data.interaction:AbstractCapabilityInclude': <class 'capellambse.model.crosslayer.interaction.AbstractCapabilityInclude'>, 'org.polarsys.capella.core.data.interaction:AbstractFunctionAbstractCapabilityInvolvement': <class 'capellambse.model.crosslayer.interaction.AbstractFunctionAbstractCapabilityInvolvement'>, 'org.polarsys.capella.core.data.interaction:CombinedFragment': <class 'capellambse.model.crosslayer.interaction.CombinedFragment'>, 'org.polarsys.capella.core.data.interaction:EventReceiptOperation': <class 'capellambse.model.crosslayer.interaction.EventReceiptOperation'>, 'org.polarsys.capella.core.data.interaction:EventSentOperation': <class 'capellambse.model.crosslayer.interaction.EventSentOperation'>, 'org.polarsys.capella.core.data.interaction:Execution': <class 'capellambse.model.crosslayer.interaction.Execution'>, 'org.polarsys.capella.core.data.interaction:ExecutionEnd': <class 'capellambse.model.crosslayer.interaction.ExecutionEnd'>, 'org.polarsys.capella.core.data.interaction:ExecutionEvent': <class 'capellambse.model.crosslayer.interaction.ExecutionEvent'>, 'org.polarsys.capella.core.data.interaction:FragmentEnd': <class 'capellambse.model.crosslayer.interaction.FragmentEnd'>, 'org.polarsys.capella.core.data.interaction:InstanceRole': <class 'capellambse.model.crosslayer.interaction.InstanceRole'>, 'org.polarsys.capella.core.data.interaction:InteractionOperand': <class 'capellambse.model.crosslayer.interaction.InteractionOperand'>, 'org.polarsys.capella.core.data.interaction:InteractionState': <class 'capellambse.model.crosslayer.interaction.InteractionState'>, 'org.polarsys.capella.core.data.interaction:MessageEnd': <class 'capellambse.model.crosslayer.interaction.MessageEnd'>, 'org.polarsys.capella.core.data.interaction:Scenario': <class 'capellambse.model.crosslayer.interaction.Scenario'>, 'org.polarsys.capella.core.data.interaction:SequenceMessage': <class 'capellambse.model.crosslayer.interaction.SequenceMessage'>, 'org.polarsys.capella.core.data.interaction:StateFragment': <class 'capellambse.model.crosslayer.interaction.StateFragment'>, 'org.polarsys.capella.core.data.la:LogicalArchitecture': <class 'capellambse.model.layers.la.LogicalArchitecture'>, 'org.polarsys.capella.core.data.oa:OperationalAnalysis': <class 'capellambse.model.layers.oa.OperationalAnalysis'>, 'org.polarsys.capella.core.data.pa:PhysicalArchitecture': <class 'capellambse.model.layers.pa.PhysicalArchitecture'>, 'viewpoint:DRepresentationDescriptor': <class 'capellambse.model.diagram.Diagram'>}}
+Defines a mapping between xsi:type
s and wrapper classes.
+The first layer’s keys can be either None
or the xsi:type
of the
+architectural layer that the wrapper should be applied to. In the case
+of None
, the wrapper will be applied to all layers. Note that
+layer-specific wrappers have precedence over layer-agnostic ones.
+These keys map to a further dictionary. This second layer maps from the
+xsi:type
(s) that each wrapper handles to the wrapper class.
+
+
+
+
+capellambse.model.common. build_xtype ( class_ )
+
+Parameters:
+class_ (type [ ModelObject ] ) –
+
+Return type:
+str
+
+
+
+
+
+
+capellambse.model.common. enumliteral ( generic_element , attr , default = 'NOT_SET' )
+
+Parameters:
+
+
+Return type:
+AttributeProperty | str
+
+
+
+
+
+
+capellambse.model.common. find_wrapper ( typehint )
+Find the possible wrapper classes for the hinted type.
+The typehint is either a single class name, or a namespace prefix
+and class name separated by :
. This function searches for all
+known wrapper classes that match the given namespace prefix (if any)
+and which have the given name, and returns them as a tuple. If no
+matching wrapper classes are found, an empty tuple is returned.
+
+Parameters:
+typehint (str ) –
+
+Return type:
+tuple [type [ModelObject ], …]
+
+
+
+
+
+
+capellambse.model.common. set_accessor ( cls , attr , accessor )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+capellambse.model.common. set_self_references ( * args )
+
+Parameters:
+args (tuple [ type [ ModelObject ] , str ] ) –
+
+Return type:
+None
+
+
+
+
+
+
+capellambse.model.common. xtype_handler ( arch = None , / , * xtypes )
+Register a class as handler for a specific xsi:type
.
+arch
is the xsi:type
of the desired architecture. It must
+always be a simple string or None. In the latter case the definition
+applies to all elements regardless of their architectural layer.
+Architecture-specific definitions will always win over
+architecture-independent ones.
+Each string given in xtypes
notes an xsi:type
of elements
+that this class handles. It is possible to specify multiple values,
+in which case the class will be registered for each xsi:type
+under the architectural layer given in arch
.
+Handler classes’ __init__
methods must accept two positional
+arguments. The first argument is the
+MelodyModel
instance which loaded the
+corresponding model, and the second one is
+the LXML element that needs to be handled.
+Example:
+>>> @xtype_handler ( 'arch:xtype' , 'xtype:1' , 'xtype:2' )
+... class Test :
+... _xmltag = "ownedTests"
+... def from_model ( self , model , element , / ):
+... ... # Instantiate from model XML element
+
+
+
+Parameters:
+
+arch (str | None ) –
+xtypes (str ) –
+
+
+Return type:
+Callable [[type [T ]], type [T ]]
+
+
+
+
+
+
+capellambse.model.common.accessors module
+
+
+class capellambse.model.common.accessors. Accessor
+Bases: Generic
[T
]
+Super class for all Accessor types.
+
+
+__init__ ( )
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.model.common.accessors. AlternateAccessor
+Bases: Accessor
[T
]
+Provides access to an “alternate” form of the object.
+
+
+__init__ ( class_ )
+
+Parameters:
+class_ (type [ T ] ) –
+
+
+
+
+
+
+class_
+
+
+
+
+
+
+class capellambse.model.common.accessors. AttrProxyAccessor
+Bases: WritableAccessor
[T
], PhysicalAccessor
[T
]
+Provides access to elements that are linked in an attribute.
+
+
+__init__ ( class_ , attr , * , aslist = None , list_extra_args = None )
+Create an AttrProxyAccessor.
+
+Parameters:
+
+class – The proxy class. Currently only used for type hints.
+attr (str ) – The XML attribute to handle.
+aslist (type [ ElementList ] | None ) – If None, the attribute contains at most one element
+reference, and either None or the constructed proxy will be
+returned. If not None, must be a subclass of
+ElementList
. It
+will be used to return a list of all matched objects.
+list_extra_args (Mapping [ str , Any ] | None ) – Extra arguments to pass to the
+ElementList
+constructor.
+class_ (type [ T ] | None ) –
+
+
+
+
+
+
+
+attr
+
+
+
+
+delete ( elmlist , obj )
+Delete the obj
from the model.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+insert ( elmlist , index , value )
+Insert the value
object into the model.
+The object must be inserted at an appropriate place, so that, if
+elmlist
were to be created afresh, value
would show up
+at index index
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+purge_references ( obj , target )
+Purge references to the given object from the model.
+This method is called while deleting physical objects, in order
+to get rid of references to that object (and its descendants).
+Reference purging is done in two steps, which is why this method
+returns a context manager.
+The first step, executed by the __enter__
method, collects
+references to the target and ensures that deleting them would
+result in a valid model. If any validity constraints would be
+violated, an exception is raised to indicate as such, and the
+whole operation is aborted. This is also when the relevant
+“capellambse.delete” audit events are fired for each reference.
+Once all __enter__
methods have been called, the target
+object is deleted from the model. Then all __exit__
methods
+are called, which triggers the actual deletion of all previously
+discovered references.
+As per the context manager protocol, __exit__
will always be
+called after __enter__
, even if the operation is to be
+aborted. The __exit__
method must therefore inspect whether
+an exception was passed in or not in order to know whether the
+operation succeeded.
+In order to not confuse other context managers and keep the
+model consistent, __exit__
must not raise any further
+exceptions. Exceptions should instead be logged to stderr, for
+example by using the
+logging.Logger.exception()
facility.
+The purge_references
method will only be called for Accessor
+instances that actually contain a reference.
+
+Parameters:
+
+
+Returns:
+A context manager that deals with purging references in a
+transactional manner.
+
+Return type:
+contextlib.AbstractContextManager
+
+Raises:
+
+InvalidModificationError – Raised by the returned context manager’s __enter__
+ method if the attempted modification would result in an
+ invalid model. Note that it is generally preferred to allow
+ the operation and take the necessary steps to keep the model
+ consistent, if possible. This can be achieved for example by
+ deleting dependent objects along with the original deletion
+ target.
+Exception – Any exception may be raised before __enter__
returns in
+ order to abort the transaction and prevent the obj
from
+ being deleted. No exceptions must be raised by __exit__
.
+
+
+
+Examples
+A simple implementation for purging a single object reference
+could look like this:
+@contextlib . contextmanager
+def purge_references ( self , obj , target ):
+ assert self . __get__ ( obj , type ( obj )) == target
+ sys . audit ( "capellambse.delete" , obj , self . __name__ , None )
+
+ yield
+
+ try :
+ self . __delete__ ( obj )
+ except Exception :
+ LOGGER . exception ( "Could not purge a dangling reference" )
+
+
+
+
+
+
+
+
+class capellambse.model.common.accessors. AttributeMatcherAccessor
+Bases: DirectProxyAccessor
[T
]
+
+
+__init__ ( class_ , xtypes = None , * , aslist = None , attributes , ** kwargs )
+Create a DirectProxyAccessor.
+
+Parameters:
+
+class – The proxy class.
+xtypes (str | type [ T ] | Iterable [ str | type [ T ] ] | None ) – The xsi:type
(s) of the child element(s). If None, then
+the constructed proxy will be passed the original element
+instead of a child.
+aslist (type [ ElementList ] | None ) – If None, only a single element must match, which will be
+returned directly. If not None, must be a subclass of
+ElementList
,
+which will be used to return a list of all matched objects.
+follow_abstract – Follow the link in the abstractType
XML attribute of
+each list member and instantiate that object instead. The
+default is to instantiate the child elements directly.
+list_extra_args – Extra arguments to pass to the
+ElementList
+constructor.
+rootelem – A class or xsi:type
(or list thereof) that defines the
+path from the current object’s XML element to the search
+root. If None, the current element will be used directly.
+single_attr – If objects can be created with only a single attribute
+specified, this argument is the name of that attribute. This
+create_singleattr()
.
+class_ (type [ T ] ) –
+attributes (dict [ str , Any ] ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+attributes
+
+
+
+
+
+
+class capellambse.model.common.accessors. CustomAccessor
+Bases: PhysicalAccessor
[T
]
+Customizable alternative to the DirectProxyAccessor.
+
+
Deprecated since version 0.5.4: Deprecated due to overcomplexity and (ironically) a lack of
+flexibility.
+
+
+
+__init__ ( class_ , *elmfinders , elmmatcher=<built-in function contains> , matchtransform=<function CustomAccessor.<lambda>> , aslist=None )
+Create a CustomAccessor.
+
+Parameters:
+
+class – The target subclass of GenericElement
+elmfinders (Callable [ [ GenericElement ] , Iterable [ T ] ] ) – Functions that are called on the current element. Each
+returns an iterable of possible targets.
+aslist (type [ ElementList ] | None ) – If None, only a single element must match, which will be
+returned directly. If not None, must be a subclass of
+ElementList
,
+which will be used to return a list of all matched objects.
+elmmatcher (Callable [ [ U , GenericElement ] , bool ] ) – Function that is called with the transformed target element
+and the current element to determine if the untransformed
+target should be accepted.
+matchtransform (Callable [ [ T ] , U ] ) – Function that transforms a target so that it can be used by
+the matcher function.
+class_ (type [ T ] ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+elmfinders
+
+
+
+
+elmmatcher
+
+
+
+
+matchtransform
+
+
+
+
+
+
+class capellambse.model.common.accessors. DeepProxyAccessor
+Bases: DirectProxyAccessor
[T
]
+A DirectProxyAccessor that searches recursively through the tree.
+
+
+
+
+class capellambse.model.common.accessors. DeprecatedAccessor
+Bases: Accessor
[T
]
+Provides a deprecated alias to another attribute.
+
+
+__init__ ( alternative , / )
+
+Parameters:
+alternative (str ) –
+
+Return type:
+None
+
+
+
+
+
+
+alternative
+
+
+
+
+
+
+class capellambse.model.common.accessors. DirectProxyAccessor
+Bases: WritableAccessor
[T
], PhysicalAccessor
[T
]
+Creates proxy objects on the fly.
+
+
+__init__ ( class_ , xtypes = None , * , aslist = None , follow_abstract = False , list_extra_args = None , rootelem = None , single_attr = None )
+Create a DirectProxyAccessor.
+
+Parameters:
+
+class – The proxy class.
+xtypes (str | type [ T ] | Iterable [ str | type [ T ] ] | None ) – The xsi:type
(s) of the child element(s). If None, then
+the constructed proxy will be passed the original element
+instead of a child.
+aslist (type [ ElementList ] | None ) – If None, only a single element must match, which will be
+returned directly. If not None, must be a subclass of
+ElementList
,
+which will be used to return a list of all matched objects.
+follow_abstract (bool ) – Follow the link in the abstractType
XML attribute of
+each list member and instantiate that object instead. The
+default is to instantiate the child elements directly.
+list_extra_args (dict [ str , Any ] | None ) – Extra arguments to pass to the
+ElementList
+constructor.
+rootelem (str | type [ GenericElement ] | Sequence [ str | type [ GenericElement ] ] | None ) – A class or xsi:type
(or list thereof) that defines the
+path from the current object’s XML element to the search
+root. If None, the current element will be used directly.
+single_attr (str | None ) – If objects can be created with only a single attribute
+specified, this argument is the name of that attribute. This
+create_singleattr()
.
+class_ (type [ T ] ) –
+
+
+
+
+
+
+
+create ( elmlist , / , * type_hints , ** kw )
+Create and return a new element of type elmclass
.
+
+Parameters:
+
+elmlist (ElementListCouplingMixin ) – The (coupled)
+ElementList
to
+insert the new object into.
+type_hints (str | None ) – Hints for finding the correct type of element to create. Can
+either be a full or shortened xsi:type
string, or an
+abbreviation defined by the specific Accessor instance.
+kw (Any ) – Initialize the properties of the new object. Depending on
+the object’s type, some attributes may be required.
+
+
+Return type:
+T
+
+
+
+
+
+
+delete ( elmlist , obj )
+Delete the obj
from the model.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+follow_abstract : bool
+
+
+
+
+insert ( elmlist , index , value )
+Insert the value
object into the model.
+The object must be inserted at an appropriate place, so that, if
+elmlist
were to be created afresh, value
would show up
+at index index
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+purge_references ( obj , target )
+Purge references to the given object from the model.
+This method is called while deleting physical objects, in order
+to get rid of references to that object (and its descendants).
+Reference purging is done in two steps, which is why this method
+returns a context manager.
+The first step, executed by the __enter__
method, collects
+references to the target and ensures that deleting them would
+result in a valid model. If any validity constraints would be
+violated, an exception is raised to indicate as such, and the
+whole operation is aborted. This is also when the relevant
+“capellambse.delete” audit events are fired for each reference.
+Once all __enter__
methods have been called, the target
+object is deleted from the model. Then all __exit__
methods
+are called, which triggers the actual deletion of all previously
+discovered references.
+As per the context manager protocol, __exit__
will always be
+called after __enter__
, even if the operation is to be
+aborted. The __exit__
method must therefore inspect whether
+an exception was passed in or not in order to know whether the
+operation succeeded.
+In order to not confuse other context managers and keep the
+model consistent, __exit__
must not raise any further
+exceptions. Exceptions should instead be logged to stderr, for
+example by using the
+logging.Logger.exception()
facility.
+The purge_references
method will only be called for Accessor
+instances that actually contain a reference.
+
+Parameters:
+
+
+Returns:
+A context manager that deals with purging references in a
+transactional manner.
+
+Return type:
+contextlib.AbstractContextManager
+
+Raises:
+
+InvalidModificationError – Raised by the returned context manager’s __enter__
+ method if the attempted modification would result in an
+ invalid model. Note that it is generally preferred to allow
+ the operation and take the necessary steps to keep the model
+ consistent, if possible. This can be achieved for example by
+ deleting dependent objects along with the original deletion
+ target.
+Exception – Any exception may be raised before __enter__
returns in
+ order to abort the transaction and prevent the obj
from
+ being deleted. No exceptions must be raised by __exit__
.
+
+
+
+Examples
+A simple implementation for purging a single object reference
+could look like this:
+@contextlib . contextmanager
+def purge_references ( self , obj , target ):
+ assert self . __get__ ( obj , type ( obj )) == target
+ sys . audit ( "capellambse.delete" , obj , self . __name__ , None )
+
+ yield
+
+ try :
+ self . __delete__ ( obj )
+ except Exception :
+ LOGGER . exception ( "Could not purge a dangling reference" )
+
+
+
+
+
+
+rootelem : Sequence [ str ]
+
+
+
+
+single_attr : str | None
+
+
+
+
+
+
+class capellambse.model.common.accessors. ElementListCouplingMixin
+Bases: ElementList
[T
], Generic
[T
]
+Couples an ElementList with an Accessor to enable write support.
+This class is meant to be subclassed further, where the subclass has
+both this class and the originally intended one as base classes (but
+no other ones, i.e. there must be exactly two bases). The Accessor
+then inserts itself as the _accessor
class variable on the new
+subclass. This allows the mixed-in methods to delegate actual model
+modifications to the Accessor.
+
+
+__init__ ( * args , parent , fixed_length = 0 , ** kw )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+create ( * type_hints , ** kw )
+Make a new model object (instance of GenericElement).
+Instead of specifying the full xsi:type
including the
+namespace, you can also pass in just the part after the :
+separator. If this is unambiguous, the appropriate
+layer-specific type will be selected automatically.
+This method can be called with or without the layertype
+argument. If a layertype is not given, all layers will be tried
+to find an appropriate xsi:type
handler. Note that setting
+the layertype to None
explicitly is different from not
+specifying it at all; None
tries only the “Transverse
+modelling” type elements.
+
+Parameters:
+
+type_hints (str | None ) – Hints for finding the correct type of element to create. Can
+either be a full or shortened xsi:type
string, or an
+abbreviation defined by the specific Accessor instance.
+kw (Any ) – Initialize the properties of the new object. Depending on
+the object, some attributes may be required.
+
+
+Return type:
+T
+
+
+
+
+
+
+create_singleattr ( arg )
+Make a new model object (instance of GenericElement).
+This new object has only one interesting attribute.
+
+
+Parameters:
+arg (Any ) –
+
+Return type:
+T
+
+
+
+
+
+
+delete_all ( ** kw )
+Delete all matching objects from the model.
+
+Parameters:
+kw (Any ) –
+
+Return type:
+None
+
+
+
+
+
+
+insert ( index , value )
+S.insert(index, value) – insert value before index
+
+Parameters:
+
+index (int ) –
+value (T ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.model.common.accessors. IndexAccessor
+Bases: Accessor
[T
]
+Access a specific index in an ElementList of a fixed size.
+
+
+__init__ ( wrapped , index )
+
+Parameters:
+
+wrapped (str ) –
+index (int ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+index
+
+
+
+
+wrapped
+
+
+
+
+
+
+exception capellambse.model.common.accessors. InvalidModificationError
+Bases: RuntimeError
+Raised when a modification would result in an invalid model.
+
+
+
+
+class capellambse.model.common.accessors. LinkAccessor
+Bases: WritableAccessor
[T
], PhysicalAccessor
[T
]
+Accesses elements through reference elements.
+
+
+__init__ ( tag , xtype , / , * , aslist = None , attr , backattr = None , unique = True )
+Create a LinkAccessor.
+
+Parameters:
+
+tag (str | None ) – The XML tag that the reference elements will have.
+xtype (str | type [ GenericElement ] ) – The xsi:type
that the reference elements will have. This
+has no influence on the elements that are referenced.
+attr (str ) – The attribute on the reference element that contains the
+actual link.
+backattr (str | None ) – An optional attribute on the reference element to store a
+reference back to the owner (parent) object.
+aslist (type [ ElementList ] | None ) – Optionally specify a different subclass of
+ElementList
.
+unique (bool ) – Enforce that each element may only appear once in the list.
+If a duplicate is attempted to be added, an exception will
+be raised. Note that this does not have an effect on lists
+already existing within the loaded model.
+
+
+Return type:
+None
+
+
+
+
+
+
+backattr : str | None
+
+
+
+
+delete ( elmlist , obj )
+Delete the obj
from the model.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+insert ( elmlist , index , value )
+Insert the value
object into the model.
+The object must be inserted at an appropriate place, so that, if
+elmlist
were to be created afresh, value
would show up
+at index index
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+purge_references ( obj , target )
+Purge references to the given object from the model.
+This method is called while deleting physical objects, in order
+to get rid of references to that object (and its descendants).
+Reference purging is done in two steps, which is why this method
+returns a context manager.
+The first step, executed by the __enter__
method, collects
+references to the target and ensures that deleting them would
+result in a valid model. If any validity constraints would be
+violated, an exception is raised to indicate as such, and the
+whole operation is aborted. This is also when the relevant
+“capellambse.delete” audit events are fired for each reference.
+Once all __enter__
methods have been called, the target
+object is deleted from the model. Then all __exit__
methods
+are called, which triggers the actual deletion of all previously
+discovered references.
+As per the context manager protocol, __exit__
will always be
+called after __enter__
, even if the operation is to be
+aborted. The __exit__
method must therefore inspect whether
+an exception was passed in or not in order to know whether the
+operation succeeded.
+In order to not confuse other context managers and keep the
+model consistent, __exit__
must not raise any further
+exceptions. Exceptions should instead be logged to stderr, for
+example by using the
+logging.Logger.exception()
facility.
+The purge_references
method will only be called for Accessor
+instances that actually contain a reference.
+
+Parameters:
+
+
+Returns:
+A context manager that deals with purging references in a
+transactional manner.
+
+Return type:
+contextlib.AbstractContextManager
+
+Raises:
+
+InvalidModificationError – Raised by the returned context manager’s __enter__
+ method if the attempted modification would result in an
+ invalid model. Note that it is generally preferred to allow
+ the operation and take the necessary steps to keep the model
+ consistent, if possible. This can be achieved for example by
+ deleting dependent objects along with the original deletion
+ target.
+Exception – Any exception may be raised before __enter__
returns in
+ order to abort the transaction and prevent the obj
from
+ being deleted. No exceptions must be raised by __exit__
.
+
+
+
+Examples
+A simple implementation for purging a single object reference
+could look like this:
+@contextlib . contextmanager
+def purge_references ( self , obj , target ):
+ assert self . __get__ ( obj , type ( obj )) == target
+ sys . audit ( "capellambse.delete" , obj , self . __name__ , None )
+
+ yield
+
+ try :
+ self . __delete__ ( obj )
+ except Exception :
+ LOGGER . exception ( "Could not purge a dangling reference" )
+
+
+
+
+
+
+tag : str | None
+
+
+
+
+unique
+
+
+
+
+
+
+exception capellambse.model.common.accessors. NonUniqueMemberError
+Bases: ValueError
+Raised when a duplicate member is inserted into a list.
+
+
+property attr
+
+
+
+
+property parent
+
+
+
+
+property target
+
+
+
+
+
+
+class capellambse.model.common.accessors. ParentAccessor
+Bases: PhysicalAccessor
[T
]
+Accesses the parent XML element.
+
+
+__init__ ( class_ )
+
+Parameters:
+class_ (type [ T ] ) –
+
+
+
+
+
+
+
+
+class capellambse.model.common.accessors. PhysicalAccessor
+Bases: Accessor
[T
]
+Helper super class for accessors that work with real elements.
+
+
+__init__ ( class_ , xtypes = None , * , aslist = None , list_extra_args = None )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+aslist : type [ ElementList ] | None
+
+
+
+
+class_ : type [ T ]
+
+
+
+
+
+
+
+
+xtypes : Set [ str ]
+
+
+
+
+
+
+class capellambse.model.common.accessors. PhysicalLinkEndsAccessor
+Bases: AttrProxyAccessor
[T
]
+
+
+__init__ ( class_ , attr , * , aslist )
+Create an AttrProxyAccessor.
+
+Parameters:
+
+class – The proxy class. Currently only used for type hints.
+attr (str ) – The XML attribute to handle.
+aslist (type [ ElementList ] ) – If None, the attribute contains at most one element
+reference, and either None or the constructed proxy will be
+returned. If not None, must be a subclass of
+ElementList
. It
+will be used to return a list of all matched objects.
+list_extra_args – Extra arguments to pass to the
+ElementList
+constructor.
+class_ (type [ T ] ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+attr
+
+
+
+
+purge_references ( obj , target )
+Purge references to the given object from the model.
+This method is called while deleting physical objects, in order
+to get rid of references to that object (and its descendants).
+Reference purging is done in two steps, which is why this method
+returns a context manager.
+The first step, executed by the __enter__
method, collects
+references to the target and ensures that deleting them would
+result in a valid model. If any validity constraints would be
+violated, an exception is raised to indicate as such, and the
+whole operation is aborted. This is also when the relevant
+“capellambse.delete” audit events are fired for each reference.
+Once all __enter__
methods have been called, the target
+object is deleted from the model. Then all __exit__
methods
+are called, which triggers the actual deletion of all previously
+discovered references.
+As per the context manager protocol, __exit__
will always be
+called after __enter__
, even if the operation is to be
+aborted. The __exit__
method must therefore inspect whether
+an exception was passed in or not in order to know whether the
+operation succeeded.
+In order to not confuse other context managers and keep the
+model consistent, __exit__
must not raise any further
+exceptions. Exceptions should instead be logged to stderr, for
+example by using the
+logging.Logger.exception()
facility.
+The purge_references
method will only be called for Accessor
+instances that actually contain a reference.
+
+Parameters:
+
+
+Returns:
+A context manager that deals with purging references in a
+transactional manner.
+
+Return type:
+contextlib.AbstractContextManager
+
+Raises:
+
+InvalidModificationError – Raised by the returned context manager’s __enter__
+ method if the attempted modification would result in an
+ invalid model. Note that it is generally preferred to allow
+ the operation and take the necessary steps to keep the model
+ consistent, if possible. This can be achieved for example by
+ deleting dependent objects along with the original deletion
+ target.
+Exception – Any exception may be raised before __enter__
returns in
+ order to abort the transaction and prevent the obj
from
+ being deleted. No exceptions must be raised by __exit__
.
+
+
+
+Examples
+A simple implementation for purging a single object reference
+could look like this:
+@contextlib . contextmanager
+def purge_references ( self , obj , target ):
+ assert self . __get__ ( obj , type ( obj )) == target
+ sys . audit ( "capellambse.delete" , obj , self . __name__ , None )
+
+ yield
+
+ try :
+ self . __delete__ ( obj )
+ except Exception :
+ LOGGER . exception ( "Could not purge a dangling reference" )
+
+
+
+
+
+
+
+
+class capellambse.model.common.accessors. ReferenceSearchingAccessor
+Bases: PhysicalAccessor
[T
]
+Searches for references to the current element elsewhere.
+
+
+__init__ ( class_ , * attrs , aslist = None )
+Create a ReferenceSearchingAccessor.
+
+Parameters:
+
+class – The type of class to search for references on.
+attrs (str ) – The attributes of the target classes to search through.
+aslist (type [ ElementList ] | None ) – If None, only a single element must match, which will be
+returned directly. If not None, must be a subclass of
+ElementList
,
+which will be used to return a list of all matched objects.
+class_ (type [ T ] | tuple [ type [ ModelObject ] , ... ] ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+attrs : tuple [ attrgetter , ... ]
+
+
+
+
+target_classes : tuple [ type [ ModelObject ] , ... ]
+
+
+
+
+
+
+class capellambse.model.common.accessors. RoleTagAccessor
+Bases: WritableAccessor
, PhysicalAccessor
+
+
+__init__ ( role_tag , * , aslist = None , list_extra_args = None )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+create ( elmlist , / , * type_hints , ** kw )
+Create and return a new element of type elmclass
.
+
+Parameters:
+
+elmlist (ElementListCouplingMixin ) – The (coupled)
+ElementList
to
+insert the new object into.
+type_hints (str | None ) – Hints for finding the correct type of element to create. Can
+either be a full or shortened xsi:type
string, or an
+abbreviation defined by the specific Accessor instance.
+kw (Any ) – Initialize the properties of the new object. Depending on
+the object’s type, some attributes may be required.
+
+
+Return type:
+GenericElement
+
+
+
+
+
+
+delete ( elmlist , obj )
+Delete the obj
from the model.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+insert ( elmlist , index , value )
+Insert the value
object into the model.
+The object must be inserted at an appropriate place, so that, if
+elmlist
were to be created afresh, value
would show up
+at index index
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+purge_references ( obj , target )
+Purge references to the given object from the model.
+This method is called while deleting physical objects, in order
+to get rid of references to that object (and its descendants).
+Reference purging is done in two steps, which is why this method
+returns a context manager.
+The first step, executed by the __enter__
method, collects
+references to the target and ensures that deleting them would
+result in a valid model. If any validity constraints would be
+violated, an exception is raised to indicate as such, and the
+whole operation is aborted. This is also when the relevant
+“capellambse.delete” audit events are fired for each reference.
+Once all __enter__
methods have been called, the target
+object is deleted from the model. Then all __exit__
methods
+are called, which triggers the actual deletion of all previously
+discovered references.
+As per the context manager protocol, __exit__
will always be
+called after __enter__
, even if the operation is to be
+aborted. The __exit__
method must therefore inspect whether
+an exception was passed in or not in order to know whether the
+operation succeeded.
+In order to not confuse other context managers and keep the
+model consistent, __exit__
must not raise any further
+exceptions. Exceptions should instead be logged to stderr, for
+example by using the
+logging.Logger.exception()
facility.
+The purge_references
method will only be called for Accessor
+instances that actually contain a reference.
+
+Parameters:
+
+
+Returns:
+A context manager that deals with purging references in a
+transactional manner.
+
+Return type:
+contextlib.AbstractContextManager
+
+Raises:
+
+InvalidModificationError – Raised by the returned context manager’s __enter__
+ method if the attempted modification would result in an
+ invalid model. Note that it is generally preferred to allow
+ the operation and take the necessary steps to keep the model
+ consistent, if possible. This can be achieved for example by
+ deleting dependent objects along with the original deletion
+ target.
+Exception – Any exception may be raised before __enter__
returns in
+ order to abort the transaction and prevent the obj
from
+ being deleted. No exceptions must be raised by __exit__
.
+
+
+
+Examples
+A simple implementation for purging a single object reference
+could look like this:
+@contextlib . contextmanager
+def purge_references ( self , obj , target ):
+ assert self . __get__ ( obj , type ( obj )) == target
+ sys . audit ( "capellambse.delete" , obj , self . __name__ , None )
+
+ yield
+
+ try :
+ self . __delete__ ( obj )
+ except Exception :
+ LOGGER . exception ( "Could not purge a dangling reference" )
+
+
+
+
+
+
+role_tag
+
+
+
+
+
+
+class capellambse.model.common.accessors. SpecificationAccessor
+Bases: Accessor
[_Specification
]
+Provides access to linked specifications.
+
+
+
+
+class capellambse.model.common.accessors. TypecastAccessor
+Bases: WritableAccessor
[T
], PhysicalAccessor
[T
]
+Changes the static type of the value of another accessor.
+This is useful for when a class has an attribute that is
+polymorphic, but the accessor should always return a specific
+subclass.
+At runtime, this Accessor mostly behaves like a simple alias
+(without performing any runtime type checks or conversions). When
+creating new objects, it will only allow to create objects of the
+specified type.
+
+
+__init__ ( cls , attr )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+aslist : type [ ElementListCouplingMixin ] | None
+
+
+
+
+class_ : type [ T ]
+
+
+
+
+create ( elmlist , / , * type_hints , ** kw )
+Create and return a new element of type elmclass
.
+
+Parameters:
+
+elmlist (ElementListCouplingMixin ) – The (coupled)
+ElementList
to
+insert the new object into.
+type_hints (str | None ) – Hints for finding the correct type of element to create. Can
+either be a full or shortened xsi:type
string, or an
+abbreviation defined by the specific Accessor instance.
+kw (Any ) – Initialize the properties of the new object. Depending on
+the object’s type, some attributes may be required.
+
+
+Return type:
+T
+
+
+
+
+
+
+delete ( elmlist , obj )
+Delete the obj
from the model.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+insert ( elmlist , index , value )
+Insert the value
object into the model.
+The object must be inserted at an appropriate place, so that, if
+elmlist
were to be created afresh, value
would show up
+at index index
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+
+
+purge_references ( obj , target )
+Purge references to the given object from the model.
+This method is called while deleting physical objects, in order
+to get rid of references to that object (and its descendants).
+Reference purging is done in two steps, which is why this method
+returns a context manager.
+The first step, executed by the __enter__
method, collects
+references to the target and ensures that deleting them would
+result in a valid model. If any validity constraints would be
+violated, an exception is raised to indicate as such, and the
+whole operation is aborted. This is also when the relevant
+“capellambse.delete” audit events are fired for each reference.
+Once all __enter__
methods have been called, the target
+object is deleted from the model. Then all __exit__
methods
+are called, which triggers the actual deletion of all previously
+discovered references.
+As per the context manager protocol, __exit__
will always be
+called after __enter__
, even if the operation is to be
+aborted. The __exit__
method must therefore inspect whether
+an exception was passed in or not in order to know whether the
+operation succeeded.
+In order to not confuse other context managers and keep the
+model consistent, __exit__
must not raise any further
+exceptions. Exceptions should instead be logged to stderr, for
+example by using the
+logging.Logger.exception()
facility.
+The purge_references
method will only be called for Accessor
+instances that actually contain a reference.
+
+Parameters:
+
+
+Returns:
+A context manager that deals with purging references in a
+transactional manner.
+
+Return type:
+contextlib.AbstractContextManager
+
+Raises:
+
+InvalidModificationError – Raised by the returned context manager’s __enter__
+ method if the attempted modification would result in an
+ invalid model. Note that it is generally preferred to allow
+ the operation and take the necessary steps to keep the model
+ consistent, if possible. This can be achieved for example by
+ deleting dependent objects along with the original deletion
+ target.
+Exception – Any exception may be raised before __enter__
returns in
+ order to abort the transaction and prevent the obj
from
+ being deleted. No exceptions must be raised by __exit__
.
+
+
+
+Examples
+A simple implementation for purging a single object reference
+could look like this:
+@contextlib . contextmanager
+def purge_references ( self , obj , target ):
+ assert self . __get__ ( obj , type ( obj )) == target
+ sys . audit ( "capellambse.delete" , obj , self . __name__ , None )
+
+ yield
+
+ try :
+ self . __delete__ ( obj )
+ except Exception :
+ LOGGER . exception ( "Could not purge a dangling reference" )
+
+
+
+
+
+
+xtypes : Set [ str ]
+
+
+
+
+
+
+class capellambse.model.common.accessors. WritableAccessor
+Bases: Accessor
[T
]
+An Accessor that also provides write support on lists it returns.
+
+
+__init__ ( * args , aslist , single_attr = None , ** kw )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+aslist : type [ ElementListCouplingMixin ] | None
+
+
+
+
+class_ : type [ T ]
+
+
+
+
+create ( elmlist , / , * type_hints , ** kw )
+Create and return a new element of type elmclass
.
+
+Parameters:
+
+elmlist (ElementListCouplingMixin ) – The (coupled)
+ElementList
to
+insert the new object into.
+type_hints (str | None ) – Hints for finding the correct type of element to create. Can
+either be a full or shortened xsi:type
string, or an
+abbreviation defined by the specific Accessor instance.
+kw (Any ) – Initialize the properties of the new object. Depending on
+the object’s type, some attributes may be required.
+
+
+Return type:
+T
+
+
+
+
+
+
+create_singleattr ( elmlist , arg , / )
+Create an element that only has a single attribute of interest.
+
+Parameters:
+
+
+Return type:
+T
+
+
+
+
+
+
+delete ( elmlist , obj )
+Delete the obj
from the model.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+insert ( elmlist , index , value )
+Insert the value
object into the model.
+The object must be inserted at an appropriate place, so that, if
+elmlist
were to be created afresh, value
would show up
+at index index
.
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+
+
+purge_references ( obj , target )
+Purge references to the given object from the model.
+This method is called while deleting physical objects, in order
+to get rid of references to that object (and its descendants).
+Reference purging is done in two steps, which is why this method
+returns a context manager.
+The first step, executed by the __enter__
method, collects
+references to the target and ensures that deleting them would
+result in a valid model. If any validity constraints would be
+violated, an exception is raised to indicate as such, and the
+whole operation is aborted. This is also when the relevant
+“capellambse.delete” audit events are fired for each reference.
+Once all __enter__
methods have been called, the target
+object is deleted from the model. Then all __exit__
methods
+are called, which triggers the actual deletion of all previously
+discovered references.
+As per the context manager protocol, __exit__
will always be
+called after __enter__
, even if the operation is to be
+aborted. The __exit__
method must therefore inspect whether
+an exception was passed in or not in order to know whether the
+operation succeeded.
+In order to not confuse other context managers and keep the
+model consistent, __exit__
must not raise any further
+exceptions. Exceptions should instead be logged to stderr, for
+example by using the
+logging.Logger.exception()
facility.
+The purge_references
method will only be called for Accessor
+instances that actually contain a reference.
+
+Parameters:
+
+
+Returns:
+A context manager that deals with purging references in a
+transactional manner.
+
+Return type:
+contextlib.AbstractContextManager
+
+Raises:
+
+InvalidModificationError – Raised by the returned context manager’s __enter__
+ method if the attempted modification would result in an
+ invalid model. Note that it is generally preferred to allow
+ the operation and take the necessary steps to keep the model
+ consistent, if possible. This can be achieved for example by
+ deleting dependent objects along with the original deletion
+ target.
+Exception – Any exception may be raised before __enter__
returns in
+ order to abort the transaction and prevent the obj
from
+ being deleted. No exceptions must be raised by __exit__
.
+
+
+
+Examples
+A simple implementation for purging a single object reference
+could look like this:
+@contextlib . contextmanager
+def purge_references ( self , obj , target ):
+ assert self . __get__ ( obj , type ( obj )) == target
+ sys . audit ( "capellambse.delete" , obj , self . __name__ , None )
+
+ yield
+
+ try :
+ self . __delete__ ( obj )
+ except Exception :
+ LOGGER . exception ( "Could not purge a dangling reference" )
+
+
+
+
+
+
+single_attr : str | None
+
+
+
+
+
+
+capellambse.model.common.element module
+
+
+class capellambse.model.common.element. CachedElementList
+Bases: ElementList
[T
], Generic
[T
]
+An ElementList that caches the constructed proxies by UUID.
+
+
+__init__ ( model , elements , elemclass , * , cacheattr = None , ** kw )
+Create a CachedElementList.
+
+Parameters:
+
+model (MelodyModel ) – The model that all elements are a part of.
+elements (list [ _Element ] ) – The members of this list.
+elemclass (type [ T ] ) – The GenericElement
subclass to use for
+reconstructing elements.
+cacheattr (str | None ) – The attribute on the model
to use as cache.
+kw (Any ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.model.common.element. ElementList
+Bases: MutableSequence
, Generic
[T
]
+Provides access to elements without affecting the underlying model.
+
+
+__init__ ( model , elements , elemclass = None , * , mapkey = None , mapvalue = None )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+filter ( predicate )
+Filter this list with a custom predicate.
+The predicate may be the name of an attribute or a callable,
+which will be called on each list item. If the attribute value
+or the callable’s return value is truthy, the item is included
+in the resulting list.
+When specifying the name of an attribute, nested attributes can
+be chained using .
, like "parent.name"
(which would
+pick all elements whose parent
has a non-empty name
).
+
+Parameters:
+predicate (str | Callable [ [ T ] , bool ] ) –
+
+Return type:
+ElementList [T ]
+
+
+
+
+
+
+get ( key : str ) → T | None
+
+get ( key : str , default : U ) → T | U
+
+
+
+
+insert ( index , value )
+S.insert(index, value) – insert value before index
+
+Parameters:
+
+index (int ) –
+value (T ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+items ( )
+
+Return type:
+ElementListMapItemsView [T ]
+
+
+
+
+
+
+keys ( )
+
+Return type:
+ElementListMapKeyView
+
+
+
+
+
+
+map ( attr )
+Apply a function to each element in this list.
+If the argument is a string, it is interpreted as an attribute
+name, and the value of that attribute is returned for each
+element. Nested attribute names can be chained with .
.
+If the argument is a callable, it is called for each element,
+and the return value is included in the result. If the callable
+returns a sequence, the sequence is flattened into the result.
+Duplicate values and Nones are always filtered out.
+It is an error if a callable returns something that is not a
+model element or a flat sequence of model elements.
+
+Parameters:
+attr (str | _MapFunction [ T ] ) –
+
+Return type:
+ElementList [GenericElement ]
+
+
+
+
+
+
+values ( )
+
+Return type:
+ElementList [T ]
+
+
+
+
+
+
+
+
+class capellambse.model.common.element. ElementListMapItemsView
+Bases: Sequence
[Tuple
[Any
, Any
]], Generic
[T
]
+
+
+__init__ ( parent , / )
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.model.common.element. ElementListMapKeyView
+Bases: Sequence
+
+
+__init__ ( parent , / )
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.model.common.element. GenericElement
+Bases: object
+Provides high-level access to a single model element.
+
+
+__init__ ( model , parent , xmltag = None , / , ** kw )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+applied_property_value_groups
+The applied property value groups of this GenericElement.
+
+
+
+
+applied_property_values
+The applied property values of this GenericElement.
+
+
+
+
+constraints : Accessor
+The constraints of this GenericElement.
+
+
+
+
+description
+
+
+
+
+property diagrams
+
+
+
+
+filtering_criteria
+The filtering criteria of this GenericElement.
+
+
+
+
+classmethod from_model ( model , element )
+Wrap an existing model object.
+
+Parameters:
+
+
+Returns:
+An instance of GenericElement (or a more appropriate
+subclass, if any) that wraps the given XML element.
+
+Return type:
+GenericElement
+
+
+
+
+
+
+name
+
+
+
+
+parent : ParentAccessor
+The parent of this GenericElement.
+
+
+
+
+property progress_status : AttributeProperty | str
+
+
+
+
+property_value_groups
+The property value groups of this GenericElement.
+
+
+
+
+property_values
+The property values of this GenericElement.
+
+
+
+
+pvmt
+The pvmt of this GenericElement.
+
+
+
+
+requirements
+The requirements of this GenericElement.
+
+
+
+
+summary
+
+
+
+
+traces
+The traces of this GenericElement.
+
+
+
+
+uuid
+
+
+
+
+property xtype
+
+
+
+
+
+
+class capellambse.model.common.element. MixedElementList
+Bases: ElementList
[GenericElement
]
+ElementList that handles proxies using XTYPE_HANDLERS
.
+
+
+__init__ ( model , elements , elemclass = None , ** kw )
+Create a MixedElementList.
+
+Parameters:
+
+model (MelodyModel ) – The model that all elements are a part of.
+elements (list [ _Element ] ) – The members of this list.
+elemclass (Any ) – Ignored; provided for drop-in compatibility.
+kw (Any ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.model.common.element. ModelObject
+Bases: Protocol
+A class that wraps a specific model object.
+Most of the time, you’ll want to subclass the concrete
+GenericElement
class. However, some special classes (e.g. AIRD
+diagrams) provide a compatible interface, but it doesn’t make sense
+to wrap a specific XML element. This protocol class is used in type
+annotations to catch both “normal” GenericElement subclasses and the
+mentioned special cases.
+
+
+__init__ ( model , parent , xmltag , / , ** kw )
+Create a new model object.
+
+Parameters:
+
+model (MelodyModel ) – The model instance.
+parent (_Element ) – The parent XML element below which to create a new object.
+kw (Any ) – Any additional arguments will be used to populate the
+instance attributes. Note that some attributes may be
+required by specific element types at construction time
+(commonly e.g. uuid
).
+xmltag (str | None ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+classmethod from_model ( model , element )
+Instantiate a ModelObject from existing model elements.
+
+Parameters:
+
+
+Return type:
+ModelObject
+
+
+
+
+
+
+
+
+capellambse.model.common.element. attr_equal ( attr )
+
+Parameters:
+attr (str ) –
+
+Return type:
+Callable [[type [T ]], type [T ]]
+
+
+
+
+
+
+capellambse.model.common.properties module
+
+
+class capellambse.model.common.properties. AttributeProperty
+Bases: object
+A property that forwards access to the underlying XML element.
+
+
+NOT_OPTIONAL = <object object>
+
+
+
+
+__init__ ( attribute , * , returntype=<class 'str'> , optional=False , default=None , writable=True , __doc__=None )
+Create an AttributeProperty.
+
+Parameters:
+
+attribute (str ) – The attribute on the XML element to handle.
+returntype (Callable [ [ str ] , Any ] ) – The type to return the result as. Must accept a single
+str
as argument.
+optional (bool ) – If False (default) and the XML attribute does not exist, an
+AttributeError is raised. Otherwise a default value is
+returned.
+default (Any ) – A new-style format string to use as fallback value. You can
+access the object instance as self
and the XML element
+as xml
.
+writable (bool ) – Whether to allow modifying the XML attribute.
+__doc__ (str | None ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+attribute
+
+
+
+
+default
+
+
+
+
+returntype
+
+
+
+
+writable
+
+
+
+
+
+
+class capellambse.model.common.properties. BooleanAttributeProperty
+Bases: AttributeProperty
+An AttributeProperty that works with booleans.
+
+
+__init__ ( attribute , * , writable = True , __doc__ = None )
+Create an AttributeProperty.
+
+Parameters:
+
+attribute (str ) – The attribute on the XML element to handle.
+returntype – The type to return the result as. Must accept a single
+str
as argument.
+optional – If False (default) and the XML attribute does not exist, an
+AttributeError is raised. Otherwise a default value is
+returned.
+default – A new-style format string to use as fallback value. You can
+access the object instance as self
and the XML element
+as xml
.
+writable (bool ) – Whether to allow modifying the XML attribute.
+__doc__ (str | None ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+attribute
+
+
+
+
+default
+
+
+
+
+returntype
+
+
+
+
+writable
+
+
+
+
+
+
+class capellambse.model.common.properties. DatetimeAttributeProperty
+Bases: AttributeProperty
+An AttributeProperty that stores a datetime.
+The value stored in the XML will be formatted as required by
+Capella. This format is the ISO8601 format with millisecond
+precision, but no :
in the time zone specification.
+
+
+__init__ ( attribute , * , optional = True , writable = True , __doc__ = None )
+Create an AttributeProperty.
+
+Parameters:
+
+attribute (str ) – The attribute on the XML element to handle.
+returntype – The type to return the result as. Must accept a single
+str
as argument.
+optional (bool ) – If False (default) and the XML attribute does not exist, an
+AttributeError is raised. Otherwise a default value is
+returned.
+default – A new-style format string to use as fallback value. You can
+access the object instance as self
and the XML element
+as xml
.
+writable (bool ) – Whether to allow modifying the XML attribute.
+__doc__ (str | None ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+format
+
+
+
+
+re_get = re.compile('(?<=[+-]\\d\\d)(?=\\d\\d$)')
+
+
+
+
+re_set = re.compile('(?<=[+-]\\d\\d):(?=\\d\\d$)')
+
+
+
+
+
+
+class capellambse.model.common.properties. EnumAttributeProperty
+Bases: AttributeProperty
+An AttributeProperty whose values are determined by an Enum.
+This works in much the same way as the standard AttributeProperty,
+except that the returned and consumed values are not simple strings,
+but members of the Enum that was passed into the constructor.
+Usually it is expected that the enum members will be directly
+assigned to this property. However it is also possible to assign a
+str
instead. In this case, the string will be taken to be
+an enum member’s name. In both cases, the enum member’s value will
+be placed in the underlying XML attribute.
+If the XML attribute contains a value that does not correspond to
+any of the Enum’s members, a KeyError will be raised. If the
+attribute is completely missing from the XML and there was no
+default=
value set during construction, this property will
+return None
.
+
+
+__init__ ( attribute , enumcls , * args , default = None , ** kw )
+Create an EnumAttributeProperty.
+
+Parameters:
+
+attribute (str ) – The attribute on the XML element to handle.
+enumcls (type [ Enum ] ) – The enum.Enum
subclass to use. The class’ members’
+values are used as the possible values for the XML
+attribute.
+default (str | Enum | None ) – The default value to return if the attribute is not present
+in the XML. If None, an AttributeError will be raised
+instead.
+args (Any ) –
+kw (Any ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+enumcls
+
+
+
+
+
+
+class capellambse.model.common.properties. HTMLAttributeProperty
+Bases: AttributeProperty
+An AttributeProperty that gracefully handles HTML-in-XML.
+
+
+__init__ ( attribute , * , optional = False , writable = True , __doc__ = None )
+Create an AttributeProperty.
+
+Parameters:
+
+attribute (str ) – The attribute on the XML element to handle.
+returntype – The type to return the result as. Must accept a single
+str
as argument.
+optional (bool ) – If False (default) and the XML attribute does not exist, an
+AttributeError is raised. Otherwise a default value is
+returned.
+default – A new-style format string to use as fallback value. You can
+access the object instance as self
and the XML element
+as xml
.
+writable (bool ) – Whether to allow modifying the XML attribute.
+__doc__ (str | None ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+attribute
+
+
+
+
+default
+
+
+
+
+returntype
+
+
+
+
+writable
+
+
+
+
+
+
+class capellambse.model.common.properties. NumericAttributeProperty
+Bases: AttributeProperty
+Attribute property that handles (possibly infinite) numeric values.
+Positive infinity is stored in Capella XML as * . This class takes
+care of converting to and from that value when setting or retrieving
+the value.
+Note that there is currently no representation of negative infinity,
+which is why -inf
is rejected with a ValueError
.
+NaN
values are rejected with a ValueError as well.
+
+
+__init__ ( attribute , * , optional = False , default = None , allow_float = True , writable = True , __doc__ = None )
+Create an AttributeProperty.
+
+Parameters:
+
+attribute (str ) – The attribute on the XML element to handle.
+returntype – The type to return the result as. Must accept a single
+str
as argument.
+optional (bool ) – If False (default) and the XML attribute does not exist, an
+AttributeError is raised. Otherwise a default value is
+returned.
+default (int | float | None ) – A new-style format string to use as fallback value. You can
+access the object instance as self
and the XML element
+as xml
.
+writable (bool ) – Whether to allow modifying the XML attribute.
+allow_float (bool ) –
+__doc__ (str | None ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+attribute
+
+
+
+
+default
+
+
+
+
+returntype
+
+
+
+
+writable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.model.crosslayer.html b/code/capellambse.model.crosslayer.html
new file mode 100644
index 000000000..7cee7e66c
--- /dev/null
+++ b/code/capellambse.model.crosslayer.html
@@ -0,0 +1,2539 @@
+
+
+
+
+
+
+
+
+ capellambse.model.crosslayer package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.model.crosslayer package
+Utility classes that are used across all layers.
+
+
+
+class capellambse.model.crosslayer. BaseArchitectureLayer
+Bases: GenericElement
+A template architecture layer.
+
+
+all_classes
+The all classes of this BaseArchitectureLayer.
+
+
+
+
+all_collections
+The all collections of this BaseArchitectureLayer.
+
+
+
+
+all_complex_values
+The all complex values of this BaseArchitectureLayer.
+
+
+
+
+all_enumerations
+The all enumerations of this BaseArchitectureLayer.
+
+
+
+
+all_interfaces
+The all interfaces of this BaseArchitectureLayer.
+
+
+
+
+all_module_types
+The all module types of this BaseArchitectureLayer.
+
+
+
+
+all_relation_types
+The all relation types of this BaseArchitectureLayer.
+
+
+
+
+all_requirement_types
+The all requirement types of this BaseArchitectureLayer.
+
+
+
+
+all_requirements
+The all requirements of this BaseArchitectureLayer.
+
+
+
+
+all_unions
+The all unions of this BaseArchitectureLayer.
+
+
+
+
+data_package
+The data package of this BaseArchitectureLayer.
+
+
+
+
+interface_package
+The interface package of this BaseArchitectureLayer.
+
+
+
+
+requirement_modules
+The requirement modules of this BaseArchitectureLayer.
+
+
+
+
+requirement_types_folders
+The requirement types folders of this BaseArchitectureLayer.
+
+
+
+
+
+
+
+capellambse.model.crosslayer.capellacommon module
+Classes handling Mode/State-Machines and related content.
+
+
+class capellambse.model.crosslayer.capellacommon. AbstractStateMode
+Bases: GenericElement
+Common code for states and modes.
+
+
+realized_states
+The realized states of this AbstractStateMode.
+
+
+
+
+regions
+The regions of this AbstractStateMode.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. DeepHistoryPseudoState
+Bases: AbstractStateMode
+A deep history pseudo state.
+
+
+realizing_states
+The realizing states of this DeepHistoryPseudoState.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. FinalState
+Bases: AbstractStateMode
+A final state.
+
+
+realizing_states
+The realizing states of this FinalState.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. ForkPseudoState
+Bases: AbstractStateMode
+A fork pseudo state.
+
+
+realizing_states
+The realizing states of this ForkPseudoState.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. GenericTrace
+Bases: TraceableElement
+A trace between two elements.
+
+
+property name : str
+Return the name.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. InitialPseudoState
+Bases: AbstractStateMode
+An initial pseudo state.
+
+
+realizing_states
+The realizing states of this InitialPseudoState.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. JoinPseudoState
+Bases: AbstractStateMode
+A join pseudo state.
+
+
+realizing_states
+The realizing states of this JoinPseudoState.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. Mode
+Bases: AbstractStateMode
+A mode.
+
+
+realizing_states
+The realizing states of this Mode.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. Region
+Bases: GenericElement
+A region inside a state machine or state/mode.
+
+
+modes : Accessor
+The modes of this Region.
+
+
+
+
+states : Accessor
+The states of this Region.
+
+
+
+
+transitions : Accessor
+The transitions of this Region.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. ShallowHistoryPseudoState
+Bases: AbstractStateMode
+A shallow history pseudo state.
+
+
+realizing_states
+The realizing states of this ShallowHistoryPseudoState.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. State
+Bases: AbstractStateMode
+A state.
+
+
+do_activity
+The do activity of this State.
+
+
+
+
+entries
+The entries of this State.
+
+
+
+
+exits
+The exits of this State.
+
+
+
+
+functions : Accessor
+The functions of this State.
+
+
+
+
+realizing_states
+The realizing states of this State.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. StateMachine
+Bases: GenericElement
+A state machine.
+
+
+regions
+The regions of this StateMachine.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. StateTransition
+Bases: GenericElement
+A transition between State
s or Mode
s.
+
+
+destination
+The destination of this StateTransition.
+
+
+
+
+effects
+The effects of this StateTransition.
+
+
+
+
+guard
+The guard of this StateTransition.
+
+
+
+
+source
+The source of this StateTransition.
+
+
+
+
+triggers
+The triggers of this StateTransition.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacommon. TerminatePseudoState
+Bases: AbstractStateMode
+A terminate pseudo state.
+
+
+realizing_states
+The realizing states of this TerminatePseudoState.
+
+
+
+
+
+
+capellambse.model.crosslayer.capellacommon. cls
+alias of TerminatePseudoState
+
+
+
+
+capellambse.model.crosslayer.capellacore module
+
+
+class capellambse.model.crosslayer.capellacore. BooleanPropertyValue
+Bases: PropertyValue
+A boolean property value.
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. Constraint
+Bases: GenericElement
+A constraint.
+
+
+constrained_elements
+The constrained elements of this Constraint.
+
+
+
+
+specification
+The specification of this Constraint.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. EnumerationPropertyLiteral
+Bases: GenericElement
+A Literal for EnumerationPropertyType.
+
+
+
+
+class capellambse.model.crosslayer.capellacore. EnumerationPropertyType
+Bases: GenericElement
+An EnumerationPropertyType.
+
+
+literals
+The literals of this EnumerationPropertyType.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. EnumerationPropertyValue
+Bases: PropertyValue
+An enumeration property value.
+
+
+type
+The type of this EnumerationPropertyValue.
+
+
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+The value of this EnumerationPropertyValue.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. FloatPropertyValue
+Bases: PropertyValue
+A floating point property value.
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. Generalization
+Bases: GenericElement
+A Generalization.
+
+
+super : c.Accessor
+The super of this Generalization.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. IntegerPropertyValue
+Bases: PropertyValue
+An integer property value.
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. PropertyValue
+Bases: GenericElement
+Abstract base class for PropertyValues.
+
+
+enumerations
+The enumerations of this PropertyValue.
+
+
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. PropertyValueGroup
+Bases: GenericElement
+A group for PropertyValues.
+
+
+values
+The values of this PropertyValueGroup.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. PropertyValuePkg
+Bases: GenericElement
+A Package for PropertyValues.
+
+
+enumeration_property_types
+The enumeration property types of this PropertyValuePkg.
+
+
+
+
+groups
+The groups of this PropertyValuePkg.
+
+
+
+
+packages
+The packages of this PropertyValuePkg.
+
+
+
+
+values
+The values of this PropertyValuePkg.
+
+
+
+
+
+
+class capellambse.model.crosslayer.capellacore. StringPropertyValue
+Bases: PropertyValue
+A string property value.
+
+
+value : c.AttributeProperty | c.AttrProxyAccessor
+
+
+
+
+
+
+capellambse.model.crosslayer.cs module
+Implementation of objects and relations for Functional Analysis.
+Composite Structure objects inheritance tree (taxonomy):
+
+Composite Structure object-relations map (ontology):
+
+
+
+class capellambse.model.crosslayer.cs. Component
+Bases: GenericElement
+A template class for components.
+
+
+exchanges
+The exchanges of this Component.
+
+
+
+
+is_abstract
+Boolean flag for an abstract Component
+
+
+
+
+is_actor
+Boolean flag for an actor Component
+
+
+
+
+is_human
+Boolean flag for a human Component
+
+
+
+
+owner
+The owner of this Component.
+
+
+
+
+parts
+The parts of this Component.
+
+
+
+
+physical_links
+The physical links of this Component.
+
+
+
+
+physical_paths
+The physical paths of this Component.
+
+
+
+
+physical_ports
+The physical ports of this Component.
+
+
+
+
+ports
+The ports of this Component.
+
+
+
+
+realized_components
+The realized components of this Component.
+
+
+
+
+realizing_components
+The realizing components of this Component.
+
+
+
+
+related_exchanges
+The related exchanges of this Component.
+
+
+
+
+state_machines
+The state machines of this Component.
+
+
+
+
+
+
+class capellambse.model.crosslayer.cs. ComponentRealization
+Bases: GenericElement
+A realization that links to a component.
+
+
+
+
+class capellambse.model.crosslayer.cs. ExchangeItemAllocation
+Bases: GenericElement
+An allocation of an ExchangeItem to an Interface.
+
+
+item
+The item of this ExchangeItemAllocation.
+
+
+
+
+
+
+class capellambse.model.crosslayer.cs. Interface
+Bases: GenericElement
+An interface.
+
+
+exchange_item_allocations
+The exchange item allocations of this Interface.
+
+
+
+
+
+
+class capellambse.model.crosslayer.cs. InterfacePkg
+Bases: GenericElement
+A package that can hold interfaces and exchange items.
+
+
+exchange_items
+The exchange items of this InterfacePkg.
+
+
+
+
+interfaces
+The interfaces of this InterfacePkg.
+
+
+
+
+packages : Accessor
+The packages of this InterfacePkg.
+
+
+
+
+
+
+class capellambse.model.crosslayer.cs. Part
+Bases: GenericElement
+A representation of a physical component.
+
+
+deployed_parts : Accessor
+The deployed parts of this Part.
+
+
+
+
+type
+The type of this Part.
+
+
+
+
+
+
+class capellambse.model.crosslayer.cs. PhysicalLink
+Bases: PhysicalPort
+A physical link.
+
+
+ends
+The ends of this PhysicalLink.
+
+
+
+
+exchanges
+The exchanges of this PhysicalLink.
+
+
+
+
+linkEnds
+The linkEnds of this PhysicalLink.
+
+
+
+
+physical_paths : Accessor
+The physical paths of this PhysicalLink.
+
+
+
+
+source
+The source of this PhysicalLink.
+
+
+
+
+target
+The target of this PhysicalLink.
+
+
+
+
+
+
+class capellambse.model.crosslayer.cs. PhysicalPath
+Bases: GenericElement
+A physical path.
+
+
+exchanges
+The exchanges of this PhysicalPath.
+
+
+
+
+involved_items
+The involved items of this PhysicalPath.
+
+
+
+
+property involved_links : ElementList [ PhysicalLink ]
+
+
+
+
+
+
+class capellambse.model.crosslayer.cs. PhysicalPort
+Bases: GenericElement
+A physical port.
+
+
+links : Accessor
+The links of this PhysicalPort.
+
+
+
+
+owner
+The owner of this PhysicalPort.
+
+
+
+
+
+
+capellambse.model.crosslayer.fa module
+Implementation of objects and relations for Functional Analysis.
+Functional Analysis objects inheritance tree (taxonomy):
+
+Functional Analysis object-relations map (ontology):
+
+
+
+class capellambse.model.crosslayer.fa. AbstractExchange
+Bases: GenericElement
+Common code for Exchanges.
+
+
+source
+The source of this AbstractExchange.
+
+
+
+
+source_port
+The source port of this AbstractExchange.
+
+
+
+
+target
+The target of this AbstractExchange.
+
+
+
+
+target_port
+The target port of this AbstractExchange.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. AbstractFunction
+Bases: GenericElement
+An AbstractFunction.
+
+
+available_in_states
+The available in states of this AbstractFunction.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. ComponentExchange
+Bases: AbstractExchange
+A functional component exchange.
+
+
+allocated_exchange_items
+The allocated exchange items of this ComponentExchange.
+
+
+
+
+allocated_functional_exchanges
+The allocated functional exchanges of this ComponentExchange.
+
+
+
+
+allocating_physical_link
+The allocating physical link of this ComponentExchange.
+
+
+
+
+property allocating_physical_path : cs.PhysicalPath | None
+
+
+
+
+allocating_physical_paths
+The allocating physical paths of this ComponentExchange.
+
+
+
+
+property exchange_items : ElementList [ ExchangeItem ]
+
+
+
+
+func_exchanges
+The func exchanges of this ComponentExchange.
+
+
+
+
+kind
+
+
+
+
+property owner : cs.PhysicalLink | None
+
+
+
+
+realized_component_exchanges
+The realized component exchanges of this ComponentExchange.
+
+
+
+
+realizing_component_exchanges
+The realizing component exchanges of this ComponentExchange.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. ComponentPort
+Bases: GenericElement
+A component port.
+
+
+direction
+
+
+
+
+exchanges : c.Accessor
+The exchanges of this ComponentPort.
+
+
+
+
+owner
+The owner of this ComponentPort.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. ControlNode
+Bases: GenericElement
+A node with a specific control-kind.
+
+
+kind
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. Function
+Bases: AbstractFunction
+Common Code for Function’s.
+
+
+exchanges : c.Accessor [ 'FunctionalExchange' ]
+The exchanges of this Function.
+
+
+
+
+functions : c.Accessor
+
+
+
+
+inputs
+The inputs of this Function.
+
+
+
+
+property is_leaf
+
+
+
+
+kind
+
+
+
+
+outputs
+The outputs of this Function.
+
+
+
+
+packages : c.Accessor
+
+
+
+
+realized_functions
+The realized functions of this Function.
+
+
+
+
+realizing_functions
+The realizing functions of this Function.
+
+
+
+
+related_exchanges : c.Accessor [ 'FunctionalExchange' ]
+The related exchanges of this Function.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionInputPort
+Bases: FunctionPort
+A function input port.
+
+
+exchange_items
+The exchange items of this FunctionInputPort.
+
+
+
+
+exchanges : c.Accessor
+The exchanges of this FunctionInputPort.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionOutputPort
+Bases: FunctionPort
+A function output port.
+
+
+exchange_items
+The exchange items of this FunctionOutputPort.
+
+
+
+
+exchanges : c.Accessor
+The exchanges of this FunctionOutputPort.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionPort
+Bases: GenericElement
+A function port.
+
+
+exchanges : c.Accessor
+
+
+
+
+owner
+The owner of this FunctionPort.
+
+
+
+
+state_machines
+The state machines of this FunctionPort.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionRealization
+Bases: GenericElement
+A realization that links to a function.
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionalChain
+Bases: GenericElement
+A functional chain.
+
+
+control_nodes
+The control nodes of this FunctionalChain.
+
+
+
+
+property involved : MixedElementList
+
+
+
+
+involved_chains
+The involved chains of this FunctionalChain.
+
+
+
+
+involved_functions
+The involved functions of this FunctionalChain.
+
+
+
+
+involved_links
+The involved links of this FunctionalChain.
+
+
+
+
+involvements
+The involvements of this FunctionalChain.
+
+
+
+
+involving_chains : c.Accessor [ 'FunctionalChain' ]
+The involving chains of this FunctionalChain.
+
+
+
+
+kind
+
+
+
+
+realized_chains
+The realized chains of this FunctionalChain.
+
+
+
+
+realizing_chains : c.Accessor [ 'FunctionalChain' ]
+The realizing chains of this FunctionalChain.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionalChainInvolvement
+Bases: AbstractInvolvement
+Abstract class for FunctionalChainInvolvementLink/Function.
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionalChainInvolvementFunction
+Bases: FunctionalChainInvolvement
+An element linking a FunctionalChain to a Function.
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionalChainInvolvementLink
+Bases: FunctionalChainInvolvement
+An element linking a FunctionalChain to an Exchange.
+
+
+exchange_context
+The exchange context of this FunctionalChainInvolvementLink.
+
+
+
+
+exchanged_items
+The exchanged items of this FunctionalChainInvolvementLink.
+
+
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionalChainReference
+Bases: FunctionalChainInvolvement
+An element linking two related functional chains together.
+
+
+
+
+class capellambse.model.crosslayer.fa. FunctionalExchange
+Bases: AbstractExchange
+A functional exchange.
+
+
+allocating_component_exchange
+The allocating component exchange of this FunctionalExchange.
+
+
+
+
+exchange_items
+The exchange items of this FunctionalExchange.
+
+
+
+
+involving_functional_chains
+The involving functional chains of this FunctionalExchange.
+
+
+
+
+property owner : ComponentExchange | None
+
+
+
+
+realized_functional_exchanges
+The realized functional exchanges of this FunctionalExchange.
+
+
+
+
+realizing_functional_exchanges : c.Accessor [ 'FunctionalExchange' ]
+The realizing functional exchanges of this FunctionalExchange.
+
+
+
+
+
+
+capellambse.model.crosslayer.interaction module
+
+
+class capellambse.model.crosslayer.interaction. AbstractCapabilityExtend
+Bases: Exchange
+An AbstractCapabilityExtend.
+
+
+source
+The source of this AbstractCapabilityExtend.
+
+
+
+
+target
+The target of this AbstractCapabilityExtend.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. AbstractCapabilityGeneralization
+Bases: Exchange
+An AbstractCapabilityGeneralization.
+
+
+source
+The source of this AbstractCapabilityGeneralization.
+
+
+
+
+target
+The target of this AbstractCapabilityGeneralization.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. AbstractCapabilityInclude
+Bases: Exchange
+An AbstractCapabilityInclude.
+
+
+source
+The source of this AbstractCapabilityInclude.
+
+
+
+
+target
+The target of this AbstractCapabilityInclude.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. AbstractFunctionAbstractCapabilityInvolvement
+Bases: AbstractInvolvement
+An abstract CapabilityInvolvement linking to SystemFunctions.
+
+
+
+
+class capellambse.model.crosslayer.interaction. AbstractInvolvement
+Bases: GenericElement
+An abstract Involvement.
+
+
+involved
+The involved of this AbstractInvolvement.
+
+
+
+
+property name : str
+Return the name.
+
+
+
+
+source
+The source of this AbstractInvolvement.
+
+
+
+
+target
+The target of this AbstractInvolvement.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. CombinedFragment
+Bases: Execution
+A combined fragment.
+
+
+operands
+The operands of this CombinedFragment.
+
+
+
+
+operator
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. Event
+Bases: GenericElement
+Abstract super class of all events in a Scenario.
+
+
+
+
+class capellambse.model.crosslayer.interaction. EventOperation
+Bases: Event
+Abstract super class for events about operations.
+
+
+operation
+The operation of this EventOperation.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. EventReceiptOperation
+Bases: EventOperation
+An event-receipt operation.
+
+
+
+
+class capellambse.model.crosslayer.interaction. EventSentOperation
+Bases: EventOperation
+An event-sent operation.
+
+
+
+
+class capellambse.model.crosslayer.interaction. Exchange
+Bases: GenericElement
+An abstract Exchange.
+
+
+source
+The source of this Exchange.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. Execution
+Bases: GenericElement
+An execution.
+
+
+finish
+The finish of this Execution.
+
+
+
+
+start
+The start of this Execution.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. ExecutionEnd
+Bases: InteractionFragment
+An end for an execution.
+
+
+event
+The event of this ExecutionEnd.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. ExecutionEvent
+Bases: Event
+An execution event.
+
+
+
+
+class capellambse.model.crosslayer.interaction. FragmentEnd
+Bases: InteractionFragment
+An end for a fragment.
+
+
+
+
+class capellambse.model.crosslayer.interaction. InstanceRole
+Bases: GenericElement
+An instance role.
+
+
+instance
+The instance of this InstanceRole.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. InteractionFragment
+Bases: GenericElement
+Abstract super class of all interaction fragments in a Scenario.
+
+
+covered
+The covered of this InteractionFragment.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. InteractionOperand
+Bases: InteractionFragment
+An interaction-operand.
+
+
+guard
+The guard of this InteractionOperand.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. InteractionState
+Bases: InteractionFragment
+An interaction-state.
+
+
+function
+The function of this InteractionState.
+
+
+
+
+state
+The state of this InteractionState.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. MessageEnd
+Bases: InteractionFragment
+A message-end.
+
+
+event
+The event of this MessageEnd.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. Scenario
+Bases: GenericElement
+A scenario that holds instance roles.
+
+
+events
+The events of this Scenario.
+
+
+
+
+fragments
+The fragments of this Scenario.
+
+
+
+
+instance_roles
+The instance roles of this Scenario.
+
+
+
+
+messages
+The messages of this Scenario.
+
+
+
+
+postcondition
+The postcondition of this Scenario.
+
+
+
+
+precondition
+The precondition of this Scenario.
+
+
+
+
+time_lapses
+The time lapses of this Scenario.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. SequenceMessage
+Bases: GenericElement
+A sequence message.
+
+
+source
+The source of this SequenceMessage.
+
+
+
+
+target
+The target of this SequenceMessage.
+
+
+
+
+
+
+class capellambse.model.crosslayer.interaction. StateFragment
+Bases: Execution
+A state fragment.
+
+
+function
+The function of this StateFragment.
+
+
+
+
+
+
+capellambse.model.crosslayer.modellingcore module
+Abstract classes acting as templates for concrete classes.
+These base classes are used between different layers.
+
+
+class capellambse.model.crosslayer.modellingcore. TraceableElement
+Bases: GenericElement
+A template for traceable ModelObjects.
+
+
+source
+The source of this TraceableElement.
+
+
+
+
+target
+The target of this TraceableElement.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.model.crosslayer.information.html b/code/capellambse.model.crosslayer.information.html
new file mode 100644
index 000000000..9b14bb6aa
--- /dev/null
+++ b/code/capellambse.model.crosslayer.information.html
@@ -0,0 +1,1240 @@
+
+
+
+
+
+
+
+
+ capellambse.model.crosslayer.information package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.model.html b/code/capellambse.model.html
new file mode 100644
index 000000000..89af305e8
--- /dev/null
+++ b/code/capellambse.model.html
@@ -0,0 +1,3760 @@
+
+
+
+
+
+
+
+
+ capellambse.model package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.model package
+Implements a high-level interface to Capella projects.
+
+
+class capellambse.model. ElementList
+Bases: MutableSequence
, Generic
[T
]
+Provides access to elements without affecting the underlying model.
+
+
+__init__ ( model , elements , elemclass = None , * , mapkey = None , mapvalue = None )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+filter ( predicate )
+Filter this list with a custom predicate.
+The predicate may be the name of an attribute or a callable,
+which will be called on each list item. If the attribute value
+or the callable’s return value is truthy, the item is included
+in the resulting list.
+When specifying the name of an attribute, nested attributes can
+be chained using .
, like "parent.name"
(which would
+pick all elements whose parent
has a non-empty name
).
+
+Parameters:
+predicate (str | Callable [ [ T ] , bool ] ) –
+
+Return type:
+ElementList [T ]
+
+
+
+
+
+
+get ( key : str ) → T | None
+
+get ( key : str , default : U ) → T | U
+
+
+
+
+insert ( index , value )
+S.insert(index, value) – insert value before index
+
+Parameters:
+
+index (int ) –
+value (T ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+items ( )
+
+Return type:
+ElementListMapItemsView [T ]
+
+
+
+
+
+
+keys ( )
+
+Return type:
+ElementListMapKeyView
+
+
+
+
+
+
+map ( attr )
+Apply a function to each element in this list.
+If the argument is a string, it is interpreted as an attribute
+name, and the value of that attribute is returned for each
+element. Nested attribute names can be chained with .
.
+If the argument is a callable, it is called for each element,
+and the return value is included in the result. If the callable
+returns a sequence, the sequence is flattened into the result.
+Duplicate values and Nones are always filtered out.
+It is an error if a callable returns something that is not a
+model element or a flat sequence of model elements.
+
+Parameters:
+attr (str | _MapFunction [ T ] ) –
+
+Return type:
+ElementList [GenericElement ]
+
+
+
+
+
+
+values ( )
+
+Return type:
+ElementList [T ]
+
+
+
+
+
+
+
+
+class capellambse.model. GenericElement
+Bases: object
+Provides high-level access to a single model element.
+
+
+__init__ ( model , parent , xmltag = None , / , ** kw )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+applied_property_value_groups
+The applied property value groups of this GenericElement.
+
+
+
+
+applied_property_values
+The applied property values of this GenericElement.
+
+
+
+
+constraints : Accessor
+The constraints of this GenericElement.
+
+
+
+
+description
+
+
+
+
+property diagrams
+
+
+
+
+filtering_criteria
+The filtering criteria of this GenericElement.
+
+
+
+
+classmethod from_model ( model , element )
+Wrap an existing model object.
+
+Parameters:
+
+
+Returns:
+An instance of GenericElement (or a more appropriate
+subclass, if any) that wraps the given XML element.
+
+Return type:
+GenericElement
+
+
+
+
+
+
+name
+
+
+
+
+parent : ParentAccessor
+The parent of this GenericElement.
+
+
+
+
+property progress_status : AttributeProperty | str
+
+
+
+
+property_value_groups
+The property value groups of this GenericElement.
+
+
+
+
+property_values
+The property values of this GenericElement.
+
+
+
+
+pvmt
+The pvmt of this GenericElement.
+
+
+
+
+requirements
+The requirements of this GenericElement.
+
+
+
+
+summary
+
+
+
+
+traces
+The traces of this GenericElement.
+
+
+
+
+uuid
+
+
+
+
+property xtype
+
+
+
+
+
+
+class capellambse.model. MelodyModel
+Bases: object
+Provides high-level access to a model.
+This class builds upon the lower-level
+MelodyLoader
to provide an
+abstract, high-level interface for easy access to various model
+aspects.
+
+
+__init__ ( path , * , diagram_cache = None , jupyter_untrusted = None , fallback_render_aird = False , ** kwargs )
+Load a project.
+For complete information on which exact kwargs
are
+supported, consult the documentation of the used file handler.
+Refer to the “See Also” section for a collection of links.
+Below are some common parameter names and their usual meanings.
+Not all file handlers support all parameters.
+
+
Note
+
Passing in arguments that are not accepted by the selected
+file handler will result in an exception being raised.
+Similarly, leaving out arguments that are required by the
+file handler will also result in an exception.
+
+
+Parameters:
+
+path (str | PathLike ) –
Path or URL to the project. The following formats are
+accepted:
+
+A path to a local .aird
file.
+A path to a local directory (requires entrypoint
).
+An SCP-style short URL, which will be treated as referring
+to a Git repository.
+Example: git@github.com:DSD-DBS/py-capellambse.git
+
+A remote URL, with a protocol or prefix that indicates
+which file handler to invoke (requires entrypoint
).
+Some examples:
+
+git://git.example.com/model/coffeemaker.git
+git+https://git.example.com/model/coffeemaker.git
+git+ssh://git@git.example.com/model/coffeemaker.git
+
+
+
Note
+
Depending on the exact file handler, saving back
+to a remote location might fail with update_cache
+set to False
. See save()
for more details.
+
+
+
+
+entrypoint (str ) – Entrypoint from path to the main .aird
file.
+revision (str ) – The revision to use, if loading a model from a version
+control system like git. Defaults to the current HEAD. If
+the used VCS does not have a notion of “current HEAD”, this
+argument is mandatory.
+disable_cache (bool ) – Disable local caching of remote content.
+update_cache (bool ) – Update the local cache. Defaults to True
, but can be
+disabled to reuse the last cached state.
+identity_file (str | pathlib.Path ) – The identity file (private key) to use when connecting via
+SSH.
+known_hosts_file (str | pathlib.Path ) – The known_hosts
file to pass to SSH for verifying the
+server’s host key.
+username (str ) – The username to log in as remotely.
+password (str ) – The password to use for logging in. Will be ignored when
+identity_file
is passed as well.
+diagram_cache (str | PathLike | FileHandler | dict [ str , Any ] | None ) –
An optional place where to find pre-rendered, cached
+diagrams. When a diagram is found in this cache, it will be
+loaded from there instead of being rendered on access. Note
+that diagrams will only be loaded from there, but not be put
+back, i.e. to use it effectively, the cache has to be
+pre-populated.
+This argument accepts the following values:
+
+None
, in which case all diagrams will be rendered
+internally the first time they are used.
+A path to a local directory.
+A URL just like for the path
argument.
+A dictionary with the arguments to a
+FileHandler
. The
+dict’s path
key will be analyzed to determine the
+correct FileHandler class.
+An instance of
+FileHandler
, which
+will be used directly.
+
+
+
Warning
+
When using the diagram cache, always make sure
+that the cached diagrams actually match the model version
+that is being used. There is no way to check this
+automatically.
+
+The file names looked up in the cache built in the format
+uuid.ext
, where uuid
is the UUID of the diagram (as
+reported by diag_obj.uuid
) and ext
is the render
+format. Example:
+
+Diagram ID: _7FWu4KrxEeqOgqWuHJrXFA
+Render call: diag_obj.as_svg
or diag_obj.render("svg")
+Cache file name: _7FWu4KrxEeqOgqWuHJrXFA.svg
+
+This argument is **not* passed to the file handler.*
+
+diagram_cache_subdir (str ) –
A sub-directory prefix to prepend to diagram UUIDs before
+looking them up in the diagram_cache
.
+This argument is **not* passed to the file handler.*
+
+jupyter_untrusted (bool ) – If set to True, restricts or disables some features that are
+unavailable in an untrusted Jupyter environment. Currently
+this only disables the SVG format as rich display option for
+Ipython, which is needed to avoid rendering issues with
+Github’s Jupyter notebook viewer.
+fallback_render_aird (bool ) – If set to True, enable the internal engine to render
+diagrams that were not found in the pre-rendered cache.
+Defaults to False, which means an exception is raised
+instead. Ignored if no diagram_cache
was specified.
+kwargs (Any ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+
+by_uuid ( uuid )
+Search the entire model for an element with the given UUID.
+
+Parameters:
+uuid (str ) –
+
+Return type:
+GenericElement
+
+
+
+
+
+
+property description_badge : str
+Describe model contents distribution with an SVG badge.
+
+
+
+
+diagram_cache : FileHandler | None
+
+
+
+
+diagrams
+The diagrams of this MelodyModel.
+
+
+
+
+enumeration_property_types
+The enumeration property types of this MelodyModel.
+
+
+
+
+filtering_model
+The filtering model of this MelodyModel.
+
+
+
+
+find_references ( target , / )
+Search the model for references to the given object.
+
+Parameters:
+target (ModelObject | str ) – The target object to search for.
+
+Yields:
+tuple[ModelObject, str, int | None] – A 3-tuple containing the referencing model object, the
+attribute on that object, and an optional index. If the
+attribute contains a list of objects, the index shows the
+index into the list that was found. Otherwise the index is
+None.
+
+Return type:
+Iterator [tuple [ModelObject , str , int | None]]
+
+
+
+
+
+
+classmethod from_model ( model , element )
+
+Parameters:
+
+
+Return type:
+MelodyModel
+
+
+
+
+
+
+property info : ModelInfo
+
+
+
+
+la
+The la of this MelodyModel.
+
+
+
+
+name
+The name of this model.
+
+
+
+
+oa
+The oa of this MelodyModel.
+
+
+
+
+pa
+The pa of this MelodyModel.
+
+
+
+
+property parent : None
+
+
+
+
+property_value_packages
+The property value packages of this MelodyModel.
+
+
+
+
+property resources : dict [ str , FileHandler ]
+
+
+
+
+sa
+The sa of this MelodyModel.
+
+
+
+
+save ( ** kw )
+Save the model back to where it was loaded from.
+
+Parameters:
+kw (Any ) – Additional keyword arguments accepted by the file handler in
+use. Please see the respective documentation for more info.
+
+Return type:
+None
+
+
+
+Notes
+With a file handler that contacts a remote location (such as the
+GitFileHandler
+with non-local repositories), saving might fail if the local
+state has gone out of sync with the remote state. To avoid this,
+always leave the update_cache
parameter at its default value
+of True
if you intend to save changes.
+
+
+
+
+search ( * xtypes , below = None )
+Search for all elements with any of the given xsi:type
s.
+If only one xtype is given, the return type will be
+ElementList
,
+otherwise it will be
+MixedElementList
.
+If no xtypes
are given at all, this method will return an
+exhaustive list of all (semantic) model objects that have an
+xsi:type
set.
+
+Parameters:
+
+xtypes (str | type [ GenericElement ] ) – The xsi:type
s to search for, or the classes
+corresponding to them (or a mix of both).
+below (GenericElement | None ) – A model element to constrain the search. If given, only
+those elements will be returned that are (immediate or
+nested) children of this element. This option takes into
+account model fragmentation, but it does not treat link
+elements specially.
+
+
+Return type:
+ElementList
+
+
+
+
+
+
+update_diagram_cache ( capella_cli , image_format = 'svg' , * , create_index = False , force = None , background = True )
+Update the diagram cache if one has been specified.
+If a diagram_cache
has been specified while loading a
+Capella model it will be updated when this function is called.
+The diagram cache will be populated by executing the Capella
+function “Export representations as images” which is normally
+accessible via the context menu of an .aird
node in
+Capella’s project explorer. The export of diagrams happens with
+the help of Capella’s command line interface (CLI).
+The CLI of Capella must be specified by the caller. It is
+possible to work with a local installation or a Docker image of
+an individual Capella bundle.
+At the moment it is supported to run a Docker image using the
+container system Docker and the docker
executable must be in
+the PATH
environment variable.
+
+Parameters:
+
+capella_cli (str ) –
The Capella CLI to use when exporting diagrams from the
+given Capella model. The provided string can come with a
+"{VERSION}"
placeholder. If specified, this placeholder
+will be replaced by the x.y.z formatted version of Capella
+that has been used when the given Capella model was last
+saved. After consideration of the optional placeholder this
+function will first check if the value of capella_cli
+points to a local Capella executable (that can be an
+absolute path or an executable/ symbolic link that has been
+made available via the environment variable PATH
). If no
+executable can be found it is expected that capella_cli
+represents a Docker image name for an image that behaves
+like the Capella CLI. For the case of passing a Docker image
+name through capella_cli
this means it is assumed that
+something like the following
+ docker run --rm -it <capella_cli> -nosplash \
+ -consolelog -app APP -appid APPID
+
+
+will work.
+The parameter force
can be set to change the described
+behaviour and force the function to treat the
+capella_cli
as a local executable or a Docker image
+only.
+
+image_format (Literal [ 'bmp' , 'gif' , 'jpg' , 'png' , 'svg' ] ) – Format of the image file(s) for the exported diagram(s).
+This can be set to any value out of "bmp"
, "gif"
,
+"jpg"
, "png"
, or "svg"
.
+create_index (bool ) –
If True
, two index files index.json
and
+index.html
will be created. The JSON file consists of a
+list of dictionaries, each representing a diagram in the
+model. The dictionaries come with the keys
+
+uuid: The unique ID of the diagram
+name: Name of the diagram as it has been set in Capella
+type: The diagram type as it was created in Capella
+viewpoint: The source layer from where the representation
+is loaded from. It is Common
for layerless diagrams.
+success: A boolean stating if a diagram has been exported
+from Capella
+
+The HTML file shows a numbered list of diagram names which
+are hyperlinked to the diagram image file. Right beside a
+diagram’s name one can also see the diagram’s UUID in a
+discreet light gray and tiny font size. The HTML index also
+provides some meta data like a timestamp for the
+update of diagrams.
+
+force (Literal [ 'docker' , 'exe' ] | None ) – If the value of capella_cli
is ambiguous and can match
+both a local executable and a Docker image, this parameter
+can be used to bypass the auto-detection and force the
+choice. A value of "exe"
always interprets
+capella_cli
as local executable, "docker"
always
+interprets it as a docker image name. None
(the default)
+enables automatic detection.
+background (bool ) –
Add a white background to exported SVG images.
+Ignored if the image_format
is not "svg"
.
+
+
+
+Raises:
+
+
+Return type:
+None
+
+
+Examples
+Running a local installation of Capella
+All the following examples call the method
+update_diagram_cache()
on a model
+for which a diagram cache has been specified, example:
+>>> import capellambse
+>>> model = capellambse . MelodyModel (
+... "/path/to/model.aird" ,
+... diagram_cache = "/path/to/diagram_cache" ,
+... )
+
+
+Passing an executable/ symlink named capella
that is in the
+PATH
environment variable:
+>>> model . update_diagram_cache (
+... "capella" , "png" , True
+... )
+
+
+Passing an absolute path to a local installation of Capella that
+contains the Capella version:
+>>> model . update_diagram_cache (
+... "/Applications/Capella_ {VERSION} .app/Contents/MacOS/capella"
+... )
+
+
+Running a Capella container
+>>> model . update_diagram_cache (
+... "ghcr.io/dsd-dbs/capella-dockerimages/capella/base"
+... ": {VERSION} -selected-dropins-main"
+... )
+
+
+
+
+
+
+uuid
+The unique ID of the model’s root element.
+
+
+
+
+
+
+exception capellambse.model. NonUniqueMemberError
+Bases: ValueError
+Raised when a duplicate member is inserted into a list.
+
+
+property attr
+
+
+
+
+property parent
+
+
+
+
+property target
+
+
+
+
+
+
+
+capellambse.model.diagram module
+Classes that allow access to diagrams in the model.
+
+
+class capellambse.model.diagram. AbstractDiagram
+Bases: object
+Abstract superclass of model diagrams.
+
+
+__init__ ( model )
+
+Parameters:
+model (MelodyModel ) –
+
+Return type:
+None
+
+
+
+
+
+
+_allow_render : bool = True
+Allow this diagram to be rendered by the internal rendering engine.
+If this property is set to False, and a diagram cache was
+specified for the model, this diagram can only be loaded from
+the cache, and will never be rendered. Has no effect if there
+was no diagram cache specified.
+
+
+
+
+
+
+abstract _create_diagram ( params )
+Perform the actual rendering of the diagram.
+This method is called by render()
to perform the actual
+rendering of the diagram. It is passed the parameters that were
+passed to render()
as a dictionary.
+Subclasses override this method to implement their rendering
+logic. Do not call this method directly, use render()
+instead - it will take care of caching and properly converting
+the render output.
+
+Parameters:
+params (dict [ str , Any ] ) –
+
+Return type:
+Diagram
+
+
+
+
+
+
+filters : MutableSet [ str ]
+The filters that are activated for this diagram.
+
+
+
+
+invalidate_cache ( )
+Reset internal diagram cache.
+
+Return type:
+None
+
+
+
+
+
+
+name : str
+Human-readable name for this diagram.
+
+
+
+
+property nodes : MixedElementList
+Return a list of all nodes visible in this diagram.
+
+
+
+
+render ( fmt : None , / , ** params ) → Diagram
+
+render ( fmt : str , / , * , pretty_print : bool = False , ** params ) → Any
+Render the diagram in the given format.
+
+Parameters:
+
+fmt –
The output format to use.
+If None
, the Diagram
is returned
+without format conversion.
+
+pretty_print – Whether to pretty-print the output. Only applies to
+text-based formats. Ignored if the output format converter
+does not support pretty-printing.
+params – Additional render parameters. Which parameters are
+supported depends on the specific type of diagram.
+
+
+
+
+
+
+
+save ( file , fmt , / , * , pretty_print = False , ** params )
+Render the diagram and write it to a file.
+
+Parameters:
+
+file (str | PathLike | IO [ bytes ] | None ) –
The file to write the diagram to. Can be a filename, or a
+file-like object in binary mode.
+Text-based formats that render to a str
will always
+be encoded as UTF-8.
+If None is passed, and the selected format has a known
+filename extension, a filename will be generated from the
+diagram’s name and the extension.
+
+fmt (str ) – The output format to use.
+pretty_print (bool ) – Whether to pretty-print the output. Only applies to
+text-based formats. Ignored if the output format converter
+does not support pretty-printing.
+params – Additional render parameters to pass to the render()
+call.
+
+
+Return type:
+None
+
+
+
+
+
+
+target : GenericElement
+This diagram’s “target”.
+The target of a diagram is usually:
+
+The model element which is the direct parent of all visible
+nodes OR
+The only top-level element in the diagram OR
+The element which is considered to be the “element of interest”.
+
+
+
+
+
+uuid : str
+Unique ID of this diagram.
+
+
+
+
+
+
+class capellambse.model.diagram. ConfluenceSVGFormat
+Bases: object
+Convert the diagram to Confluence-style SVG.
+
+
+classmethod convert ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+str
+
+
+
+
+
+
+classmethod convert_pretty ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+str
+
+
+
+
+
+
+filename_extension = '.svg'
+
+
+
+
+classmethod from_cache ( cache )
+
+Parameters:
+cache (bytes ) –
+
+Return type:
+str
+
+
+
+
+
+
+postfix = ']]></ac:plain-text-body></ac:structured-macro>'
+
+
+
+
+prefix = '<ac:structured-macro ac:macro-id="ffefeaaf-baaf-4871-8223-161715abef07" ac:name="html" ac:schema-version="1"><ac:plain-text-body><![CDATA['
+
+
+
+
+
+
+class capellambse.model.diagram. Diagram
+Bases: AbstractDiagram
+Provides access to a single diagram.
+
+
+__init__ ( ** kw )
+
+Parameters:
+kw (Any ) –
+
+Return type:
+None
+
+
+
+
+
+
+property _allow_render : bool
+bool(x) -> bool
+Returns True when the argument x is true, False otherwise.
+The builtins True and False are the only two instances of the class bool.
+The class bool is a subclass of the class int, and cannot be subclassed.
+
+
+
+
+_create_diagram ( params )
+Perform the actual rendering of the diagram.
+This method is called by render()
to perform the actual
+rendering of the diagram. It is passed the parameters that were
+passed to render()
as a dictionary.
+Subclasses override this method to implement their rendering
+logic. Do not call this method directly, use render()
+instead - it will take care of caching and properly converting
+the render output.
+
+Parameters:
+params (dict [ str , Any ] ) –
+
+Return type:
+Diagram
+
+
+
+
+
+
+description
+
+
+
+
+property filters : MutableSet [ str ]
+Return a set of currently activated filters on this diagram.
+
+
+
+
+classmethod from_model ( model , descriptor )
+Wrap a diagram already defined in the Capella AIRD.
+
+Parameters:
+
+
+Return type:
+Diagram
+
+
+
+
+
+
+invalidate_cache ( )
+Reset internal diagram cache.
+
+Return type:
+None
+
+
+
+
+
+
+name : str
+Human-readable name for this diagram.
+
+
+
+
+property nodes : MixedElementList
+Return a list of all nodes visible in this diagram.
+
+
+
+
+property target : GenericElement
+
+
+
+
+property type : DiagramType
+Return the type of this diagram.
+
+
+
+
+uuid : str
+Unique ID of this diagram.
+
+
+
+
+property viewpoint : str
+
+
+
+
+property xtype
+
+
+
+
+
+
+class capellambse.model.diagram. DiagramAccessor
+Bases: Accessor
+Provides access to a list of diagrams below the specified viewpoint.
+
+
+__init__ ( viewpoint = None , * , cacheattr = None )
+
+Parameters:
+
+viewpoint (str | None ) –
+cacheattr (str | None ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+class capellambse.model.diagram. DiagramFormat
+Bases: Protocol
+
+
+__init__ ( * args , ** kwargs )
+
+
+
+
+classmethod convert ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+Any
+
+
+
+
+
+
+filename_extension : str
+
+
+
+
+classmethod from_cache ( cache )
+
+Parameters:
+cache (bytes ) –
+
+Return type:
+Any
+
+
+
+
+
+
+
+
+class capellambse.model.diagram. PNGFormat
+Bases: object
+Convert the diagram to PNG.
+
+
+static convert ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+bytes
+
+
+
+
+
+
+filename_extension = '.png'
+
+
+
+
+static from_cache ( cache )
+
+Parameters:
+cache (bytes ) –
+
+Return type:
+bytes
+
+
+
+
+
+
+mimetype = 'image/png'
+
+
+
+
+
+
+class capellambse.model.diagram. PrettyDiagramFormat
+Bases: DiagramFormat
, Protocol
+
+
+classmethod convert_pretty ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+Any
+
+
+
+
+
+
+
+
+class capellambse.model.diagram. SVGDataURIFormat
+Bases: object
+
+
+classmethod convert ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+str
+
+
+
+
+
+
+filename_extension = '.svg'
+
+
+
+
+classmethod from_cache ( cache )
+
+Parameters:
+cache (bytes ) –
+
+Return type:
+str
+
+
+
+
+
+
+preamble = 'data:image/svg+xml;base64,'
+
+
+
+
+
+
+class capellambse.model.diagram. SVGFormat
+Bases: object
+Convert the diagram to SVG.
+
+
+static convert ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+str
+
+
+
+
+
+
+static convert_pretty ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+str
+
+
+
+
+
+
+filename_extension = '.svg'
+
+
+
+
+static from_cache ( cache )
+
+Parameters:
+cache (bytes ) –
+
+Return type:
+str
+
+
+
+
+
+
+mimetype = 'image/svg+xml'
+
+
+
+
+
+
+class capellambse.model.diagram. SVGInHTMLIMGFormat
+Bases: object
+
+
+static convert ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+Markup
+
+
+
+
+
+
+filename_extension = '.svg'
+
+
+
+
+static from_cache ( cache )
+
+Parameters:
+cache (bytes ) –
+
+Return type:
+str
+
+
+
+
+
+
+mimetype = 'text/html'
+
+
+
+
+
+
+class capellambse.model.diagram. TerminalGraphicsFormat
+Bases: object
+The kitty terminal graphics protocol diagram format.
+This graphics format generates terminal escape codes that transfer
+PNG data to a TTY using the kitty graphics protocol .
+
+
+classmethod convert ( dg )
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+bytes
+
+
+
+
+
+
+filename_extension = '.png'
+
+
+
+
+static from_cache ( cache )
+
+Parameters:
+cache (bytes ) –
+
+Return type:
+bytes
+
+
+
+
+
+
+static is_supported ( )
+Return whether the used terminal supports graphics.
+This implementation checks whether stdin, stdout and stderr are
+connected to a terminal, and whether the $TERM
environment
+variable is set to a know-supportive value. Currently the only
+recognized value is xterm-kitty
.
+
+Return type:
+bool
+
+
+
+
+
+
+
+
+exception capellambse.model.diagram. UnknownOutputFormat
+Bases: ValueError
+An unknown output format was requested for the diagram.
+
+
+
+
+capellambse.model.diagram. convert_svgdiagram ( dg )
+Convert the diagram to a SVGDiagram.
+
+Parameters:
+dg (Diagram ) –
+
+Return type:
+SVGDiagram
+
+
+
+
+
+
+capellambse.model.modeltypes module
+Enumeration types used by the MelodyModel.
+
+
+class capellambse.model.modeltypes. AggregationKind
+Bases: _StringyEnumMixin
, Enum
+Aggregation kind.
+
+
+AGGREGATION = 3
+
+
+
+
+ASSOCIATION = 2
+
+
+
+
+COMPOSITION = 4
+
+
+
+
+UNSET = 1
+
+
+
+
+
+
+class capellambse.model.modeltypes. CollectionKind
+Bases: _StringyEnumMixin
, Enum
+
+
+ARRAY = 1
+
+
+
+
+SEQUENCE = 2
+
+
+
+
+
+
+class capellambse.model.modeltypes. ComponentExchangeKind
+Bases: _StringyEnumMixin
, Enum
+The KIND of a ComponentExchange.
+
+
+ASSEMBLY = 3
+
+
+
+
+DELEGATION = 2
+
+
+
+
+FLOW = 4
+
+
+
+
+UNSET = 1
+
+
+
+
+
+
+class capellambse.model.modeltypes. ControlNodeKind
+Bases: _StringyEnumMixin
, Enum
+ControlNode kind.
+
+
+AND = 2
+
+
+
+
+ITERATE = 3
+
+
+
+
+OR = 1
+
+
+
+
+
+
+class capellambse.model.modeltypes. DiagramType
+Bases: _StringyEnumMixin
, Enum
+The types of diagrams that Capella knows about.
+Extracted from:
+ $CAPELLA/eclipse/configuration/org.eclipse.osgi/635/0/.cp/description
+
+
+with:
+grep '<ownedRepresentations' * ( . ) | grep -- color = always - P '(?<=name=").*?(?=")'
+
+
+
+
+CC = 'Contextual Capability'
+
+
+
+
+CDB = 'Class Diagram Blank'
+
+
+
+
+CDI = 'Contextual Component Detailed Interfaces'
+
+
+
+
+CEI = 'Contextual Component External Interfaces'
+
+
+
+
+CIBD = 'Configuration Items Breakdown'
+
+
+
+
+CII = 'Contextual Component Internal Interfaces'
+
+
+
+
+CM = 'Contextual Mission'
+
+
+
+
+COC = 'Contextual Operational Capability'
+
+
+
+
+CRB = 'Capability Realization Blank'
+
+
+
+
+CRI = 'Contextual Capability Realization Involvement'
+
+
+
+
+CRR = 'Capability Realization Refinement'
+
+
+
+
+CSA = 'Contextual System Actors'
+
+
+
+
+EAB = 'EPBS Architecture Blank'
+
+
+
+
+ES = 'Component Exchanges Scenario'
+
+
+
+
+FS = 'Functional Scenario'
+
+
+
+
+ID = 'Interface Delegations'
+
+
+
+
+IDB = 'Interfaces Diagram Blank'
+
+
+
+
+IS = 'Component Interfaces Scenario'
+
+
+
+
+LAB = 'Logical Architecture Blank'
+
+
+
+
+LCBD = 'Logical Component Breakdown'
+
+
+
+
+LDFB = 'Logical Data Flow Blank'
+
+
+
+
+LFBD = 'Logical Function Breakdown'
+
+
+
+
+LFCD = 'Functional Chain Description'
+
+
+
+
+MB = 'Missions Blank'
+
+
+
+
+MCB = 'Missions Capabilities Blank'
+
+
+
+
+MSM = 'Mode State Machine'
+
+
+
+
+OAB = 'Operational Entity Blank'
+
+
+
+
+OABD = 'Operational Activity Breakdown'
+
+
+
+
+OAIB = 'Operational Activity Interaction Blank'
+
+
+
+
+OAS = 'Activity Interaction Scenario'
+
+
+
+
+OCB = 'Operational Capabilities Blank'
+
+
+
+
+OEBD = 'Operational Entity Breakdown'
+
+
+
+
+OES = 'Operational Interaction Scenario'
+
+
+
+
+OPD = 'Operational Process Description'
+
+
+
+
+ORB = 'Operational Role Blank'
+
+
+
+
+PAB = 'Physical Architecture Blank'
+
+
+
+
+PCBD = 'Physical Component Breakdown'
+
+
+
+
+PD = 'Package Dependencies'
+
+
+
+
+PDFB = 'Physical Data Flow Blank'
+
+
+
+
+PFBD = 'Physical Function Breakdown'
+
+
+
+
+PFCD = 'Functional Chain Description'
+
+
+
+
+PPD = 'Physical Path Description'
+
+
+
+
+SAB = 'System Architecture Blank'
+
+
+
+
+SDFB = 'System Data Flow Blank'
+
+
+
+
+SFBD = 'System Function Breakdown'
+
+
+
+
+SFCD = 'Functional Chain Description'
+
+
+
+
+UNKNOWN = '(Unknown Diagram Type)'
+
+
+
+
+
+
+class capellambse.model.modeltypes. ExchangeItemType
+Bases: _StringyEnumMixin
, Enum
+The “TYPE” of ExchangeItem
s.
+
+
+EVENT = 2
+
+
+
+
+FLOW = 3
+
+
+
+
+OPERATION = 4
+
+
+
+
+SHARED_DATA = 5
+
+
+
+
+UNSET = 1
+
+
+
+
+
+
+class capellambse.model.modeltypes. FPortDir
+Bases: _StringyEnumMixin
, Flag
+Direction of component and function ports.
+
+
+IN = 1
+
+
+
+
+INOUT = 3
+
+
+
+
+OUT = 2
+
+
+
+
+
+
+class capellambse.model.modeltypes. FunctionKind
+Bases: _StringyEnumMixin
, Enum
+The KIND of a Function.
+
+
+DUPLICATE = 2
+
+
+
+
+FUNCTION = 1
+
+
+
+
+GATHER = 3
+
+
+
+
+ROUTE = 6
+
+
+
+
+SELECT = 4
+
+
+
+
+SPLIT = 5
+
+
+
+
+
+
+class capellambse.model.modeltypes. FunctionalChainKind
+Bases: _StringyEnumMixin
, Enum
+The kind of a Functional Chain.
+
+
+COMPOSITE = 2
+
+
+
+
+FRAGMENT = 3
+
+
+
+
+SIMPLE = 1
+
+
+
+
+
+
+class capellambse.model.modeltypes. NumericTypeKind
+Bases: _StringyEnumMixin
, Enum
+Specifies the kind of this numeric data type.
+
+
+FLOAT = 2
+
+
+
+
+INTEGER = 1
+
+
+
+
+
+
+class capellambse.model.modeltypes. PhysicalComponentKind
+Bases: _StringyEnumMixin
, Enum
+The “KIND” of PhysicalComponent
s.
+
+
+DATA = 5
+
+
+
+
+FACILITIES = 9
+
+
+
+
+FIRMWARE = 12
+
+
+
+
+HARDWARE = 2
+
+
+
+
+HARDWARE_COMPUTER = 6
+
+
+
+
+MATERIALS = 10
+
+
+
+
+PERSON = 13
+
+
+
+
+PROCESSES = 3
+
+
+
+
+SERVICES = 7
+
+
+
+
+SOFTWARE = 11
+
+
+
+
+SOFTWARE_APPLICATION = 14
+
+
+
+
+SOFTWARE_DEPLOYMENT_UNIT = 4
+
+
+
+
+SOFTWARE_EXECUTION_UNIT = 8
+
+
+
+
+UNSET = 1
+
+
+
+
+
+
+class capellambse.model.modeltypes. PhysicalComponentNature
+Bases: _StringyEnumMixin
, Enum
+The “NATURE” of PhysicalComponent
s.
+
+
+BEHAVIOR = 3
+
+
+
+
+NODE = 2
+
+
+
+
+UNSET = 1
+
+
+
+
+
+
+class capellambse.model.modeltypes. ScenarioKind
+Bases: _StringyEnumMixin
, Enum
+
+
+DATA_FLOW = 2
+
+
+
+
+FUNCTIONAL = 3
+
+
+
+
+INTERACTION = 4
+
+
+
+
+INTERFACE = 5
+
+
+
+
+UNSET = 1
+
+
+
+
+
+
+class capellambse.model.modeltypes. UnionKind
+Bases: _StringyEnumMixin
, Enum
+
+
+UNION = 1
+
+
+
+
+VARIANT = 2
+
+
+
+
+
+
+class capellambse.model.modeltypes. VisibilityKind
+Bases: _StringyEnumMixin
, Enum
+Visibility kind.
+
+
+PACKAGE = 5
+
+
+
+
+PRIVATE = 4
+
+
+
+
+PROTECTED = 3
+
+
+
+
+PUBLIC = 2
+
+
+
+
+UNSET = 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.model.layers.html b/code/capellambse.model.layers.html
new file mode 100644
index 000000000..8d2129160
--- /dev/null
+++ b/code/capellambse.model.layers.html
@@ -0,0 +1,2100 @@
+
+
+
+
+
+
+
+
+ capellambse.model.layers package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.model.layers package
+
+
+capellambse.model.layers.ctx module
+Tools for the System Analysis layer.
+This is normally the place to declare data used in the model for e.g.
+functions, actors etc. which is best presented in a glossary document.
+
+
+
+class capellambse.model.layers.ctx. Capability
+Bases: GenericElement
+A capability.
+
+
+component_involvements
+The component involvements of this Capability.
+
+
+
+
+extended_by
+The extended by of this Capability.
+
+
+
+
+extends
+The extends of this Capability.
+
+
+
+
+generalized_by
+The generalized by of this Capability.
+
+
+
+
+generalizes
+The generalizes of this Capability.
+
+
+
+
+included_by
+The included by of this Capability.
+
+
+
+
+includes
+The includes of this Capability.
+
+
+
+
+incoming_exploitations
+The incoming exploitations of this Capability.
+
+
+
+
+involved_chains
+The involved chains of this Capability.
+
+
+
+
+involved_components
+The involved components of this Capability.
+
+
+
+
+involved_functions
+The involved functions of this Capability.
+
+
+
+
+owned_chains
+The owned chains of this Capability.
+
+
+
+
+packages : Accessor
+
+
+
+
+postcondition
+The postcondition of this Capability.
+
+
+
+
+precondition
+The precondition of this Capability.
+
+
+
+
+realized_capabilities
+The realized capabilities of this Capability.
+
+
+
+
+realizing_capabilities
+The realizing capabilities of this Capability.
+
+
+
+
+scenarios
+The scenarios of this Capability.
+
+
+
+
+states
+The states of this Capability.
+
+
+
+
+
+
+class capellambse.model.layers.ctx. CapabilityExploitation
+Bases: GenericElement
+A CapabilityExploitation.
+
+
+capability
+The capability of this CapabilityExploitation.
+
+
+
+
+property name : str
+Return the name.
+
+
+
+
+
+
+class capellambse.model.layers.ctx. CapabilityInvolvement
+Bases: AbstractInvolvement
+A CapabilityInvolvement.
+
+
+
+
+class capellambse.model.layers.ctx. CapabilityPkg
+Bases: GenericElement
+A capability package that can hold capabilities.
+
+
+capabilities
+The capabilities of this CapabilityPkg.
+
+
+
+
+packages : Accessor
+
+
+
+
+
+
+class capellambse.model.layers.ctx. Mission
+Bases: GenericElement
+A mission.
+
+
+exploitations
+The exploitations of this Mission.
+
+
+
+
+exploits
+The exploits of this Mission.
+
+
+
+
+incoming_involvements
+The incoming involvements of this Mission.
+
+
+
+
+involvements
+The involvements of this Mission.
+
+
+
+
+
+
+class capellambse.model.layers.ctx. MissionInvolvement
+Bases: AbstractInvolvement
+A MissionInvolvement.
+
+
+
+
+class capellambse.model.layers.ctx. MissionPkg
+Bases: GenericElement
+A system mission package that can hold missions.
+
+
+missions
+The missions of this MissionPkg.
+
+
+
+
+packages : Accessor
+The packages of this MissionPkg.
+
+
+
+
+
+
+class capellambse.model.layers.ctx. SystemAnalysis
+Bases: BaseArchitectureLayer
+Provides access to the SystemAnalysis layer of the model.
+
+
+actor_exchanges
+The actor exchanges of this SystemAnalysis.
+
+
+
+
+property all_actors
+
+
+
+
+all_capabilities
+The all capabilities of this SystemAnalysis.
+
+
+
+
+all_capability_exploitations
+The all capability exploitations of this SystemAnalysis.
+
+
+
+
+all_component_exchanges
+The all component exchanges of this SystemAnalysis.
+
+
+
+
+all_components
+The all components of this SystemAnalysis.
+
+
+
+
+all_function_exchanges
+The all function exchanges of this SystemAnalysis.
+
+
+
+
+property all_functional_chains
+
+
+
+
+all_functions
+The all functions of this SystemAnalysis.
+
+
+
+
+all_missions
+The all missions of this SystemAnalysis.
+
+
+
+
+capability_package
+The capability package of this SystemAnalysis.
+
+
+
+
+component_exchanges
+The component exchanges of this SystemAnalysis.
+
+
+
+
+component_package
+The component package of this SystemAnalysis.
+
+
+
+
+diagrams : accessors.Accessor [ capellambse.model.diagram.Diagram ]
+The diagrams of this SystemAnalysis.
+
+
+
+
+function_package
+The function package of this SystemAnalysis.
+
+
+
+
+mission_package
+The mission package of this SystemAnalysis.
+
+
+
+
+root_component
+The root component of this SystemAnalysis.
+
+
+
+
+root_function
+The root function of this SystemAnalysis.
+
+
+
+
+
+
+class capellambse.model.layers.ctx. SystemComponent
+Bases: Component
+A system component.
+
+
+allocated_functions
+The allocated functions of this SystemComponent.
+
+
+
+
+components
+The components of this SystemComponent.
+
+
+
+
+realized_entities
+The realized entities of this SystemComponent.
+
+
+
+
+realized_operational_entities
+The realized operational entities of this SystemComponent.
+
+
+
+
+realizing_logical_components
+The realizing logical components of this SystemComponent.
+
+
+
+
+
+
+class capellambse.model.layers.ctx. SystemComponentPkg
+Bases: GenericElement
+A system component package.
+
+
+components
+The components of this SystemComponentPkg.
+
+
+
+
+packages : Accessor
+The packages of this SystemComponentPkg.
+
+
+
+
+state_machines
+The state machines of this SystemComponentPkg.
+
+
+
+
+
+
+class capellambse.model.layers.ctx. SystemFunction
+Bases: Function
+A system function.
+
+
+functions : c.Accessor
+The functions of this SystemFunction.
+
+
+
+
+involved_in
+The involved in of this SystemFunction.
+
+
+
+
+owner : Accessor
+The owner of this SystemFunction.
+
+
+
+
+packages : c.Accessor
+The packages of this SystemFunction.
+
+
+
+
+realized_operational_activities
+The realized operational activities of this SystemFunction.
+
+
+
+
+realizing_logical_functions
+The realizing logical functions of this SystemFunction.
+
+
+
+
+
+
+class capellambse.model.layers.ctx. SystemFunctionPkg
+Bases: GenericElement
+A function package that can hold functions.
+
+
+functions
+The functions of this SystemFunctionPkg.
+
+
+
+
+packages : Accessor
+The packages of this SystemFunctionPkg.
+
+
+
+
+
+
+capellambse.model.layers.la module
+Tools for the Logical Architecture layer.
+
+
+
+class capellambse.model.layers.la. CapabilityRealization
+Bases: GenericElement
+A capability.
+
+
+involved_chains
+The involved chains of this CapabilityRealization.
+
+
+
+
+involved_components
+The involved components of this CapabilityRealization.
+
+
+
+
+involved_functions
+The involved functions of this CapabilityRealization.
+
+
+
+
+owned_chains
+The owned chains of this CapabilityRealization.
+
+
+
+
+packages : c.Accessor
+
+
+
+
+postcondition
+The postcondition of this CapabilityRealization.
+
+
+
+
+precondition
+The precondition of this CapabilityRealization.
+
+
+
+
+realized_capabilities
+The realized capabilities of this CapabilityRealization.
+
+
+
+
+scenarios
+The scenarios of this CapabilityRealization.
+
+
+
+
+states
+The states of this CapabilityRealization.
+
+
+
+
+
+
+class capellambse.model.layers.la. CapabilityRealizationPkg
+Bases: GenericElement
+A capability package that can hold capabilities.
+
+
+capabilities
+The capabilities of this CapabilityRealizationPkg.
+
+
+
+
+packages : c.Accessor
+
+
+
+
+
+
+class capellambse.model.layers.la. LogicalArchitecture
+Bases: BaseArchitectureLayer
+Provides access to the LogicalArchitecture layer of the model.
+
+
+actor_exchanges
+The actor exchanges of this LogicalArchitecture.
+
+
+
+
+property all_actors
+
+
+
+
+all_capabilities
+The all capabilities of this LogicalArchitecture.
+
+
+
+
+all_component_exchanges
+The all component exchanges of this LogicalArchitecture.
+
+
+
+
+all_components
+The all components of this LogicalArchitecture.
+
+
+
+
+all_function_exchanges
+The all function exchanges of this LogicalArchitecture.
+
+
+
+
+property all_functional_chains
+
+
+
+
+all_functions
+The all functions of this LogicalArchitecture.
+
+
+
+
+capability_package
+The capability package of this LogicalArchitecture.
+
+
+
+
+component_exchanges
+The component exchanges of this LogicalArchitecture.
+
+
+
+
+component_package
+The component package of this LogicalArchitecture.
+
+
+
+
+diagrams : accessors.Accessor [ capellambse.model.diagram.Diagram ]
+The diagrams of this LogicalArchitecture.
+
+
+
+
+function_package
+The function package of this LogicalArchitecture.
+
+
+
+
+root_component
+The root component of this LogicalArchitecture.
+
+
+
+
+root_function
+The root function of this LogicalArchitecture.
+
+
+
+
+
+
+class capellambse.model.layers.la. LogicalComponent
+Bases: Component
+A logical component on the Logical Architecture layer.
+
+
+allocated_functions
+The allocated functions of this LogicalComponent.
+
+
+
+
+components : c.Accessor
+The components of this LogicalComponent.
+
+
+
+
+functions
+The functions of this LogicalComponent.
+
+
+
+
+realized_system_components
+The realized system components of this LogicalComponent.
+
+
+
+
+realizing_physical_components
+The realizing physical components of this LogicalComponent.
+
+
+
+
+
+
+class capellambse.model.layers.la. LogicalComponentPkg
+Bases: GenericElement
+A logical component package.
+
+
+components
+The components of this LogicalComponentPkg.
+
+
+
+
+exchanges
+The exchanges of this LogicalComponentPkg.
+
+
+
+
+packages : c.Accessor
+The packages of this LogicalComponentPkg.
+
+
+
+
+state_machines
+The state machines of this LogicalComponentPkg.
+
+
+
+
+
+
+class capellambse.model.layers.la. LogicalFunction
+Bases: Function
+A logical function on the Logical Architecture layer.
+
+
+functions : c.Accessor
+The functions of this LogicalFunction.
+
+
+
+
+involved_in
+The involved in of this LogicalFunction.
+
+
+
+
+owner : c.Accessor [ LogicalComponent ]
+The owner of this LogicalFunction.
+
+
+
+
+packages : c.Accessor
+The packages of this LogicalFunction.
+
+
+
+
+realized_system_functions
+The realized system functions of this LogicalFunction.
+
+
+
+
+realizing_physical_functions
+The realizing physical functions of this LogicalFunction.
+
+
+
+
+
+
+class capellambse.model.layers.la. LogicalFunctionPkg
+Bases: GenericElement
+A logical function package.
+
+
+functions
+The functions of this LogicalFunctionPkg.
+
+
+
+
+packages : c.Accessor
+The packages of this LogicalFunctionPkg.
+
+
+
+
+
+
+capellambse.model.layers.oa module
+Tools for the Operational Analysis layer.
+
+
+
+class capellambse.model.layers.oa. AbstractEntity
+Bases: Component
+Common code for Entities.
+
+
+activities
+The activities of this AbstractEntity.
+
+
+
+
+capabilities
+The capabilities of this AbstractEntity.
+
+
+
+
+
+
+class capellambse.model.layers.oa. CommunicationMean
+Bases: AbstractExchange
+An operational entity exchange.
+
+
+allocated_exchange_items
+The allocated exchange items of this CommunicationMean.
+
+
+
+
+allocated_interactions
+The allocated interactions of this CommunicationMean.
+
+
+
+
+property exchange_items : ElementList [ ExchangeItem ]
+
+
+
+
+
+
+class capellambse.model.layers.oa. Entity
+Bases: AbstractEntity
+An Entity in the OperationalAnalysis layer.
+
+
+entities : c.Accessor
+The entities of this Entity.
+
+
+
+
+exchanges
+The exchanges of this Entity.
+
+
+
+
+property inputs : ElementList [ CommunicationMean ]
+
+
+
+
+property outputs : ElementList [ CommunicationMean ]
+
+
+
+
+realizing_system_components
+The realizing system components of this Entity.
+
+
+
+
+related_exchanges
+The related exchanges of this Entity.
+
+
+
+
+
+
+class capellambse.model.layers.oa. EntityOperationalCapabilityInvolvement
+Bases: AbstractInvolvement
+An EntityOperationalCapabilityInvolvement.
+
+
+
+
+class capellambse.model.layers.oa. EntityPkg
+Bases: GenericElement
+A package that holds operational entities.
+
+
+entities
+The entities of this EntityPkg.
+
+
+
+
+exchanges
+The exchanges of this EntityPkg.
+
+
+
+
+packages : c.Accessor
+The packages of this EntityPkg.
+
+
+
+
+state_machines
+The state machines of this EntityPkg.
+
+
+
+
+
+
+class capellambse.model.layers.oa. OperationalActivity
+Bases: AbstractFunction
+An operational activity.
+
+
+activities
+The activities of this OperationalActivity.
+
+
+
+
+exchanges
+The exchanges of this OperationalActivity.
+
+
+
+
+property inputs : ElementList [ FunctionalExchange ]
+
+
+
+
+property outputs : ElementList [ FunctionalExchange ]
+
+
+
+
+owner : c.Accessor [ Entity ]
+The owner of this OperationalActivity.
+
+
+
+
+owning_entity
+The owning entity of this OperationalActivity.
+
+
+
+
+packages
+The packages of this OperationalActivity.
+
+
+
+
+realizing_system_functions
+The realizing system functions of this OperationalActivity.
+
+
+
+
+property related_exchanges : ElementList [ FunctionalExchange ]
+
+
+
+
+
+
+class capellambse.model.layers.oa. OperationalActivityPkg
+Bases: GenericElement
+A package that holds operational entities.
+
+
+activities
+The activities of this OperationalActivityPkg.
+
+
+
+
+packages : c.Accessor
+The packages of this OperationalActivityPkg.
+
+
+
+
+
+
+class capellambse.model.layers.oa. OperationalAnalysis
+Bases: BaseArchitectureLayer
+Provides access to the OperationalAnalysis layer of the model.
+
+
+activity_package
+The activity package of this OperationalAnalysis.
+
+
+
+
+all_activities
+The all activities of this OperationalAnalysis.
+
+
+
+
+all_activity_exchanges
+The all activity exchanges of this OperationalAnalysis.
+
+
+
+
+property all_actors
+
+
+
+
+all_capabilities
+The all capabilities of this OperationalAnalysis.
+
+
+
+
+all_entities
+The all entities of this OperationalAnalysis.
+
+
+
+
+all_entity_exchanges
+The all entity exchanges of this OperationalAnalysis.
+
+
+
+
+property all_operational_processes
+
+
+
+
+all_processes
+The all processes of this OperationalAnalysis.
+
+
+
+
+capability_package
+The capability package of this OperationalAnalysis.
+
+
+
+
+diagrams : accessors.Accessor [ capellambse.model.diagram.Diagram ]
+The diagrams of this OperationalAnalysis.
+
+
+
+
+entity_package
+The entity package of this OperationalAnalysis.
+
+
+
+
+root_activity
+The root activity of this OperationalAnalysis.
+
+
+
+
+root_entity
+The root entity of this OperationalAnalysis.
+
+
+
+
+
+
+class capellambse.model.layers.oa. OperationalCapability
+Bases: GenericElement
+A capability in the OperationalAnalysis layer.
+
+
+entity_involvements
+The entity involvements of this OperationalCapability.
+
+
+
+
+extended_by
+The extended by of this OperationalCapability.
+
+
+
+
+extends
+The extends of this OperationalCapability.
+
+
+
+
+generalized_by
+The generalized by of this OperationalCapability.
+
+
+
+
+generalizes
+The generalizes of this OperationalCapability.
+
+
+
+
+included_by
+The included by of this OperationalCapability.
+
+
+
+
+includes
+The includes of this OperationalCapability.
+
+
+
+
+involved_activities
+The involved activities of this OperationalCapability.
+
+
+
+
+involved_entities
+The involved entities of this OperationalCapability.
+
+
+
+
+involved_processes
+The involved processes of this OperationalCapability.
+
+
+
+
+owned_processes
+The owned processes of this OperationalCapability.
+
+
+
+
+packages : c.Accessor
+
+
+
+
+postcondition
+The postcondition of this OperationalCapability.
+
+
+
+
+precondition
+The precondition of this OperationalCapability.
+
+
+
+
+realizing_capabilities
+The realizing capabilities of this OperationalCapability.
+
+
+
+
+scenarios
+The scenarios of this OperationalCapability.
+
+
+
+
+states
+The states of this OperationalCapability.
+
+
+
+
+
+
+class capellambse.model.layers.oa. OperationalCapabilityPkg
+Bases: GenericElement
+A package that holds operational capabilities.
+
+
+capabilities
+The capabilities of this OperationalCapabilityPkg.
+
+
+
+
+packages : c.Accessor
+The packages of this OperationalCapabilityPkg.
+
+
+
+
+
+
+class capellambse.model.layers.oa. OperationalProcess
+Bases: FunctionalChain
+An operational process.
+
+
+
+
+capellambse.model.layers.pa module
+Tools for the Physical Architecture layer.
+
+
+
+class capellambse.model.layers.pa. PhysicalArchitecture
+Bases: BaseArchitectureLayer
+Provides access to the Physical Architecture layer of the model.
+
+
+property all_actors
+
+
+
+
+all_capabilities
+The all capabilities of this PhysicalArchitecture.
+
+
+
+
+all_component_exchanges
+The all component exchanges of this PhysicalArchitecture.
+
+
+
+
+all_components
+The all components of this PhysicalArchitecture.
+
+
+
+
+all_function_exchanges
+The all function exchanges of this PhysicalArchitecture.
+
+
+
+
+property all_functional_chains
+
+
+
+
+all_functions
+The all functions of this PhysicalArchitecture.
+
+
+
+
+all_physical_exchanges
+The all physical exchanges of this PhysicalArchitecture.
+
+
+
+
+all_physical_links
+The all physical links of this PhysicalArchitecture.
+
+
+
+
+all_physical_paths
+The all physical paths of this PhysicalArchitecture.
+
+
+
+
+capability_package
+The capability package of this PhysicalArchitecture.
+
+
+
+
+component_package
+The component package of this PhysicalArchitecture.
+
+
+
+
+diagrams : accessors.Accessor [ capellambse.model.diagram.Diagram ]
+The diagrams of this PhysicalArchitecture.
+
+
+
+
+function_package
+The function package of this PhysicalArchitecture.
+
+
+
+
+root_component
+The root component of this PhysicalArchitecture.
+
+
+
+
+root_function
+The root function of this PhysicalArchitecture.
+
+
+
+
+
+
+class capellambse.model.layers.pa. PhysicalComponent
+Bases: Component
+A physical component on the Physical Architecture layer.
+
+
+allocated_functions
+The allocated functions of this PhysicalComponent.
+
+
+
+
+property components : ElementList [ PhysicalComponent ]
+
+
+
+
+property deployed_components : ElementList [ PhysicalComponent ]
+
+
+
+
+deploying_components : c.Accessor
+The deploying components of this PhysicalComponent.
+
+
+
+
+functions
+The functions of this PhysicalComponent.
+
+
+
+
+kind
+
+
+
+
+nature
+
+
+
+
+owned_components : c.Accessor
+The owned components of this PhysicalComponent.
+
+
+
+
+realized_logical_components
+The realized logical components of this PhysicalComponent.
+
+
+
+
+
+
+class capellambse.model.layers.pa. PhysicalComponentPkg
+Bases: GenericElement
+A logical component package.
+
+
+components
+The components of this PhysicalComponentPkg.
+
+
+
+
+exchanges
+The exchanges of this PhysicalComponentPkg.
+
+
+
+
+packages : c.Accessor
+The packages of this PhysicalComponentPkg.
+
+
+
+
+state_machines
+The state machines of this PhysicalComponentPkg.
+
+
+
+
+
+
+class capellambse.model.layers.pa. PhysicalFunction
+Bases: Function
+A physical function on the Physical Architecture layer.
+
+
+functions : c.Accessor
+The functions of this PhysicalFunction.
+
+
+
+
+owner : c.Accessor [ PhysicalComponent ]
+The owner of this PhysicalFunction.
+
+
+
+
+packages : c.Accessor
+The packages of this PhysicalFunction.
+
+
+
+
+realized_logical_functions
+The realized logical functions of this PhysicalFunction.
+
+
+
+
+
+
+class capellambse.model.layers.pa. PhysicalFunctionPkg
+Bases: GenericElement
+A logical component package.
+
+
+functions
+The functions of this PhysicalFunctionPkg.
+
+
+
+
+packages : c.Accessor
+The packages of this PhysicalFunctionPkg.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.pvmt.html b/code/capellambse.pvmt.html
new file mode 100644
index 000000000..65ec283d1
--- /dev/null
+++ b/code/capellambse.pvmt.html
@@ -0,0 +1,1060 @@
+
+
+
+
+
+
+
+
+ capellambse.pvmt package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.pvmt package
+Provides easy access to the Polarsys Capella PVMT extension.
+The public API of this submodule uses raw LXML elements. For a more
+object oriented and user friendly way to access property values in a
+model, see the capellambse.model.MelodyModel
class.
+
+
+capellambse.pvmt.core module
+Core functionality shared by all PVMT submodules.
+
+
+class capellambse.pvmt.core. Generic
+Bases: object
+Base class for PropertyValues, Domains etc.
+
+
+__init__ ( xml_element , * args , ** kwargs )
+
+
+
+
+classmethod from_xml_element ( element )
+Construct an object from the given XML element.
+This function is used to allow subclasses more control over how
+they are instantiated from existing XML elements, compared to
+creating them from scratch.
+
+Parameters:
+element (_Element ) –
+
+Return type:
+Generic
+
+
+
+
+
+
+idx
+
+
+
+
+name
+
+
+
+
+sid
+
+
+
+
+
+
+class capellambse.pvmt.core. XMLDictProxy
+Bases: Generic
, XMLDictProxy
+Makes using XMLDictProxy with PVMT easier.
+
+
+__init__ ( xml_element , * args , ** kwargs )
+Initialize the XMLDictProxy.
+
+Parameters:
+
+xml_element (_Element ) – The underlying XML element.
+childtag – The XML tag of handled child elements.
+keyattr – The element attribute to use as dictionary key.
+model – Reference to the original MelodyLoader. If not None, the
+loader will be informed about element creation and deletion.
+
+
+Return type:
+None
+
+
+
+
+
+
+
+
+capellambse.pvmt.exceptions module
+Exceptions that may be raised by the PVMT module.
+
+
+exception capellambse.pvmt.exceptions. CastingError
+Bases: PropertyValueError
+A supplied value cannot be cast from or to the XML representation.
+
+
+
+
+exception capellambse.pvmt.exceptions. GroupNotAppliedError
+Bases: PropertyValueError
, KeyError
+The property value group has not been applied to this element.
+
+
+
+
+exception capellambse.pvmt.exceptions. PropertyValueError
+Bases: Exception
+Base class for all property-value related errors.
+
+
+
+
+exception capellambse.pvmt.exceptions. ScopeError
+Bases: PropertyValueError
+Attempted to apply a PV group to an element outside its scope.
+
+
+
+
+exception capellambse.pvmt.exceptions. UndefinedKeyError
+Bases: PropertyValueError
, KeyError
+A key is attempted to be added which is not defined for the group.
+
+
+
+
+capellambse.pvmt.model module
+Provides easy access to the Polarsys Capella PVMT extensions.
+
+
+class capellambse.pvmt.model. Domain
+Bases: XMLDictProxy
+A PVMT Domain.
+
+
+__init__ ( element , * args , parent = None , ** kwargs )
+Initialize the XMLDictProxy.
+
+Parameters:
+
+xml_element – The underlying XML element.
+childtag – The XML tag of handled child elements.
+keyattr – The element attribute to use as dictionary key.
+model – Reference to the original MelodyLoader. If not None, the
+loader will be informed about element creation and deletion.
+
+
+
+
+
+
+
+property groups
+Return a list of all property value groups in this domain.
+
+
+
+
+
+
+class capellambse.pvmt.model. Group
+Bases: XMLDictProxy
+PVMT Group.
+
+
+__init__ ( * args , parent = None , ** kwargs )
+Initialize the XMLDictProxy.
+
+Parameters:
+
+xml_element – The underlying XML element.
+childtag – The XML tag of handled child elements.
+keyattr – The element attribute to use as dictionary key.
+model – Reference to the original MelodyLoader. If not None, the
+loader will be informed about element creation and deletion.
+
+
+
+
+
+
+
+classmethod from_xml_element ( element )
+Construct an object from the given XML element.
+
+Parameters:
+element (_Element ) –
+
+Return type:
+Group
+
+
+
+
+
+
+parent : Any | None
+
+
+
+
+property properties
+Return a list of all properties defined in this group.
+
+
+
+
+scope
+
+
+
+
+
+
+class capellambse.pvmt.model. PVMTExtension
+Bases: XMLDictProxy
+Facilitates access to property values.
+
+
+__init__ ( element , model = None )
+Initialize the XMLDictProxy.
+
+Parameters:
+
+xml_element – The underlying XML element.
+childtag – The XML tag of handled child elements.
+keyattr – The element attribute to use as dictionary key.
+model – Reference to the original MelodyLoader. If not None, the
+loader will be informed about element creation and deletion.
+
+
+
+
+
+
+
+property domains
+Return a list of all property value domains in the model.
+
+
+
+
+get_element_pv ( element , groupname , create = True )
+Return the named PVMT group on element
.
+
+Parameters:
+
+element – An LXML element with property value groups.
+groupname – The fully qualified name of the property value group, in the
+format “domain.group”.
+create – True to create (apply) the group if necessary.
+
+
+Return type:
+AppliedPropertyValueGroup
+
+
+
+
+
+
+
+
+capellambse.pvmt.model. load_pvmt_from_model ( model )
+Load the Property Value management extension for the given model.
+This function is the main entry point for the pvmt
module. It
+should be called after constructing a MelodyLoader
instance on
+the model file. It will return a PVMTExtension
object, which can
+be used to easily access the property values of the model given
+during intialization.
+
+
+
+
+capellambse.pvmt.types module
+Classes that represent different property value types.
+
+
+class capellambse.pvmt.types. AppliedPropertyValueGroup
+Bases: XMLDictProxy
+A group of applied property values.
+
+
+__init__ ( pvmt_ext , * args , ** kwargs )
+Create an AppliedPropertyValueGroup.
+
+Parameters:
+pvmt_ext – The capellambse.pvmt.model.PVMTExtension
object of
+the model.
+
+
+
+
+
+
+classmethod applyto ( pvmt_ext , xml_element , groupname )
+Apply the named property value group to the given element.
+
+Parameters:
+
+pvmt_ext – The PVMT extension object
+xml_element – The XML element of the target object
+groupname – The fully qualified name of the PVMT group
+
+
+Returns:
+The newly created XML element, a child of xml_element.
+
+Return type:
+lxml.etree._Element
+
+
+
+
+
+
+get_definition ( key )
+Return the PV definition instance for the given key.
+
+
+
+
+
+
+class capellambse.pvmt.types. BooleanPropertyValue
+Bases: GenericPropertyValue
+A boolean property value.
+
+
+static cast ( value )
+Cast the given string into an appropriate Python object.
+
+
+
+
+classmethod serialize ( value , element = None )
+Serialize the given value into an XML string.
+This function must be able to handle two types of input values:
+
+The type produced by .cast()
, which shall be turned back
+into its XML form, so that it can be passed into .cast()
+again.
+The XML representation of a valid value, i.e. its own output.
+
+If it is ambiguous which of the two types is being handled, the
+former shall be assumed.
+Note that escaping of XML special characters is handled by the
+underlying XML library.
+The default implementation works for the simple case where
+cast
is a type constructor, but for more complex cases it
+should be overridden.
+
+Parameters:
+
+value – The value that should be serialized.
+element – The XML element into which the value will be inserted. This
+may be used to construct links across fragment boundaries.
+This parameter may be None, in which case it is assumed that
+all elements exist within the same fragment.
+
+
+
+
+
+
+
+
+
+class capellambse.pvmt.types. EnumerationPropertyType
+Bases: XMLDictProxy
+Maps the literals’ UUIDs to their human-readable values.
+
+
+__init__ ( * args , ** kwargs )
+Initialize the XMLDictProxy.
+
+Parameters:
+
+xml_element – The underlying XML element.
+childtag – The XML tag of handled child elements.
+keyattr – The element attribute to use as dictionary key.
+model – Reference to the original MelodyLoader. If not None, the
+loader will be informed about element creation and deletion.
+
+
+
+
+
+
+
+property literals
+Return a list of valid literal values for this enumeration.
+
+
+
+
+
+
+class capellambse.pvmt.types. EnumerationPropertyValue
+Bases: GenericPropertyValue
+An enumeration property value.
+
+
+__init__ ( * args , typedef = None , ** kwargs )
+
+
+
+
+static applyto ( pvmt_ext , defelem , modelobj , targetelem )
+Apply a property value to targetelem
.
+
+Parameters:
+
+pvmt_ext – The PVMT Extension object.
+defelem – The ownedPropertyValues
element that should be applied.
+modelobj – A model object’s XML element that will be a (direct or
+indirect) parent to this property value.
+targetelem – The new ownedPropertyValues
element.
+
+
+
+
+
+
+
+cast ( value )
+Cast the given string into an appropriate Python object.
+
+
+
+
+property default_value
+Return this property’s default value.
+
+
+
+
+property parent
+Return the parent group of this property value.
+
+
+
+
+serialize ( value , element = None )
+Serialize the given value into an XML string.
+This function must be able to handle two types of input values:
+
+The type produced by .cast()
, which shall be turned back
+into its XML form, so that it can be passed into .cast()
+again.
+The XML representation of a valid value, i.e. its own output.
+
+If it is ambiguous which of the two types is being handled, the
+former shall be assumed.
+Note that escaping of XML special characters is handled by the
+underlying XML library.
+The default implementation works for the simple case where
+cast
is a type constructor, but for more complex cases it
+should be overridden.
+
+Parameters:
+
+value – The value that should be serialized.
+element – The XML element into which the value will be inserted. This
+may be used to construct links across fragment boundaries.
+This parameter may be None, in which case it is assumed that
+all elements exist within the same fragment.
+
+
+
+
+
+
+
+property typedef
+Return the type definition of this enumeration.
+
+
+
+
+
+
+class capellambse.pvmt.types. FloatPropertyValue
+Bases: GenericPropertyValue
+A floating point property value.
+
+
+cast
+alias of float
+
+
+
+
+property unit
+Return the measurement unit of this property value.
+
+
+
+
+
+
+class capellambse.pvmt.types. GenericPropertyValue
+Bases: Generic
+Base class for property value types.
+
+
+__init__ ( * args , ** kwargs )
+
+
+
+
+static applyto ( pvmt_ext , defelem , modelobj , targetelem )
+Apply a property value to targetelem
.
+
+Parameters:
+
+pvmt_ext – The PVMT Extension object.
+defelem – The ownedPropertyValues
element that should be applied.
+modelobj – A model object’s XML element that will be a (direct or
+indirect) parent to this property value.
+targetelem – The new ownedPropertyValues
element.
+
+
+
+
+
+
+
+abstract static cast ( value )
+Cast the given string into an appropriate Python object.
+
+
+
+
+description
+
+
+
+
+serialize ( value , element = None )
+Serialize the given value into an XML string.
+This function must be able to handle two types of input values:
+
+The type produced by .cast()
, which shall be turned back
+into its XML form, so that it can be passed into .cast()
+again.
+The XML representation of a valid value, i.e. its own output.
+
+If it is ambiguous which of the two types is being handled, the
+former shall be assumed.
+Note that escaping of XML special characters is handled by the
+underlying XML library.
+The default implementation works for the simple case where
+cast
is a type constructor, but for more complex cases it
+should be overridden.
+
+Parameters:
+
+value – The value that should be serialized.
+element – The XML element into which the value will be inserted. This
+may be used to construct links across fragment boundaries.
+This parameter may be None, in which case it is assumed that
+all elements exist within the same fragment.
+
+
+
+
+
+
+
+xtype
+
+
+
+
+
+
+class capellambse.pvmt.types. IntegerPropertyValue
+Bases: GenericPropertyValue
+An integer property value.
+
+
+cast
+alias of int
+
+
+
+
+property unit
+Return the measurement unit of this property value.
+
+
+
+
+
+
+class capellambse.pvmt.types. StringPropertyValue
+Bases: GenericPropertyValue
+A string property value.
+
+
+cast
+alias of str
+
+
+
+
+
+
+capellambse.pvmt.types. select_property_loader ( element )
+Execute the appropriate loader for the PV definition element.
+
+
+
+
+capellambse.pvmt.validation module
+Validation functions for PVMT.
+
+
+capellambse.pvmt.validation. validate_group_scope ( pvmt_ext , groupdef , xml_element )
+Verify that the groupdef
’s scope applies to the given element.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/capellambse.svg.html b/code/capellambse.svg.html
new file mode 100644
index 000000000..6a30f4cc5
--- /dev/null
+++ b/code/capellambse.svg.html
@@ -0,0 +1,1884 @@
+
+
+
+
+
+
+
+
+ capellambse.svg package - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+capellambse.svg package
+Export diagrams to .svg
files.
+
+
+capellambse.svg.decorations module
+The decoration factories for svg elements.
+
+
+class capellambse.svg.decorations. DecoFactories
+Bases: dict
[str
, DecoFactory
]
+
+
+
+
+class capellambse.svg.decorations. DecoFactory
+Bases: object
+DecoFactory(function: ‘cabc.Callable’, dependencies: ‘tuple[str, …]’)
+
+
+__init__ ( function , dependencies )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+dependencies : tuple [ str , ... ]
+
+
+
+
+function : Callable
+
+
+
+
+
+
+capellambse.svg.decorations. feature_space = 24
+Default margins/padding (top/bot and left/right) for feature text.
+
+
+
+
+capellambse.svg.decorations. icon_padding = 2
+Default icon padding (left/right side).
+
+
+
+
+capellambse.svg.decorations. icon_size = 20
+Default icon size.
+
+
+
+
+capellambse.svg.decorations. max_label_width = 1500
+Maximum width for a label.
+
+
+
+
+capellambse.svg.drawing module
+Custom extensions to the svgwrite Drawing
object.
+
+
+capellambse.svg.drawing. DEBUG = False
+Debug flag to render helping lines.
+
+
+
+
+class capellambse.svg.drawing. Drawing
+Bases: object
+The main container that stores all svg elements.
+
+
+__init__ ( metadata , * , font_family = "'Open Sans','Segoe UI',Arial,sans-serif" , font_size = 11 , transparent_background = False )
+
+Parameters:
+
+
+
+
+
+
+
+draw_object ( obj )
+Draw an object into this drawing.
+
+Parameters:
+obj (Mapping [ str , Any ] ) – The (decoded) JSON-dict of a single diagram object.
+
+Return type:
+None
+
+
+
+
+
+
+property filename : str
+Return the filename of the SVG.
+
+
+
+
+save_as ( filename = None , ** kw )
+Write the SVG to a file.
+If filename
wasn’t given the underlying filename
is
+taken.
+
+Parameters:
+
+filename (str | None ) –
+kw (Any ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+to_string ( )
+Return a string representation of the SVG.
+
+Return type:
+str
+
+
+
+
+
+
+
+
+capellambse.svg.drawing. LABEL_ICON_PADDING = 2
+Default padding between a label’s icon and text.
+
+
+
+
+class capellambse.svg.drawing. LabelBuilder
+Bases: object
+Helper data-class for building labels.
+
+
+__init__ ( rect_width , rect_height , labels , group , labelstyle , class_ = None , y_margin = 0 , text_anchor = 'start' , icon = True , icon_size = 20 , alignment = 'center' )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+alignment : Literal [ 'center' , 'left' , 'right' ] = 'center'
+
+
+
+
+class_ : str | None = None
+
+
+
+
+group : Group
+
+
+
+
+icon : bool = True
+
+
+
+
+icon_size : float | int = 20
+
+
+
+
+labels : list [ LabelDict ]
+
+
+
+
+labelstyle : Styling
+
+
+
+
+rect_height : int | float
+
+
+
+
+rect_width : int | float
+
+
+
+
+text_anchor : str = 'start'
+
+
+
+
+y_margin : int | float = 0
+
+
+
+
+
+
+class capellambse.svg.drawing. LabelDict
+Bases: TypedDict
+
+
+class : str
+
+
+
+
+height : float
+
+
+
+
+text : str
+
+
+
+
+width : float
+
+
+
+
+x : float
+
+
+
+
+y : float
+
+
+
+
+
+
+class capellambse.svg.drawing. LinesData
+Bases: object
+Helper data-tuple for rendering text-lines from labels.
+
+
+__init__ ( lines , line_height , text_height , margin , max_line_width , min_x = None )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+line_height : float
+
+
+
+
+lines : list [ str ]
+
+
+
+
+margin : float
+
+
+
+
+max_line_width : float
+
+
+
+
+min_x : float | None = None
+
+
+
+
+text_height : float
+
+
+
+
+
+
+capellambse.svg.drawing. get_label_icon_position ( builder , lines )
+Calculate the icon’s position.
+
+Parameters:
+
+
+Return type:
+Vector2D
+
+
+
+
+
+
+capellambse.svg.drawing. get_label_position ( builder , lines )
+Calculate the label positions.
+
+Parameters:
+
+
+Return type:
+Vector2D
+
+
+
+
+
+
+capellambse.svg.drawing. render_hbounded_lines ( builder , render_icon )
+Return Lines data to render a label.
+
+Parameters:
+
+
+Return type:
+LinesData
+
+
+
+
+
+
+capellambse.svg.generate module
+
+
+class capellambse.svg.generate. ContentsDict
+Bases: TypedDict
+
+
+class : str
+
+
+
+
+height : float
+
+
+
+
+id : str
+
+
+
+
+label : LabelDict | str
+
+
+
+
+points : List [ List [ int ] ]
+
+
+
+
+type : str
+
+
+
+
+width : float
+
+
+
+
+x : float
+
+
+
+
+y : float
+
+
+
+
+
+
+class capellambse.svg.generate. DiagramMetadata
+Bases: object
+Holds metadata about a diagram.
+The metadata of a diagram includes the diagram-name, (x, y)
+position, (w, h)
size, the viewbox string and the diagram class,
+e.g. LogicalArchitectureBlank
.
+
+
+__init__ ( pos , size , name , class_ , ** _kw )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+class_ : str | None
+
+
+
+
+classmethod from_dict ( data )
+
+Parameters:
+data (DiagramMetadataDict ) –
+
+Return type:
+DiagramMetadata
+
+
+
+
+
+
+name : str
+
+
+
+
+pos : tuple [ float , float ]
+
+
+
+
+size : tuple [ float , float ]
+
+
+
+
+viewbox : str
+
+
+
+
+
+
+class capellambse.svg.generate. DiagramMetadataDict
+Bases: TypedDict
+
+
+class : str | None
+
+
+
+
+contents : Sequence [ ContentsDict ]
+
+
+
+
+height : float
+
+
+
+
+name : str
+
+
+
+
+width : float
+
+
+
+
+x : float
+
+
+
+
+y : float
+
+
+
+
+
+
+class capellambse.svg.generate. SVGDiagram
+Bases: object
+An SVG diagram that can be drawn on and serialized.
+SVG diagram object that takes the metadata
of a diagram via the
+DiagramMetadata
and a list of objects that are dictionaries
+describing the components to be drawn on the diagram canvas of type
+Drawing
.
+Example of expected json-file/string:
+{
+ "name" : "FA00 - Functional Architecture Example" ,
+ "class" : "LogicalArchitectureBlank" ,
+ "x" : 10 ,
+ "y" : 20 ,
+ "width" : 100 ,
+ "height" : 200 ,
+ "contents" : [
+ {
+ "type" : "box" ,
+ "id" : "_ZNVPYDHuEeqOg4absf8kjA" ,
+ "class" : "LogicalFunction" ,
+ "x" : 150 ,
+ "y" : 130 ,
+ "width" : 101 ,
+ "height" : 101 ,
+ "label" : "example label"
+ }
+ ]
+}
+
+
+
+
+__init__ ( metadata , objects , params = None )
+
+Parameters:
+
+
+Return type:
+None
+
+
+
+
+
+
+draw_object ( obj )
+Draw the given obj
on the underlaying Drawing
.
+
+Parameters:
+obj (ContentsDict ) –
+
+Return type:
+None
+
+
+
+
+
+
+classmethod from_json ( jsonstring )
+Create an SVGDiagram from the given JSON string.
+
+Parameters:
+jsonstring (str ) – Json/dictionary in str
format
+
+Returns:
+SVG diagram object
+
+Return type:
+SVGDiagram
+
+
+
+
+
+
+classmethod from_json_path ( path )
+Create an SVGDiagram from the given JSON file.
+
+Parameters:
+path (str | PathLike ) – path to .json file
+
+Returns:
+SVG diagram object
+
+Return type:
+SVGDiagram
+
+
+
+
+
+
+save ( filename = None , pretty = False , indent = 2 )
+Write the underlying Drawing
to an SVG file.
+
+Parameters:
+
+filename (str | None ) –
+pretty (bool ) –
+indent (int ) –
+
+
+Return type:
+None
+
+
+
+
+
+
+save_drawing ( * args , ** kwargs )
+
+Return type:
+None
+
+
+
+
+
+
+to_string ( )
+Return a string representation of the underlying Drawing
.
+
+Return type:
+str
+
+
+
+
+
+
+
+
+capellambse.svg.helpers module
+
+
+capellambse.svg.helpers. check_for_horizontal_overflow ( text , width , icon_padding , icon_size , alignment = 'center' )
+
+Parameters:
+
+
+Return type:
+tuple [Sequence [str ], float , float ]
+
+
+
+
+
+
+capellambse.svg.helpers. check_for_vertical_overflow ( lines , height , max_text_width )
+
+Parameters:
+
+
+Return type:
+list [str ]
+
+
+
+
+
+
+capellambse.svg.style module
+Stylesheet generator for SVG diagrams.
+
+
+class capellambse.svg.style. Styling
+Bases: object
+Container for style attributes of svg objects.
+Notes
+Attributes containing ‘-’ are only referenceable via getattr() or
+subscripting syntax, due to Python identifier naming rules.
+
+
+__init__ ( diagram_class , class_ , prefix = '' , ** attr )
+
+Parameters:
+
+
+
+
+
+
+
+_to_dict ( )
+Convert this styling to a dictionary.
+The returned dict also includes the built-in default styles for
+the diagram class and object class given to the constructor.
+
+Return type:
+dict [str , float | int | str ]
+
+
+
+
+
+
+
+
+capellambse.svg.symbols module
+
+
+capellambse.svg.symbols. and_control_node_symbol ( id_ = 'AndControlNodeSymbol' )
+
+
+
+
+capellambse.svg.symbols. arrow_mark ( id_ = 'Arrow' , ** kw )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Marker
+
+
+
+
+
+
+capellambse.svg.symbols. capability_symbol ( id_ = 'CapabilitySymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. class_symbol ( id_ = 'ClassSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. component_exchange_symbol ( id_ = 'ComponentExchangeSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. component_port_symbol ( id_ = 'ComponentPortSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. diamond_mark ( id_ = 'Diamond' , ** kw )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Marker
+
+
+
+
+
+
+capellambse.svg.symbols. entity_symbol ( id_ = 'EntitySymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. error_symbol ( id_ = 'ErrorSymbol' , ** kw )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. filled_diamond_mark ( id_ = 'FilledDiamond' , ** kw )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Marker
+
+
+
+
+
+
+capellambse.svg.symbols. final_state_symbol ( id_ = 'FinalStateSymbol' )
+
+
+
+
+capellambse.svg.symbols. fine_arrow_mark ( id_ = 'FineArrow' , ** kw )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Marker
+
+
+
+
+
+
+capellambse.svg.symbols. function_symbol ( id_ = 'FunctionSymbol' , colors = ('#6CB35B', '#ffffff') , gradient_url = 'green' , label = 'F' )
+
+Parameters:
+
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. functional_exchange_symbol ( id_ = 'FunctionalExchangeSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. generalization_mark ( id_ = 'Generalization' , ** kw )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Marker
+
+
+
+
+
+
+capellambse.svg.symbols. initial_pseudo_state_symbol ( id_ = 'InitialPseudoStateSymbol' )
+
+
+
+
+capellambse.svg.symbols. iterate_control_node_symbol ( id_ = 'IterateControlNodeSymbol' )
+
+
+
+
+capellambse.svg.symbols. logical_actor_symbol ( id_ = 'LogicalActorSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. logical_component_symbol ( id_ = 'LogicalComponentSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. logical_function_symbol ( id_ = 'LogicalFunctionSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. logical_human_actor_symbol ( id_ = 'LogicalHumanActorSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. logical_human_component_symbol ( id_ = 'LogicalHumanComponentSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. mission_symbol ( id_ = 'MissionSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. mode_symbol ( id_ = 'ModeSymbol' )
+
+
+
+
+capellambse.svg.symbols. operational_activity_symbol ( id_ = 'OperationalActivitySymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. operational_actor_box_symbol ( id_ = 'OperationalActorBoxSymbol' )
+
+
+
+
+capellambse.svg.symbols. operational_actor_symbol ( id_ = 'OperationalActorSymbol' )
+
+
+
+
+capellambse.svg.symbols. operational_capability_symbol ( id_ = 'OperationalCapabilitySymbol' )
+
+
+
+
+capellambse.svg.symbols. operational_exchange_symbol ( id_ = 'OperationalExchangeSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. or_control_node_symbol ( id_ = 'OrControlNodeSymbol' )
+
+
+
+
+capellambse.svg.symbols. physical_behavior_actor_symbol ( id_ = 'PhysicalBehaviorActorSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_behavior_component_symbol ( id_ = 'PhysicalBehaviorComponentSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_behavior_human_actor_symbol ( id_ = 'PhysicalBehaviorHumanActorSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_behavior_human_component_symbol ( id_ = 'PhysicalBehaviorHumanComponentSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_component_symbol ( id_ = 'PhysicalComponentSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_function_symbol ( id_ = 'PhysicalFunctionSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_link_symbol ( id_ = 'PhysicalLinkSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_node_actor_symbol ( id_ = 'PhysicalNodeActorSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_node_component_symbol ( id_ = 'PhysicalNodeComponentSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_node_human_actor_symbol ( id_ = 'PhysicalNodeHumanActorSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. physical_node_human_component_symbol ( id_ = 'PhysicalNodeHumanComponentSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. port_symbol ( id_ = 'PortSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. representation_link_symbol ( id_ = 'RepresentationLinkSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. requirement_symbol ( id_ = 'RequirementSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. standalone_stick_figure_symbol ( id_ = 'StandaloneStickFigureSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. state_symbol ( id_ = 'StateSymbol' )
+
+
+
+
+capellambse.svg.symbols. stick_figure_symbol ( id_ = 'StickFigureSymbol' , transform = None , head_color = 'none' , ** kw )
+Generate StickFigure svg symbol.
+
+Parameters:
+
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. system_actor_symbol ( id_ = 'SystemActorSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. system_component_symbol ( id_ = 'SystemComponentSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. system_function_symbol ( id_ = 'SystemFunctionSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. system_human_actor_symbol ( id_ = 'SystemHumanActorSymbol' )
+
+Parameters:
+id_ (str ) –
+
+Return type:
+Symbol
+
+
+
+
+
+
+capellambse.svg.symbols. terminate_pseudo_state_symbol ( id_ = 'TerminatePseudoStateSymbol' , stroke = '#000' , stroke_width = 0.165 )
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/modules.html b/code/modules.html
new file mode 100644
index 000000000..4d7163c72
--- /dev/null
+++ b/code/modules.html
@@ -0,0 +1,508 @@
+
+
+
+
+
+
+
+
+ py-capellambse - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/development/developing-docs.html b/development/developing-docs.html
new file mode 100644
index 000000000..81d6b6bd9
--- /dev/null
+++ b/development/developing-docs.html
@@ -0,0 +1,329 @@
+
+
+
+
+
+
+
+
+ Documentation development - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+Documentation development
+The following command deletes previous built documentation and derives
+docs out of code:
+
+The following command builds the docs:
+
+The resulting documentation build should be available in docs/build/html ,
+entry point is index.html
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/development/how-to-explore-capella-mm.html b/development/how-to-explore-capella-mm.html
new file mode 100644
index 000000000..366dbc3a5
--- /dev/null
+++ b/development/how-to-explore-capella-mm.html
@@ -0,0 +1,512 @@
+
+
+
+
+
+
+
+
+ How to explore Capella meta-model - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/development/low-level-api.html b/development/low-level-api.html
new file mode 100644
index 000000000..ba6b4c548
--- /dev/null
+++ b/development/low-level-api.html
@@ -0,0 +1,1005 @@
+
+
+
+
+
+
+
+
+ Low-level API - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+Low-level API
+The high level MelodyModel
-based API is largely
+manually designed, and therefore sometimes does not cover all interesting
+objects to a usable level. While we are constantly working on improving the
+situation, it’s also possible to use the low-level API based directly on the
+XML files in order to temporarily work around these shortcomings. This
+documentation sheds some light on the inner workings of this low-level API.
+In order to effectively work with it, you need to understand the basics of XML.
+It also helps to be familiar with LXML , which is used to parse and manipulate
+the XML trees in memory.
+Unfortunately it’s not possible to use LXML’s built-in XML serializer. It
+produces different whitespace in the XML tree, which confuses Capella’s XML
+diff-merge algorithm. This is why py-capellambse ships with a custom serializer that
+produces the same output format as Capella. It resides in the
+capellambse.loader.exs
module.
+
+The MelodyLoader object
+While the main object of interest for the high-level API is the
+capellambse.model.MelodyModel
class, for the low-level API it is
+the capellambse.loader.core.MelodyLoader
. It offers numerous
+methods to search elements, resolve references, ensure model integrity during
+certain modifications, and many more.
+The following sections categorize and document the various methods.
+The MelodyLoader
closely works together with its auxiliary class
+ModelFile
. However, the ModelFile
+mainly plays a role while loading or saving a model from/to disk (or other data
+stores), and isn’t used much when interacting with an already loaded model.
+
+
+Shifting between API levels
+
+High to low-level shift
+Every model object (i.e. instance of GenericElement
or one of its
+subclasses) has an attribute _element
, which holds a reference to the
+corresponding lxml.etree._Element
instance. The low-level API works
+directly with these _Element
instances.
+The MelodyModel
object stores a reference to the
+MelodyLoader
instance.
+
+
+Low to high-level shift
+The GenericElement class offers the
+from_model()
class
+method, which takes a MelodyModel
instance and a low-level LXML
+_Element
as arguments and constructs a high-level API proxy object from
+them. This is the way “back up” to the high-level API.
+
+
Note
+
Always call from_model
on the base GenericElement
class, not on its
+subclasses. The base class automatically searches for the correct subclass
+to instantiate, based on the xsi:type
of the passed XML element. Calling
+the method on a subclass directly may inadvertently cause the wrong class to
+be picked.
+
+>>> myfunc = model . search ( "LogicalFunction" )[ 0 ]
+>>> el = myfunc . _element
+>>> el
+<Element ownedFunctions at 0x7f9e3742b840>
+>>> from capellambse.model import GenericElement
+>>> high_el = GenericElement . from_model ( model , el )
+>>> high_el == myfunc
+True
+
+
+When working with multiple objects, it can be desirable to directly construct a
+high-level ElementList
with them.
+The ElementList constructor works similar to GenericElement.from_model
, but
+it takes a list of elements instead of only a single one.
+>>> mycomp = model . search ( "LogicalComponent" )[ 0 ]
+>>> children = mycomp . _element . getchildren ()
+>>> len ( children )
+7
+>>> mylist = ElementList ( model , children )
+>>> mylist
+[0] <Constraint 'Chamber of secrets closed' (7a5b8b30-f596-43d9-b810-45ab02f4a81c)>
+[1] <ComponentExchange 'Care' (c31491db-817d-44b3-a27c-67e9cc1e06a2)>
+[2] <InterfacePkg 'Interfaces' (c8f33066-2801-4970-8aea-6aadc189b9f3)>
+[3] <Part 'Whomping Willow' (1188fc31-789b-424f-a2d4-06791873a351)>
+[4] <Part 'School' (018a8ae9-8e8e-4aea-8191-4abf844a79e3)>
+[5] <LogicalComponent 'Whomping Willow' (3bdd4fa2-5646-44a1-9fa6-80c68433ddb7)>
+[6] <LogicalComponent 'School' (a58821df-c5b4-4958-9455-0d30755be6b1)>
+
+
+
+
+
+Moving along the XML tree
+In most simple cases, you can use the standard LXML methods in order to select
+parent, child and sibling elements.
+>>> myfunc = model . search ( "LogicalFunction" )[ 3 ]
+>>> myfunc . _element . getparent ()
+<Element ownedLogicalFunctions at 0x7f9e3742ad00>
+>>> myfunc . _element . getchildren ()
+[<Element outputs at 0x7f9e3742b9d0>]
+>>> myfunc . _element . getprevious ()
+<Element ownedFunctions at 0x7f9e3742b6b0>
+>>> myfunc . _element . getnext ()
+<Element ownedFunctions at 0x7f9e3742bca0>
+
+
+These elements and lists of elements can then be fed into
+GenericElement.from_model
or the ElementList
constructor respectively
+in order to return to the high-level API .
+Capella models support fragmentation into multiple files, which results in
+multiple XML trees being loaded into memory. This makes it difficult to
+traverse up and down the hierarchy, because in theory every element can be a
+fragment boundary – in this case, it does not have a physical parent element,
+and getparent()
will return None
. A call to getchildren()
or
+similar on the (logical) parent element will yield a placeholder which only
+contains a reference to the real element, but does not hold any other
+information.
+MelodyLoader
provides methods to traverse upwards or downwards in the
+model’s XML tree, while also taking into account fragment boundaries and the
+aforementioned placeholder elements.
+
+
+class capellambse.loader.core. MelodyLoader
+
+
+iterancestors ( element , * tags )
+Iterate over the ancestors of element
.
+This method will follow fragment links back to the origin point.
+
+Parameters:
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+iterchildren_xt ( element , * xtypes )
+Iterate over the children of element
.
+This method will follow links into different fragment files and
+yield those elements as if they were direct children.
+
+Parameters:
+
+element (_Element ) – The parent element under which to search for children.
+xtypes (str ) – Only yield elements whose xsi:type
matches one of those
+given here. If no types are given, all elements are yielded.
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+iterdescendants ( root_elm , * tags )
+Iterate over all descendants of root_elm
.
+This method will follow links into different fragment files and
+yield those elements as if they were part of the origin subtree.
+
+Parameters:
+
+root_elm (_Element ) – The root element of the tree
+tags (str ) – Only yield elements with a matching XML tag. If none are
+given, all elements are yielded.
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+iterdescendants_xt ( element , * xtypes )
+Iterate over all descendants of element
by xsi:type
.
+This method will follow links into different fragment files and
+yield those elements as if they were part of the origin subtree.
+
+Parameters:
+
+element (_Element ) – The root element of the tree
+xtypes (str ) – Only yield elements whose xsi:type
matches one of those
+given here. If no types are given, all elements are yielded.
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+
+
+Resolving references
+You will often encounter attributes that contain references to other elements.
+The MelodyLoader
provides the following methods to work with references:
+
+
+class capellambse.loader.core. MelodyLoader
+
+
+follow_link ( from_element , link )
+Follow a single link and return the target element.
+Valid links have one of the following two formats:
+
+Within the same fragment, a reference is the target’s UUID
+prepended with a #
, for example
+#7a5b8b30-f596-43d9-b810-45ab02f4a81c
.
+A reference to a different fragment contains the target’s
+xsi:type
and the path of the fragment, relative to the
+current one. For example, to link from main.capella
into
+frag/logical.capellafragment
, the reference could be:
+org.polarsys.capella.core.data.capellacore:Constraint
+frag/logical.capellafragment#7a5b8b30-f596-43d9-b810-45ab02f4a81c
.
+To link back to the project root from there, it could look
+like: org.polarsys.capella.core.data.pa:PhysicalArchitecture
+../main.capella#26e187b6-72e7-4872-8d8d-70b96243c96c
.
+
+
+Parameters:
+
+
+Raises:
+
+ValueError – If the link is malformed
+FileNotFoundError – If the target fragment is not loaded (only applicable if
+ from_element
is not None and fragment
is part of the
+ link)
+RuntimeError – If the expected xsi:type
does not match the actual
+ xsi:type
of the found target
+KeyError – If the target cannot be found
+
+
+Return type:
+_Element
+
+
+
+
+
+
+follow_links ( from_element , links , * , ignore_broken = False )
+Follow multiple links and return all results as list.
+The format for an individual link is the same as accepted by
+follow_link()
. Multiple links are separated by a single space.
+If any target cannot be found, None
will be inserted at that
+point in the returned list.
+
+Parameters:
+
+from_element (_Element | None ) – The element at the start of the link. This is needed to verify
+cross-fragment links.
+links (str ) – A string containing space-separated links as described in
+follow_link()
.
+ignore_broken (bool ) – Ignore broken references instead of raising a KeyError.
+
+
+Raises:
+
+KeyError – If any link points to a non-existing target. Can be
+ suppressed with ignore_broken
.
+ValueError – If any link is malformed.
+RuntimeError – If any expected xsi:type
does not match the actual
+ xsi:type
of the found target.
+
+
+Return type:
+list [_Element ]
+
+
+
+
+
+
+create_link ( from_element , to_element , * , include_target_type = None )
+Create a link to to_element
from from_element
.
+
+Parameters:
+
+from_element (_Element ) – The source element of the link.
+to_element (_Element ) – The target element of the link.
+include_target_type (bool | None ) –
Whether to include the target type in cross-fragment link
+definitions.
+If set to True, it will always be included, False will
+always exclude it. Setting it to None (the default) will use
+a simple heuristic: It will be added unless the
+from_element
is in a visual-only fragment (aird /
+airdfragment).
+Regardless of this setting, the target type will never be
+included if the link does not cross fragment boundaries.
+
+
+
+Returns:
+A link in one of the formats described by follow_link()
.
+Which format is used depends on whether from_element
and
+to_element
live in the the same fragment, and whether the
+include_target_type
parameter is set.
+
+Return type:
+str
+
+
+
+
+
+
+
+
+Finding elements elsewhere
+The low-level API implements the fundamentals for looking up model objects or
+finding them by their type. The following methods are involved in these
+operations:
+
+
+class capellambse.loader.core. MelodyLoader
+
+
+iterall ( * tags )
+Iterate over all elements in all trees by tags.
+
+Parameters:
+tags (str ) – Optionally restrict the iterator to the given tags.
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+iterall_xt ( * xtypes , trees = None )
+Iterate over all elements in all trees by xsi:type
s.
+
+Parameters:
+
+
+Return type:
+Iterator [_Element ]
+
+
+
+
+
+
+xpath ( query , * , namespaces = None , roots = None )
+Run an XPath query on all fragments.
+Note that, unlike the iter_*
methods, placeholder elements
+are not followed into their respective fragment.
+
+Parameters:
+
+query (str | XPath ) – The XPath query
+namespaces (Mapping [ str , str ] | None ) – Namespaces used in the query. Defaults to all known
+namespaces.
+roots (_Element | Iterable [ _Element ] | None ) – A list of XML elements to use as roots for the query.
+Defaults to all tree roots.
+
+
+Returns:
+A list of all matching elements.
+
+Return type:
+list [lxml.etree._Element ]
+
+
+
+
+
+
+xpath2 ( query , * , namespaces = None , roots = None )
+Run an XPath query and return the fragments and elements.
+Note that, unlike the iter_*
methods, placeholder elements
+are not followed into their respective fragment.
+The tuples have the fragment where the match was found as first
+element, and the LXML element as second one.
+
+Parameters:
+
+query (str | XPath ) – The XPath query
+namespaces (Mapping [ str , str ] | None ) – Namespaces used in the query. Defaults to all known
+namespaces.
+roots (_Element | Iterable [ _Element ] | None ) – A list of XML elements to use as roots for the query.
+Defaults to all tree roots.
+
+
+Returns:
+
A list of 2-tuples, containing:
+
+The fragment name where the match was found.
+The matching element.
+
+
+
+Return type:
+list [tuple [pathlib.PurePosixPath , lxml.etree._Element ]]
+
+
+
+
+
+
+
+
+Manipulating objects
+
+
Warning
+
The low-level API by itself does not do any consistency or validity checks
+when modifying a model. Therefore it is very easy to break a model using it,
+which can be very hard to recover from. Proceed with caution.
+
+As GenericElement
instances are simply wrappers around the raw XML
+elements, any changes to their attributes are directly reflected by changes to
+the attributes or children of the underlying XML element and vice versa. This
+means that no special care needs to be taken to keep the high-level and
+low-level parts of the API synchronized.
+In many cases, the attribute names of the high-level API match those in the
+XML, with the difference that the former uses snake_case
naming (as is
+conventional in the Python world), while the latter uses camelCase
naming.
+This example shows how the name of a function is accessed and modified using
+the low-level API:
+>>> myfunc = model . search ( "LogicalFunction" )[ 3 ]
+>>> myfunc . name
+'defend the surrounding area against Intruders'
+>>> myfunc . _element . attrib [ "name" ]
+'defend the surrounding area against Intruders'
+>>> myfunc . _element . attrib [ "name" ] = "My Function"
+>>> myfunc . name
+'My Function'
+
+
+Be aware that the XML usually does not explicitly store attributes that are set
+to their default value (as defined by the meta model). In addition to that, the
+high-level API often offers convenience shortcuts and reverse lookups that are
+not directly reflected by XML attributes. Without at the detailed definitions,
+it can therefore be difficult to infer the correct attributes for the low-level
+API objects.
+
+
+Creating and deleting objects
+
+
Warning
+
Creating or deleting objects through the low-level API is highly
+discouraged, as it bears a very high risk of breaking the model. It’s
+unlikely that we can support you with any breakage that you encounter as a
+result of using the low-level API.
+
If you need access to model elements and relations that are not yet covered
+by our high-level API, please consider contributing and extending it instead
+– it’s probably easier anyway. ;)
+
+
+The ID cache
+In order to provide instantaneous access to any model element via its UUID, the
+MelodyLoader maintains a hashmap containing all UUIDs. This hashmap needs to be
+updated when inserting or removing elements in the tree. The following methods
+take care of that:
+
+
+class capellambse.loader.core. MelodyLoader
+
+
+idcache_index ( subtree )
+Index the IDs of subtree
.
+This method must be called after adding subtree
to the XML
+tree.
+
+Parameters:
+subtree (_Element ) – The new element that was just inserted.
+
+Return type:
+None
+
+
+
+
+
+
+idcache_remove ( subtree )
+Remove the subtree
from the ID cache.
+This method must be called before actually removing subtree
+from the XML tree.
+
+Parameters:
+subtree (_Element ) – The element that is about to be removed.
+
+Return type:
+None
+
+
+
+
+
+
+idcache_rebuild ( )
+Rebuild the ID caches of all loaded ModelFile
instances.
+
+Return type:
+None
+
+
+
+
+
+
+
+
+Creating objects
+Creating a new object with the low-level API is a rather complex process. The
+MelodyLoader
does provide some basic integrity checks, but most of the
+meta-model-aware logic is implemented within the high-level API.
+Before creating a new object, you need to generate and reserve a UUID for it.
+This is done using the generate_uuid
method. new_uuid
provides a
+context manager around it, which automatically cleans up the model in case
+anything went wrong. It also checks that the UUID was properly registered with
+the ID cache (see below). It is therefore highly recommended to use
+new_uuid
over directly calling generate_uuid
. Note that even when using
+new_uuid
, you still need to manually call idcache_index
on the newly
+inserted element.
+
+
+class capellambse.loader.core. MelodyLoader
+
+
+generate_uuid ( parent , * , want = None )
+Generate a unique UUID for a new child of parent
.
+The generated ID is guaranteed to be unique across all currently
+loaded fragments.
+
+Parameters:
+
+parent (_Element ) – The parent element below which the new UUID will be used.
+want (str | None ) – Try this UUID first, and use it if it satisfies all other
+constraints. If it does not satisfy all constraints (e.g. it
+would be non-unique), a random UUID will be generated as
+normal.
+
+
+Returns:
+The new UUID.
+
+Return type:
+str
+
+
+
+
+
+
+new_uuid ( parent , * , want = None )
+Context Manager around generate_uuid()
.
+This context manager yields a newly generated model-wide unique
+UUID that can be inserted into a new element during the with
+block. It tries to keep the ID cache consistent in some harder
+to manage edge cases, like exceptions being thrown. Additionally
+it checks that the generated UUID was actually used in the tree;
+not using it before the with
block ends is an error and
+provokes an Exception.
+
+
Note
+
You still need to call idcache_index()
on the
+newly inserted element!
+
+Example usage:
+>>> with ldr . new_uuid ( parent_elm ) as obj_id :
+... child_elm = parent_elm . makeelement ( "ownedObjects" )
+... child_elm . set ( "id" , obj_id )
+... parent_elm . append ( child_elm )
+... ldr . idcache_index ( child_elm )
+
+
+If you intend to reserve a UUID that should be inserted later,
+use generate_uuid()
directly.
+
+Parameters:
+
+parent (_Element ) – The parent element below which the new UUID will be used.
+want (str | None ) – Request this UUID. The request may or may not be fulfilled;
+always use the actual UUID returned by the context manager.
+
+
+Return type:
+Generator [str , None, None]
+
+
+
+
+
+
+
+
+Deleting objects
+Inversely to creating new ones, when deleting an object from the XML tree it
+also needs to be removed from the ID cache. This is done by calling
+idcache_remove
(see above) on the element to be removed. Afterwards, delete
+the element from its parent using the standard LXML API.
+
+
+
+Saving modifications
+The MelodyLoader
provides the same save()
method as the high-level
+MelodyModel
.
+
+
+class capellambse.loader.core. MelodyLoader
+
+
+save ( ** kw )
+Save all model files.
+
+Parameters:
+kw (Any ) – Additional keyword arguments accepted by the file handler in
+use. Please see the respective documentation for more info.
+
+Return type:
+None
+
+
+
+Notes
+With a filehandler
that contacts a remote location (such
+as the capellambse.filehandler.git.GitFileHandler
with
+non-local repositories), saving might fail if the local state
+has gone out of sync with the remote state. To avoid this,
+always leave the update_cache
parameter at its default value
+of True
if you intend to save changes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/development/repl.html b/development/repl.html
new file mode 100644
index 000000000..c46bb380b
--- /dev/null
+++ b/development/repl.html
@@ -0,0 +1,382 @@
+
+
+
+
+
+
+
+
+ The py-capellambse REPL - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+The py-capellambse REPL
+A simple Python REPL with a Capella model.
+You can use this script to quickly launch an interactive Python
+interpreter and load a model.
+If the readline
module is available, the interpreter spawned from
+this script uses a separate readline history. It is located in
+$XDG_STATE_HOME/capellambse
on proper operating systems and in the
+capellambse
cache directory on others.
+Normally this script is run with something like python -Xdev -m
+capellambse.repl test-5.0
. However, as that can become quite unwieldy,
+it is also possible to run it as ./capellambse/repl.py 5.0
from the
+source tree – on Unix-like operating systems, this will automatically
+enable -Xdev
on the Python interpreter. Requirement is a
+sufficiently recent version of env
, which by now even Debian should
+have.
+In order to add custom models for the model
+argument, add a JSON file to the capellambse/known_models
directory.
+This file defines the instantiation parameters for the
+capellambse.model.MelodyModel
:
+1 {
+2 "path" : "tests/data/Library Project/Library Project.aird" ,
+3 "resources" : {
+4 "Library Test" : "tests/data/Library Test"
+5 }
+6 }
+
+
+
+Capellambse Repl
+capellambse / repl . py [ - h ] [ -- disable - diagram - cache ] [ -- dump ] [ - V ] [ -- hold | -- wipe ] [ model ]
+
+
+
+positional arguments
+
+model
- A model name from known_models, an AIRD file, or the path to (or contents of) a JSON file describing the model. The following models are known: docs
, test-5.2
, test-6.0
, level-crossing-demo
, coffee-machine
, test-lib
, croud-surveillance-demo
, test-5.0
, ife-demo
(default: None
)
+
+
+
+options
+
+-h
, --help
- show this help message and exit
+--disable-diagram-cache
- Disable the diagram cache, if one was defined for the model
+--dump
- Dump model info as JSON to stdout and exit
+-V
, --version
- show program’s version number and exit
+--hold
- Inhibit automatic model updates (update_cache=False)
+--wipe
- Wipe the cache (disable_cache=True)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/01 Introduction.html b/examples/01 Introduction.html
new file mode 100644
index 000000000..919df7107
--- /dev/null
+++ b/examples/01 Introduction.html
@@ -0,0 +1,657 @@
+
+
+
+
+
+
+
+
+ 1. Introduction - py-capellambse documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+ Light mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dark mode
+
+
+
+
+
+
+ Auto light/dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hide table of contents sidebar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+ Toggle Light / Dark / Auto color theme
+
+
+
+
+
+
+ Toggle table of contents sidebar
+
+
+
+
+
+1. Introduction
+Welcome to the py-capella-mbse Showcase notebook. This notebook will show you some basic (and not so basic) things that you can get done using this library. For more advanced features have a look around the nearby notebooks.
+The below code loads the library and one of the test models:
+
+
+
+
+
+<capellambse.model.MelodyModel at 0x7f3f44f97970>
+
+
+Let’s go to the first practical example of working with the library!
+
+1.1. Example 1: Actor functions
+The below code will print every Actor available in the Logical Architecture layer
+
+
+
+
+
+
+Multiport
+Prof. S. Snape
+Voldemort
+R. Weasley
+Prof. A. P. W. B. Dumbledore
+Harry J. Potter
+
+
+but we could also “zoom-in” to an actor of interest:
+
+
+
+
+
Prof. S. Snape (org.polarsys.capella.core.data.la:LogicalComponent) allocated_functions LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)applied_property_value_groups PropertyValueGroup "DarkMagic.Power" (2a480409-57d1-46f8-a0ce-e574706a9a7c)PropertyValueGroup "DarkMagic.Power Level" (b1d7453b-69ab-4d81-ab8b-1e48b5870340)applied_property_values (Empty list)
components (Empty list)
constraints (Empty list)
context_diagram Context of Prof. S. Snape (uuid: 6f463eed-c77b-4568-8078-beec0536f243_context)description Good guy and teacher of brewing arts.
+diagrams (Empty list)
exchanges (Empty list)
filtering_criteria (Empty list)
functions LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)is_abstract False is_actor True is_human True name Prof. S. Snape owner LogicalComponentPkg "Structure" (84c0978d-9a32-4f5b-8013-5b0b6adbfd73)parent LogicalComponentPkg "Structure" (84c0978d-9a32-4f5b-8013-5b0b6adbfd73)parts Backreference to Part - omitted: can be slow to compute. Display this property directly to show. physical_links (Empty list)
physical_paths (Empty list)
physical_ports (Empty list)
ports ComponentPort "CP 1" (b4e39757-b0fd-41ff-a7b8-c9fc36de2ca9)progress_status NOT_SET property_value_groups PropertyValueGroup "DarkMagic.Power" (2a480409-57d1-46f8-a0ce-e574706a9a7c)PropertyValueGroup "DarkMagic.Power Level" (b1d7453b-69ab-4d81-ab8b-1e48b5870340)property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f496cb3f010> realized_components (Empty list)
realized_system_components (Empty list)
realizing_components Backreference to - omitted: can be slow to compute. Display this property directly to show. realizing_physical_components Backreference to PhysicalComponent - omitted: can be slow to compute. Display this property directly to show. related_exchanges Backreference to ComponentExchange - omitted: can be slow to compute. Display this property directly to show. requirements (Empty list)
state_machines (Empty list)
summary None traces (Empty list)
uuid 6f463eed-c77b-4568-8078-beec0536f243 xtype org.polarsys.capella.core.data.la:LogicalComponent
+
+We can also turn the above data into a table, for example “actor function allocation”, using pandas
.
+For this, we first make sure pandas itself is installed, as well as an extension we’ll use later.
+
+Now we can use it together with capellambse
:
+
+
+
+
+
+
+
+
+
+
+ actor
+ functions
+
+
+
+
+ 0
+ Multiport
+ LAF 1
+
+
+ 1
+ Prof. S. Snape
+ Teaching; maintain a layer of defense for the ...
+
+
+ 2
+ Voldemort
+ no functions assigned
+
+
+ 3
+ R. Weasley
+ assist Harry; break school rules
+
+
+ 4
+ Prof. A. P. W. B. Dumbledore
+ manage the school; advise Harry
+
+
+ 5
+ Harry J. Potter
+ kill He Who Must Not Be Named
+
+
+
+
+
+and any pandas.DataFrame
can always be turned into an Excel Spreadsheet, just like that:
+
+you can check the resulting file in the folder next to this notebook (right after you run the above cell)
+Now that we’ve seen the basics, lets do something visually cool.
+
+
+1.2. Example 2: working with diagrams
+The below code will find some diagrams for us.
+
+
+
+
+
+
+[LAB] Wizzard Education
+[LAB] Test Component Port Filter
+[LAB] Hidden Wizzard Education
+
+
+We can analyze which model objects are shown in a particular diagram.
+
+
+
+
+
Part "Hogwarts" (101ffa60-f8a2-4ea2-a0d8-d10910ceac06)LogicalFunction "produce Great Wizards" (0e71a0d3-0a18-4671-bba0-71b5f88f95dd)LogicalFunction "protect Students against the Death Eaters" (264fb47d-67b7-4bdc-8d06-8a0e5139edbf)Part "Campus" (a3194240-cd17-4998-8f8b-785233487ec3)Part "School" (018a8ae9-8e8e-4aea-8191-4abf844a79e3)LogicalFunction "educate Wizards" (957c5799-1d4a-4ac0-b5de-33a65bf1519c)Part "Whomping Willow" (1188fc31-789b-424f-a2d4-06791873a351)LogicalFunction "defend the surrounding area against Intruders" (7f2936ab-0b54-4e92-9f0c-85a9f0981959)Part "Prof. A. P. W. B. Dumbledore" (4c1f2b5d-0641-42c7-911f-7a42928580b8)LogicalFunction "manage the school" (f708bc29-d69f-42a0-90cc-11fc01054cd0)LogicalFunction "advise Harry" (beaf5ba4-8fa9-4342-911f-0266bb29be45)Part "Prof. S. Snape" (ccbad61a-39dc-4af8-8199-3fee30de2f1d)LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)ComponentExchange "Headmaster Responsibilities" (c0bc49e1-8043-4418-8c0a-de6c6b749eab)ComponentExchange "Teacher Responsibilities" (9cbdd233-aff5-47dd-9bef-9be1277c77c3)Part "Harry J. Potter" (26543596-7646-4d81-8f15-c4e01ec930a7)LogicalFunction "kill He Who Must Not Be Named" (aa9931e3-116c-461e-8215-6b9fdbdd4a1b)Part "R. Weasley" (4d31caaf-210e-4bdf-982e-cdecbc80c947)LogicalFunction "assist Harry" (c1a42acc-1f53-42bb-8404-77a5c08c414b)LogicalFunction "break school rules" (edbd1ad4-31c0-4d53-b856-3ffa60e0e99b)ComponentExchange "Punishment" (85a1fb20-38ea-4d77-acd7-90a8c44dc695)FunctionalExchange "wizardry" (6545a77d-d224-4662-a5b2-3c016b78e33d)PortAllocation "" (a4e2bf11-0705-4f20-bf73-5fa5519954f7)PortAllocation "" (7d31ab50-63d6-46bb-bf53-1716175beae3)PortAllocation "" (317715cb-376c-4df6-a32c-433e3c081f8d)ComponentExchange "Learning" (3b3fc202-be5c-49ae-bf2f-1d61daf3bb50)PortAllocation "" (c1019d06-f376-48e3-832e-634a8ec59463)PortAllocation "" (4cbdf5fd-7268-470b-9811-b62ad67fded1)FunctionalExchange "assistance" (241f3901-11f0-4b00-a903-ed158cce73de)FunctionalExchange "friendship" (1bbb9b2d-517c-4f77-a35c-b3aa3f9422b8)PortAllocation "" (18fa81ee-8b16-4815-86ea-0c287ace43d8)ComponentExchange "Help for Harry" (d8655737-39ab-4482-a934-ee847c7ff6bd)FunctionalExchange "punish" (96a0cf4c-adfe-4490-92d1-bcf75ee77004)FunctionalExchange "educate & mature" (09efaeb7-2d50-40ed-a4da-46afcb9ca7a1)FunctionalExchange "Knowledge" (b1a817bc-40a9-4fc4-b62c-8dea4aa28915)PortAllocation "" (dda7a62a-f25f-46d8-8f05-867c616914c1)PortAllocation "" (fee1fff5-d751-401b-bb3c-2114a74f0c8a)PortAllocation "" (0f6e1aa0-942a-40a9-930f-c7df34b9d8eb)ComponentExchange "Care" (c31491db-817d-44b3-a27c-67e9cc1e06a2)PortAllocation "" (98760017-b3a3-46ca-b1ef-87eee9ea1600)PortAllocation "" (74bd0ab3-6a28-4025-822e-90201445a56e)PortAllocation "" (3ed5ae4f-8a4e-4690-9088-655990a1b77b)PortAllocation "" (299b98b8-8716-4dbc-bc7e-4b9349778c26)PortAllocation "" (14cabdd9-c36f-4e01-ad09-110f906ad725)PortAllocation "" (6d882e28-4208-41d0-b8a5-3a19e1805a34)FunctionalExchange "educate" (cdc69c5e-ddd8-4e59-8b99-f510400650aa)PortAllocation "" (c90bb30d-e36b-46a3-a3a1-e39fdcb519be)
+
+And again there are warnings - there are quite a few visual filters in Capella and we are not handling all of those yet but mostly those that are used in our projects. The filter coverage will eventally improve, stay tuned.
+And finally, you can display the diagram right in the notebook.
+
+
+
+
+
+
+We use SVG diagrams a lot since they look great in documentation, are zoomable and really light-weight. To make integrating them into a pipeline easier, we also support some derived formats, which you can access using .as_<format>
style attributes. With some additional dependencies set up (see the README), capellambse can also automatically convert these images to PNG format.
+
+
+
+
+
+
+'<svg baseProfile="full" class="LogicalArchitectureBlank" height="611" style="shape-rendering: geome ...
+'data:image/svg+xml;base64,PHN2ZyBiYXNlUHJvZmlsZT0iZnVsbCIgY2xhc3M9IkxvZ2ljYWxBcmNoaXRlY3R1cmVCbGFua ...
+Markup('<img src="data:image/svg+xml;base64,PHN2ZyBiYXNlUHJvZmlsZT0iZnVsbCIgY2xhc3M9IkxvZ2ljYWxBcmNo ...
+b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x04\x8a\x00\x00\x02c\x08\x02\x00\x00\x00\xec\xe8m\xd2\ ...
+
+
+It’s also possible to directly save a diagram to a file by calling its save
method:
+
+
+
+
+
+
+
+<?xml version="1.0" encoding="utf-8" ?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink" baseProfile="full" class="LogicalArchitectureBlank" height="611" style="shape-rendering: geometricPrecision; font-family: 'Segoe UI'; font-size: 8pt; cursor: pointer;" version="1.1" viewBox="15 15 1162 611" width="1162">
+ <defs>
+ <symbol id="LogicalComponentSymbol" style="stroke: #000; stroke-width: 2;" viewBox="0 0 79 79">
+ <path d="M18 237h46v43H18z" style="fill: #dbe6f4" transform="translate(0 -218)"/>
+ <path d="M12 247h11v8H12z" style="fill: #dbe6f4" transform="translate(0 -218)"/>
+ <path d="M12 261h11v8H12z" style="fill: #dbe6f4" transform="translate(0 -218)"/>
+ <g transform="scale(0.90705135,1.1024734)">
+ <path d="m 37.427456,20.821353 h 4.221475 V 50.90971 H 37.427456 Z M 39.538194,46.89517 H 56.75519 v 4.01454 H 39.538194 Z" style="fill: #000;stroke-width: 0.1;"/>
+ </g>
+...
+
+
+Lets now try something else - we check if function port has any protocols (state machines) underneath:
+
+
+
+
+
StateMachine "FaultStates" (06cefb2b-534e-4453-9aba-fe53329197ad)
+
+and we can also check what states it could have:
+
+
+
+
+
State "normal defence" (e494e247-efce-4258-9cc6-fd799dbb0adf)State "erroneous defence" (81f3de46-4596-41b0-8569-c3c21161a2f6)State "no defence" (5b6a03d8-0ef9-4b2b-9a50-a745f490d663)
+
+This concludes our introduction. There is a lot more you can do with the library - feel free to explore the examples collection or create an issue to ask for a specific use-case example and you may see it around pretty soon.
+
+
+
+
+
+
+
+
+
+
+
+ Copyright © DB InfraGO AG and the capellambse contributors
+
+ Made with
Sphinx and
@pradyunsg 's
+
+
Furo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/01 Introduction.ipynb b/examples/01 Introduction.ipynb
new file mode 100644
index 000000000..13fa7c0d5
--- /dev/null
+++ b/examples/01 Introduction.ipynb
@@ -0,0 +1,658 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1a1fe414",
+ "metadata": {},
+ "source": [
+ "# Introduction\n",
+ "\n",
+ "Welcome to the py-capella-mbse Showcase notebook. This notebook will show you some basic (and not so basic) things that you can get done using this library. For more advanced features have a look around the nearby notebooks.\n",
+ "\n",
+ "The below code loads the library and one of the test models:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3e28d1c9",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import capellambse\n",
+ "path_to_model = \"../../../tests/data/melodymodel/5_0/Melody Model Test.aird\"\n",
+ "model = capellambse.MelodyModel(path_to_model)\n",
+ "model"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "48ce0c1e",
+ "metadata": {},
+ "source": [
+ "Let's go to the first practical example of working with the library!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7e68b88c-b4bc-4c20-a39f-48094c0eabdd",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "## Example 1: Actor functions\n",
+ "\n",
+ "The below code will print every Actor available in the Logical Architecture layer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "abcd8693",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Multiport\n",
+ "Prof. S. Snape\n",
+ "Voldemort\n",
+ "R. Weasley\n",
+ "Prof. A. P. W. B. Dumbledore\n",
+ "Harry J. Potter\n"
+ ]
+ }
+ ],
+ "source": [
+ "for actor in model.la.all_actors:\n",
+ " print(actor.name)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4ddbf9be",
+ "metadata": {},
+ "source": [
+ "but we could also \"zoom-in\" to an actor of interest:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "56bb4b44",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Prof. S. Snape (org.polarsys.capella.core.data.la:LogicalComponent) allocated_functions LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)applied_property_value_groups PropertyValueGroup "DarkMagic.Power" (2a480409-57d1-46f8-a0ce-e574706a9a7c)PropertyValueGroup "DarkMagic.Power Level" (b1d7453b-69ab-4d81-ab8b-1e48b5870340)applied_property_values (Empty list)
components (Empty list)
constraints (Empty list)
context_diagram Context of Prof. S. Snape (uuid: 6f463eed-c77b-4568-8078-beec0536f243_context)description Good guy and teacher of brewing arts.
\n",
+ "diagrams (Empty list)
exchanges (Empty list)
filtering_criteria (Empty list)
functions LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)is_abstract False is_actor True is_human True name Prof. S. Snape owner LogicalComponentPkg "Structure" (84c0978d-9a32-4f5b-8013-5b0b6adbfd73)parent LogicalComponentPkg "Structure" (84c0978d-9a32-4f5b-8013-5b0b6adbfd73)parts Backreference to Part - omitted: can be slow to compute. Display this property directly to show. physical_links (Empty list)
physical_paths (Empty list)
physical_ports (Empty list)
ports ComponentPort "CP 1" (b4e39757-b0fd-41ff-a7b8-c9fc36de2ca9)progress_status NOT_SET property_value_groups PropertyValueGroup "DarkMagic.Power" (2a480409-57d1-46f8-a0ce-e574706a9a7c)PropertyValueGroup "DarkMagic.Power Level" (b1d7453b-69ab-4d81-ab8b-1e48b5870340)property_values (Empty list)
pvmt <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f496cb3f010> realized_components (Empty list)
realized_system_components (Empty list)
realizing_components Backreference to - omitted: can be slow to compute. Display this property directly to show. realizing_physical_components Backreference to PhysicalComponent - omitted: can be slow to compute. Display this property directly to show. related_exchanges Backreference to ComponentExchange - omitted: can be slow to compute. Display this property directly to show. requirements (Empty list)
state_machines (Empty list)
summary None traces (Empty list)
uuid 6f463eed-c77b-4568-8078-beec0536f243 xtype org.polarsys.capella.core.data.la:LogicalComponent
"
+ ],
+ "text/plain": [
+ "\n",
+ ".allocated_functions = [0] \n",
+ " [1] \n",
+ ".applied_property_value_groups = [0] \n",
+ " [1] \n",
+ ".applied_property_values = []\n",
+ ".components = []\n",
+ ".constraints = []\n",
+ ".context_diagram = \n",
+ ".description = Markup('Good guy and teacher of brewing arts.
\\n')\n",
+ ".diagrams = []\n",
+ ".exchanges = []\n",
+ ".filtering_criteria = []\n",
+ ".functions = [0] \n",
+ " [1] \n",
+ ".is_abstract = False\n",
+ ".is_actor = True\n",
+ ".is_human = True\n",
+ ".name = 'Prof. S. Snape'\n",
+ ".owner = \n",
+ ".parent = \n",
+ ".parts = ... # backreference to Part - omitted: can be slow to compute\n",
+ ".physical_links = []\n",
+ ".physical_paths = []\n",
+ ".physical_ports = []\n",
+ ".ports = [0] \n",
+ ".progress_status = 'NOT_SET'\n",
+ ".property_value_groups = [0] \n",
+ " [1] \n",
+ ".property_values = []\n",
+ ".pvmt = \n",
+ ".realized_components = []\n",
+ ".realized_system_components = []\n",
+ ".realizing_components = ... # backreference to - omitted: can be slow to compute\n",
+ ".realizing_physical_components = ... # backreference to PhysicalComponent - omitted: can be slow to compute\n",
+ ".related_exchanges = ... # backreference to ComponentExchange - omitted: can be slow to compute\n",
+ ".requirements = []\n",
+ ".state_machines = []\n",
+ ".summary = None\n",
+ ".traces = []\n",
+ ".uuid = '6f463eed-c77b-4568-8078-beec0536f243'\n",
+ ".xtype = 'org.polarsys.capella.core.data.la:LogicalComponent'"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.la.all_actors.by_name(\"Prof. S. Snape\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "30e17ac3",
+ "metadata": {},
+ "source": [
+ "We can also turn the above data into a table, for example \"actor function allocation\", using `pandas`.\n",
+ "\n",
+ "For this, we first make sure pandas itself is installed, as well as an extension we'll use later."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "400e483d-eca7-4fdd-a9e0-71467e1af8d8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%pip install -q pandas openpyxl"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acbe1247-e1a1-4da8-a95a-7b41f4836937",
+ "metadata": {},
+ "source": [
+ "Now we can use it together with `capellambse`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "833220d0",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " actor \n",
+ " functions \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " Multiport \n",
+ " LAF 1 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " Prof. S. Snape \n",
+ " Teaching; maintain a layer of defense for the ... \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " Voldemort \n",
+ " no functions assigned \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " R. Weasley \n",
+ " assist Harry; break school rules \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " Prof. A. P. W. B. Dumbledore \n",
+ " manage the school; advise Harry \n",
+ " \n",
+ " \n",
+ " 5 \n",
+ " Harry J. Potter \n",
+ " kill He Who Must Not Be Named \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " actor \\\n",
+ "0 Multiport \n",
+ "1 Prof. S. Snape \n",
+ "2 Voldemort \n",
+ "3 R. Weasley \n",
+ "4 Prof. A. P. W. B. Dumbledore \n",
+ "5 Harry J. Potter \n",
+ "\n",
+ " functions \n",
+ "0 LAF 1 \n",
+ "1 Teaching; maintain a layer of defense for the ... \n",
+ "2 no functions assigned \n",
+ "3 assist Harry; break school rules \n",
+ "4 manage the school; advise Harry \n",
+ "5 kill He Who Must Not Be Named "
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "\n",
+ "data = []\n",
+ "for actor in model.la.all_actors:\n",
+ " actor_functions = \"; \".join([function.name for function in actor.functions] or [\"no functions assigned\"])\n",
+ " data.append(dict(actor=actor.name, functions=actor_functions))\n",
+ "df = pd.DataFrame(data)\n",
+ "df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e04c482",
+ "metadata": {},
+ "source": [
+ "and any `pandas.DataFrame` can always be turned into an Excel Spreadsheet, just like that:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "10af24a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df.to_excel(\"01_intro_actor_functions.xlsx\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5370bc56",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "you can check the resulting file in the folder next to this notebook (right after you run the above cell)\n",
+ "\n",
+ "Now that we've seen the basics, lets do something visually cool."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5afcdfdd-79e0-4e07-b321-d92a11f1d082",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "## Example 2: working with diagrams\n",
+ "\n",
+ "The below code will find some diagrams for us."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "eb5f8747",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[LAB] Wizzard Education\n",
+ "[LAB] Test Component Port Filter\n",
+ "[LAB] Hidden Wizzard Education\n"
+ ]
+ }
+ ],
+ "source": [
+ "for diagram in model.la.diagrams.by_type('LAB'):\n",
+ " print(diagram.name)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "66609218",
+ "metadata": {},
+ "source": [
+ "We can analyze which model objects are shown in a particular diagram."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "71bf090e",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Part "Hogwarts" (101ffa60-f8a2-4ea2-a0d8-d10910ceac06)LogicalFunction "produce Great Wizards" (0e71a0d3-0a18-4671-bba0-71b5f88f95dd)LogicalFunction "protect Students against the Death Eaters" (264fb47d-67b7-4bdc-8d06-8a0e5139edbf)Part "Campus" (a3194240-cd17-4998-8f8b-785233487ec3)Part "School" (018a8ae9-8e8e-4aea-8191-4abf844a79e3)LogicalFunction "educate Wizards" (957c5799-1d4a-4ac0-b5de-33a65bf1519c)Part "Whomping Willow" (1188fc31-789b-424f-a2d4-06791873a351)LogicalFunction "defend the surrounding area against Intruders" (7f2936ab-0b54-4e92-9f0c-85a9f0981959)Part "Prof. A. P. W. B. Dumbledore" (4c1f2b5d-0641-42c7-911f-7a42928580b8)LogicalFunction "manage the school" (f708bc29-d69f-42a0-90cc-11fc01054cd0)LogicalFunction "advise Harry" (beaf5ba4-8fa9-4342-911f-0266bb29be45)Part "Prof. S. Snape" (ccbad61a-39dc-4af8-8199-3fee30de2f1d)LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)ComponentExchange "Headmaster Responsibilities" (c0bc49e1-8043-4418-8c0a-de6c6b749eab)ComponentExchange "Teacher Responsibilities" (9cbdd233-aff5-47dd-9bef-9be1277c77c3)Part "Harry J. Potter" (26543596-7646-4d81-8f15-c4e01ec930a7)LogicalFunction "kill He Who Must Not Be Named" (aa9931e3-116c-461e-8215-6b9fdbdd4a1b)Part "R. Weasley" (4d31caaf-210e-4bdf-982e-cdecbc80c947)LogicalFunction "assist Harry" (c1a42acc-1f53-42bb-8404-77a5c08c414b)LogicalFunction "break school rules" (edbd1ad4-31c0-4d53-b856-3ffa60e0e99b)ComponentExchange "Punishment" (85a1fb20-38ea-4d77-acd7-90a8c44dc695)FunctionalExchange "wizardry" (6545a77d-d224-4662-a5b2-3c016b78e33d)PortAllocation "" (a4e2bf11-0705-4f20-bf73-5fa5519954f7)PortAllocation "" (7d31ab50-63d6-46bb-bf53-1716175beae3)PortAllocation "" (317715cb-376c-4df6-a32c-433e3c081f8d)ComponentExchange "Learning" (3b3fc202-be5c-49ae-bf2f-1d61daf3bb50)PortAllocation "" (c1019d06-f376-48e3-832e-634a8ec59463)PortAllocation "" (4cbdf5fd-7268-470b-9811-b62ad67fded1)FunctionalExchange "assistance" (241f3901-11f0-4b00-a903-ed158cce73de)FunctionalExchange "friendship" (1bbb9b2d-517c-4f77-a35c-b3aa3f9422b8)PortAllocation "" (18fa81ee-8b16-4815-86ea-0c287ace43d8)ComponentExchange "Help for Harry" (d8655737-39ab-4482-a934-ee847c7ff6bd)FunctionalExchange "punish" (96a0cf4c-adfe-4490-92d1-bcf75ee77004)FunctionalExchange "educate & mature" (09efaeb7-2d50-40ed-a4da-46afcb9ca7a1)FunctionalExchange "Knowledge" (b1a817bc-40a9-4fc4-b62c-8dea4aa28915)PortAllocation "" (dda7a62a-f25f-46d8-8f05-867c616914c1)PortAllocation "" (fee1fff5-d751-401b-bb3c-2114a74f0c8a)PortAllocation "" (0f6e1aa0-942a-40a9-930f-c7df34b9d8eb)ComponentExchange "Care" (c31491db-817d-44b3-a27c-67e9cc1e06a2)PortAllocation "" (98760017-b3a3-46ca-b1ef-87eee9ea1600)PortAllocation "" (74bd0ab3-6a28-4025-822e-90201445a56e)PortAllocation "" (3ed5ae4f-8a4e-4690-9088-655990a1b77b)PortAllocation "" (299b98b8-8716-4dbc-bc7e-4b9349778c26)PortAllocation "" (14cabdd9-c36f-4e01-ad09-110f906ad725)PortAllocation "" (6d882e28-4208-41d0-b8a5-3a19e1805a34)FunctionalExchange "educate" (cdc69c5e-ddd8-4e59-8b99-f510400650aa)PortAllocation "" (c90bb30d-e36b-46a3-a3a1-e39fdcb519be) "
+ ],
+ "text/plain": [
+ "[0] \n",
+ "[1] \n",
+ "[2] \n",
+ "[3] \n",
+ "[4] \n",
+ "[5] \n",
+ "[6] \n",
+ "[7] \n",
+ "[8] \n",
+ "[9] \n",
+ "[10] \n",
+ "[11] \n",
+ "[12] \n",
+ "[13] \n",
+ "[14] \n",
+ "[15] \n",
+ "[16] \n",
+ "[17] \n",
+ "[18] \n",
+ "[19] \n",
+ "[20] \n",
+ "[21] \n",
+ "[22] \n",
+ "[23] \n",
+ "[24] \n",
+ "[25] \n",
+ "[26] \n",
+ "[27] \n",
+ "[28] \n",
+ "[29] \n",
+ "[30] \n",
+ "[31]