Skip to content

tags: - developer - classes description: Core class descriptions for the core classes of Supernotify for Home Assistant


Core Classes

Info

See the Class Diagram for how these relate to each other.

custom_components.supernotify.transport.Transport

Base class for delivery transports.

Sub classes integrste with Home Assistant notification services or alternative notification mechanisms.

METHOD DESCRIPTION
deliver

Delivery implementation

initialize

Async post-construction initialization

log_delivery_failure

Log a delivery failure, passing the exception caught in the caller's except block.

log_delivery_recovered

Call on a successful delivery - logs once if this transport was previously

simplify

Simplify text for delivery transports with speaking or plain text interfaces

validate_action

Override in subclass if transport has fixed action or doesn't require one

deliver(envelope, debug_trace=None) abstractmethod async

Delivery implementation


envelope (Envelope): envelope to be delivered
debug_trace (DebugTrace): debug info collector

initialize() async

Async post-construction initialization

log_delivery_failure(err, message, *args)

Log a delivery failure, passing the exception caught in the caller's except block.

Logged at ERROR (with traceback) the first time this transport becomes unavailable, then downgraded to DEBUG for consecutive failures until it recovers - avoids spamming the log every notification while an external service/device stays down. Call alongside record_error(), which keeps tracking the lifetime error count regardless of log level.

log_delivery_recovered()

Call on a successful delivery - logs once if this transport was previously flagged unavailable, then clears the flag.

simplify(text, strip_urls=False)

Simplify text for delivery transports with speaking or plain text interfaces

validate_action(action)

Override in subclass if transport has fixed action or doesn't require one

custom_components.supernotify.notification.Notification

Bases: ArchivableObject


              flowchart TD
              custom_components.supernotify.notification.Notification[Notification]
              custom_components.supernotify.archive.ArchivableObject[ArchivableObject]

                              custom_components.supernotify.archive.ArchivableObject --> custom_components.supernotify.notification.Notification
                


              click custom_components.supernotify.notification.Notification href "" "custom_components.supernotify.notification.Notification"
              click custom_components.supernotify.archive.ArchivableObject href "" "custom_components.supernotify.archive.ArchivableObject"
            
METHOD DESCRIPTION
apply_enabled_scenarios

Set media and action_groups from scenario if defined, first come first applied

base_filename

ArchiveableObject implementation

contents

ArchiveableObject implementation

convert_notify_entities

Short circuit supernotify notify entities so they're handled directly so not

initialize

Async post-construction initialization

media_requirements

If no media defined, look for iOS / Android actions that have media defined

record_result

Debugging (and unit test) support for notifications that failed or were skipped

apply_enabled_scenarios()

Set media and action_groups from scenario if defined, first come first applied

base_filename()

ArchiveableObject implementation

contents(diagnostics=False, **_kwargs)

ArchiveableObject implementation

convert_notify_entities(target=None)

Short circuit supernotify notify entities so they're handled directly so not going round in circles via calls to notify.send_message

Defined here rather than in models/Target since requires access to registries

initialize() async

Async post-construction initialization

media_requirements(data)

If no media defined, look for iOS / Android actions that have media defined

Example is the Frigate blueprint, which generates image, video etc in the data section, that can also be used for email attachments

record_result(delivery, envelope=None, targets=None, suppression_reason=None)

Debugging (and unit test) support for notifications that failed or were skipped

custom_components.supernotify.envelope.Envelope

Bases: DupeCheckable


              flowchart TD
              custom_components.supernotify.envelope.Envelope[Envelope]
              custom_components.supernotify.common.DupeCheckable[DupeCheckable]

                              custom_components.supernotify.common.DupeCheckable --> custom_components.supernotify.envelope.Envelope
                


              click custom_components.supernotify.envelope.Envelope href "" "custom_components.supernotify.envelope.Envelope"
              click custom_components.supernotify.common.DupeCheckable href "" "custom_components.supernotify.common.DupeCheckable"
            

Wrap a notification with a specific set of targets and service data possibly customized for those targets

METHOD DESCRIPTION
__eq__

Specialized equality check for subset of attributes

__repr__

Return a concise string representation of the Envelope.

core_action_data

Build the core set of service_data dict to pass to underlying notify service

customize_data

Return data filtered by delivery data_keys_select option, pruning empty maps by default.

grab_image

Grab an image from a camera, snapshot URL, MQTT Image etc

hash

Alpha hash to reduce noise from messages with timestamps or incrementing counts

__eq__(other)

Specialized equality check for subset of attributes

__repr__()

Return a concise string representation of the Envelope.

The returned string includes the envelope's message, title, and delivery name in the form: Envelope(message=,title=,delivery=<delivery_name>).</p> <p>Primarily intended for debugging and logging; note that attribute values are inserted directly and may not be quoted or escaped.</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.envelope.Envelope.core_action_data class="doc doc-heading"> <code class="highlight language-python"><span class=n>core_action_data</span><span class=p>(</span><span class=n>force_message</span><span class=o>=</span><span class=kc>True</span><span class=p>)</span></code> <a href=#custom_components.supernotify.envelope.Envelope.core_action_data class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Build the core set of <code>service_data</code> dict to pass to underlying notify service</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.envelope.Envelope.customize_data class="doc doc-heading"> <code class="highlight language-python"><span class=n>customize_data</span><span class=p>(</span><span class=n>data</span><span class=p>,</span> <span class=n>prune_empty</span><span class=o>=</span><span class=kc>True</span><span class=p>)</span></code> <a href=#custom_components.supernotify.envelope.Envelope.customize_data class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Return data filtered by delivery data_keys_select option, pruning empty maps by default.</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.envelope.Envelope.grab_image class="doc doc-heading"> <code class="highlight language-python"><span class=n>grab_image</span><span class=p>()</span></code> <span class="doc doc-labels"> <small class="doc doc-label doc-label-async"><code>async</code></small> </span> <a href=#custom_components.supernotify.envelope.Envelope.grab_image class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Grab an image from a camera, snapshot URL, MQTT Image etc</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.envelope.Envelope.hash class="doc doc-heading"> <code class="highlight language-python"><span class=nb>hash</span><span class=p>()</span></code> <a href=#custom_components.supernotify.envelope.Envelope.hash class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Alpha hash to reduce noise from messages with timestamps or incrementing counts</p> </div> </div> </div> </div> </div> <div class="doc doc-object doc-class"> <h2 id=custom_components.supernotify.scenario.Scenario class="doc doc-heading"> <code>custom_components.supernotify.scenario.Scenario</code> <a href=#custom_components.supernotify.scenario.Scenario class=headerlink title="Permanent link">¶</a></h2> <div class="doc doc-contents first"> <table> <thead> <tr> <th><span class=doc-section-title>METHOD</span></th> <th><span>DESCRIPTION</span></th> </tr> </thead> <tbody> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="attributes(include_condition=True, include_trace=False) (custom_components.supernotify.scenario.Scenario.attributes)" href=#custom_components.supernotify.scenario.Scenario.attributes>attributes</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Return scenario attributes</p> </div> </td> </tr> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="contents(minimal=False, **_kwargs) (custom_components.supernotify.scenario.Scenario.contents)" href=#custom_components.supernotify.scenario.Scenario.contents>contents</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Archive friendly view of scenario</p> </div> </td> </tr> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="evaluate(condition_variables) (custom_components.supernotify.scenario.Scenario.evaluate)" href=#custom_components.supernotify.scenario.Scenario.evaluate>evaluate</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Evaluate scenario conditions</p> </div> </td> </tr> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="trace(condition_variables) async (custom_components.supernotify.scenario.Scenario.trace)" href=#custom_components.supernotify.scenario.Scenario.trace>trace</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Trace scenario condition execution</p> </div> </td> </tr> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="validate(valid_action_group_names=None) async (custom_components.supernotify.scenario.Scenario.validate)" href=#custom_components.supernotify.scenario.Scenario.validate>validate</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Validate Home Assistant conditiion definition at initiation</p> </div> </td> </tr> </tbody> </table> <div class="doc doc-children"> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.scenario.Scenario.attributes class="doc doc-heading"> <code class="highlight language-python"><span class=n>attributes</span><span class=p>(</span><span class=n>include_condition</span><span class=o>=</span><span class=kc>True</span><span class=p>,</span> <span class=n>include_trace</span><span class=o>=</span><span class=kc>False</span><span class=p>)</span></code> <a href=#custom_components.supernotify.scenario.Scenario.attributes class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Return scenario attributes</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.scenario.Scenario.contents class="doc doc-heading"> <code class="highlight language-python"><span class=n>contents</span><span class=p>(</span><span class=n>minimal</span><span class=o>=</span><span class=kc>False</span><span class=p>,</span> <span class=o>**</span><span class=n>_kwargs</span><span class=p>)</span></code> <a href=#custom_components.supernotify.scenario.Scenario.contents class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Archive friendly view of scenario</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.scenario.Scenario.evaluate class="doc doc-heading"> <code class="highlight language-python"><span class=n>evaluate</span><span class=p>(</span><span class=n>condition_variables</span><span class=p>)</span></code> <a href=#custom_components.supernotify.scenario.Scenario.evaluate class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Evaluate scenario conditions</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.scenario.Scenario.trace class="doc doc-heading"> <code class="highlight language-python"><span class=n>trace</span><span class=p>(</span><span class=n>condition_variables</span><span class=p>)</span></code> <span class="doc doc-labels"> <small class="doc doc-label doc-label-async"><code>async</code></small> </span> <a href=#custom_components.supernotify.scenario.Scenario.trace class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Trace scenario condition execution</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.scenario.Scenario.validate class="doc doc-heading"> <code class="highlight language-python"><span class=n>validate</span><span class=p>(</span><span class=n>valid_action_group_names</span><span class=o>=</span><span class=kc>None</span><span class=p>)</span></code> <span class="doc doc-labels"> <small class="doc doc-label doc-label-async"><code>async</code></small> </span> <a href=#custom_components.supernotify.scenario.Scenario.validate class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Validate Home Assistant conditiion definition at initiation</p> </div> </div> </div> </div> </div> <div class="doc doc-object doc-class"> <h2 id=custom_components.supernotify.model.Target class="doc doc-heading"> <code>custom_components.supernotify.model.Target</code> <a href=#custom_components.supernotify.model.Target class=headerlink title="Permanent link">¶</a></h2> <div class="doc doc-contents first"> <table> <thead> <tr> <th><span class=doc-section-title>METHOD</span></th> <th><span>DESCRIPTION</span></th> </tr> </thead> <tbody> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="__add__(other) (custom_components.supernotify.model.Target.__add__)" href=#custom_components.supernotify.model.Target.__add__>__add__</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Create a new target by adding another to this one</p> </div> </td> </tr> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="__eq__(other) (custom_components.supernotify.model.Target.__eq__)" href=#custom_components.supernotify.model.Target.__eq__>__eq__</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Compare two targets</p> </div> </td> </tr> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="__len__() (custom_components.supernotify.model.Target.__len__)" href=#custom_components.supernotify.model.Target.__len__>__len__</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>How many targets, whether direct or indirect</p> </div> </td> </tr> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="__sub__(other) (custom_components.supernotify.model.Target.__sub__)" href=#custom_components.supernotify.model.Target.__sub__>__sub__</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Create a new target by removing another from this one, ignoring target_data</p> </div> </td> </tr> </tbody> </table> <div class="doc doc-children"> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.model.Target.__add__ class="doc doc-heading"> <code class="highlight language-python"><span class=fm>__add__</span><span class=p>(</span><span class=n>other</span><span class=p>)</span></code> <a href=#custom_components.supernotify.model.Target.__add__ class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Create a new target by adding another to this one</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.model.Target.__eq__ class="doc doc-heading"> <code class="highlight language-python"><span class=fm>__eq__</span><span class=p>(</span><span class=n>other</span><span class=p>)</span></code> <a href=#custom_components.supernotify.model.Target.__eq__ class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Compare two targets</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.model.Target.__len__ class="doc doc-heading"> <code class="highlight language-python"><span class=fm>__len__</span><span class=p>()</span></code> <a href=#custom_components.supernotify.model.Target.__len__ class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>How many targets, whether direct or indirect</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.model.Target.__sub__ class="doc doc-heading"> <code class="highlight language-python"><span class=fm>__sub__</span><span class=p>(</span><span class=n>other</span><span class=p>)</span></code> <a href=#custom_components.supernotify.model.Target.__sub__ class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Create a new target by removing another from this one, ignoring target_data</p> </div> </div> </div> </div> </div> <div class="doc doc-object doc-class"> <h2 id=custom_components.supernotify.model.DeliveryConfig class="doc doc-heading"> <code>custom_components.supernotify.model.DeliveryConfig</code> <a href=#custom_components.supernotify.model.DeliveryConfig class=headerlink title="Permanent link">¶</a></h2> <div class="doc doc-contents first"> <p>Shared config for transport defaults and Delivery definitions</p> <table> <thead> <tr> <th><span class=doc-section-title>METHOD</span></th> <th><span>DESCRIPTION</span></th> </tr> </thead> <tbody> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="__repr__() (custom_components.supernotify.model.DeliveryConfig.__repr__)" href=#custom_components.supernotify.model.DeliveryConfig.__repr__>__repr__</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Log friendly representation</p> </div> </td> </tr> </tbody> </table> <div class="doc doc-children"> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.model.DeliveryConfig.__repr__ class="doc doc-heading"> <code class="highlight language-python"><span class=fm>__repr__</span><span class=p>()</span></code> <a href=#custom_components.supernotify.model.DeliveryConfig.__repr__ class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Log friendly representation</p> </div> </div> </div> </div> </div> <div class="doc doc-object doc-class"> <h2 id=custom_components.supernotify.model.TransportConfig class="doc doc-heading"> <code>custom_components.supernotify.model.TransportConfig</code> <a href=#custom_components.supernotify.model.TransportConfig class=headerlink title="Permanent link">¶</a></h2> <div class="doc doc-contents first"> <div class="doc doc-children"> </div> </div> </div> <div class="doc doc-object doc-class"> <h2 id=custom_components.supernotify.snoozer.Snooze class="doc doc-heading"> <code>custom_components.supernotify.snoozer.Snooze</code> <a href=#custom_components.supernotify.snoozer.Snooze class=headerlink title="Permanent link">¶</a></h2> <div class="doc doc-contents first"> <table> <thead> <tr> <th><span class=doc-section-title>METHOD</span></th> <th><span>DESCRIPTION</span></th> </tr> </thead> <tbody> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="__eq__(other) (custom_components.supernotify.snoozer.Snooze.__eq__)" href=#custom_components.supernotify.snoozer.Snooze.__eq__>__eq__</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Check if two snoozes for the same thing</p> </div> </td> </tr> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="__repr__() (custom_components.supernotify.snoozer.Snooze.__repr__)" href=#custom_components.supernotify.snoozer.Snooze.__repr__>__repr__</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Return a string representation of the object.</p> </div> </td> </tr> </tbody> </table> <div class="doc doc-children"> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.snoozer.Snooze.__eq__ class="doc doc-heading"> <code class="highlight language-python"><span class=fm>__eq__</span><span class=p>(</span><span class=n>other</span><span class=p>)</span></code> <a href=#custom_components.supernotify.snoozer.Snooze.__eq__ class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Check if two snoozes for the same thing</p> </div> </div> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.snoozer.Snooze.__repr__ class="doc doc-heading"> <code class="highlight language-python"><span class=fm>__repr__</span><span class=p>()</span></code> <a href=#custom_components.supernotify.snoozer.Snooze.__repr__ class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Return a string representation of the object.</p> </div> </div> </div> </div> </div> <div class="doc doc-object doc-class"> <h2 id=custom_components.supernotify.model.ConditionVariables class="doc doc-heading"> <code>custom_components.supernotify.model.ConditionVariables</code> <span class="doc doc-labels"> <small class="doc doc-label doc-label-dataclass"><code>dataclass</code></small> </span> <a href=#custom_components.supernotify.model.ConditionVariables class=headerlink title="Permanent link">¶</a></h2> <div class="doc doc-contents first"> <p>Variables presented to all condition evaluations</p> <h4 id=custom_components.supernotify.model.ConditionVariables--attributes>Attributes<a class=headerlink href=#custom_components.supernotify.model.ConditionVariables--attributes title="Permanent link">¶</a></h4> <div class="language-text highlight"><pre><span></span><code>applied_scenarios (list[str]): Scenarios that have been applied required_scenarios (list[str]): Scenarios that must be applied constrain_scenarios (list[str]): Only scenarios in this list, or in explicit apply_scenarios, can be applied notification_priority (str): Priority of the notification notification_message (str): Message of the notification notification_title (str): Title of the notification occupancy (list[str]): List of occupancy scenarios notification_data (dict[str,Any]): Additional data passed on notify action call </code></pre></div> <div class="doc doc-children"> </div> </div> </div> <div class="doc doc-object doc-class"> <h2 id=custom_components.supernotify.people.PeopleRegistry class="doc doc-heading"> <code>custom_components.supernotify.people.PeopleRegistry</code> <a href=#custom_components.supernotify.people.PeopleRegistry class=headerlink title="Permanent link">¶</a></h2> <div class="doc doc-contents first"> <table> <thead> <tr> <th><span class=doc-section-title>METHOD</span></th> <th><span>DESCRIPTION</span></th> </tr> </thead> <tbody> <tr class=doc-section-item> <td><code><a class="autorefs autorefs-internal" title="mobile_devices_for_person(person_entity_id) (custom_components.supernotify.people.PeopleRegistry.mobile_devices_for_person)" href=#custom_components.supernotify.people.PeopleRegistry.mobile_devices_for_person>mobile_devices_for_person</a></code></td> <td class=doc-function-details> <div class=doc-md-description> <p>Auto detect mobile_app targets for a person.</p> </div> </td> </tr> </tbody> </table> <div class="doc doc-children"> <div class="doc doc-object doc-function"> <h3 id=custom_components.supernotify.people.PeopleRegistry.mobile_devices_for_person class="doc doc-heading"> <code class="highlight language-python"><span class=n>mobile_devices_for_person</span><span class=p>(</span><span class=n>person_entity_id</span><span class=p>)</span></code> <a href=#custom_components.supernotify.people.PeopleRegistry.mobile_devices_for_person class=headerlink title="Permanent link">¶</a></h3> <div class="doc doc-contents "> <p>Auto detect mobile_app targets for a person.</p> <p>Targets not currently validated as async registration may not be complete at this stage</p> <hr> <div class="language-text highlight"><pre><span></span><code>person_entity_id (str): _description_ </code></pre></div> <hr> <div class="language-text highlight"><pre><span></span><code>list: mobile target actions for this person </code></pre></div> </div> </div> </div> </div> </div> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-timeago" title="December 13, 2025 22:11:05 UTC"><span class=timeago datetime=2025-12-13T22:11:05+00:00 locale=en></span></span><span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-iso_date" title="December 13, 2025 22:11:05 UTC">2025-12-13</span> </span> <span class=md-source-file__fact> <span class=md-icon title=Created> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M14.47 15.08 11 13V7h1.5v5.25l3.08 1.83c-.41.28-.79.62-1.11 1m-1.39 4.84c-.36.05-.71.08-1.08.08-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8c0 .37-.03.72-.08 1.08.69.1 1.33.32 1.92.64.1-.56.16-1.13.16-1.72 0-5.5-4.5-10-10-10S2 6.5 2 12s4.47 10 10 10c.59 0 1.16-.06 1.72-.16-.32-.59-.54-1.23-.64-1.92M18 15v3h-3v2h3v3h2v-3h3v-2h-3v-3z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-timeago" title="October 25, 2025 13:35:43 UTC"><span class=timeago datetime=2025-10-25T13:35:43+00:00 locale=en></span></span><span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-iso_date" title="October 25, 2025 13:35:43 UTC">2025-10-25</span> </span> </aside> </article> </div> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> <button type=button class="md-top md-icon" data-md-component=top hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg> Back to top </button> </main> <footer class=md-footer> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-copyright> Made with <a href=https://squidfunk.github.io/mkdocs-material/ target=_blank rel=noopener> Material for MkDocs </a> </div> <div class=md-social> <a href=https://github.com/rhizomatics target=_blank rel=noopener title=github.com class=md-social__link> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </a> </div> </div> </div> </footer> </div> <div class=md-dialog data-md-component=dialog> <div class="md-dialog__inner md-typeset"></div> </div> <script id=__config type=application/json>{"annotate": null, "base": "../..", "features": ["content.action.edit", "content.action.view", "content.code.copy", "content.code.select", "content.code.annotate", "navigation.instant", "navigation.tracking", "navigation.tabs", "navigation.tabs.sticky", "navigation.sections", "navigation.expand", "navigation.path", "navigation.indexes", "navigation.top", "search.suggest", "search", "search.share", "toc.follow", "toc.integrate"], "search": "../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": {"provider": "mike"}}</script> <script src=../../assets/javascripts/bundle.d7400e89.min.js></script> <script src=../../js/timeago.min.js></script> <script src=../../js/timeago_mkdocs_material.js></script> <script src=../../assets/mkdocs_pagetree_plugin.js></script> </body> </html>